Python: print base class variables - python

I'm using a library to share data between C++, VHDL, and SystemVerilog. It uses codegenerators to build datastructures that contain the appropriate field. Think of a c type data structure. I want to generate python code that contains the datastructure and read/write functions to set and write the contents of the datastructure from a / to a file.
To do this i am trying to write a program that prints all the variables in the baseclass with updates from the subclass, but without the subclass variables.
The idea being that class A is the actual VHDL/SystemVerilog/C++ record/structure and class B contains logic to do processing and generate the values in class A.
For example:
class A(object):
def __init__(self):
self.asd = "Test string"
self.foo = 123
def write(self):
print self.__dict__
class B(A):
def __init__(self):
A.__init__(self)
self.bar = 456
self.foo += 1
def write(self):
super(B, self).write()
Calling B.write() should yield the following: (Note the incremented value of foo)
"asd: Test String, foo: 124"
but instead it yields
"asd: Test String, bar: 456, foo: 124".
Is there a way to only get the base class variables? I could compare the base dictionary with the subclass dictionary and only print the values that appear in both but this does not feel like a clean way.

There is no distinction between base class and subclass variables. By definition, inheritance is an is-a relationship; everything defined in the base class is as if it was defined in the subclass.
Similarly, anything you define on the instance at any other point in your code will also appear in the dict; Python does not restrict you from adding new instance variables elsewhere in the class or even from outside.
The only way to do what you want is to record the keys when you enter A.__init__.

You said: "I could compare the base dictionary with the subclass dictionary and only print the values that appear in both but this does not feel like a clean way". What you're trying to do isn't a natural thing to do in Python, so no matter what you do, it's not going to be clean. But in fact, what you suggest is impossible, since you can't get the base dictionary when you make the .write call in a B instance. The closest you can do is to take a copy of it (or, as Daniel Roseman suggests, its keys) immediately after the __init__ call in B so you can refer to that copy later when you need it.
Here's some code that does that:
class A(object):
def __init__(self):
self.asd = "Test string"
self.foo = 123
def write(self, d=None):
print self.__dict__
class B(A):
def __init__(self):
A.__init__(self)
self.parentkeys = self.__dict__.keys()
self.bar = 456
self.foo += 1
def write(self):
bdict = self.__dict__
print dict((k, bdict[k]) for k in self.parentkeys)
a = A()
b = B()
a.write()
b.write()
output
{'foo': 123, 'asd': 'Test string'}
{'foo': 124, 'asd': 'Test string'}
Here's a minor variation:
class A(object):
def __init__(self):
self.asd = "Test string"
self.foo = 123
def write(self, d=None):
if d is None:
d = self.__dict__
print d
class B(A):
def __init__(self):
super(B, self).__init__()
self.parentkeys = self.__dict__.keys()
self.bar = 456
self.foo += 1
def write(self):
bdict = self.__dict__
d = dict((k, bdict[k]) for k in self.parentkeys)
super(B, self).write(d)
However, I get the feeling that there may be a more Pythonic way to do what you really want to do...

Related

Dynamically adopt the methods of an instance of another class

I have a case, where I have an instance of a class in python which holds instances of other classes. For my use case, I would like a way to use the methods of the "inner" classes from the outer class without referencing the attribute holding the inner class.
I have made a simplistic example here:
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_instance):
self.other_instance= other_instance
def say_good_night(self):
print("Good night")
my_a = A()
my_c = C(other_instance=my_a)
# How to make this possible:
my_c.say_hi()
# Instead of
my_c.other_instance.say_hi()
Class inheritance is not possible, as the object passed to C may be an instance of a range of classes. Is this possible in Python?
I think this is the simplest solution although it is possible with metaprogramming.
class A:
def __init__(self):
pass
def say_hi(self):
print("Hi")
def say_goodbye(self):
print("Goodbye")
class C:
def __init__(self, other_class):
self.other_class = other_class
C._add_methods(other_class)
def say_good_night(self):
print("Good night")
#classmethod
def _add_methods(cls, obj):
type_ = type(obj)
for k, v in type_.__dict__.items():
if not k.startswith('__'):
setattr(cls, k, v)
my_a = A()
my_c = C(other_class=my_a)
my_c.say_hi()
output :
Hi
First we get the type of passed instance, then we iterate through it's attribute (because methods are attributes of the class not the instance).
If self.other_class is only needed for this purpose, you can omit it as well.
So, because you have done:
my_a = A() and my_c = C(other_class=my_a).
my_c.other_class is the same as my_a asthey point to the same location in memory.
Therefore, as you can do my_a.say_hi() you could also do my_c.other_class.say_hi().
Also, just a note, as you are calling A() before you store it into other_classes, I would probably rename the variable other_classes to class_instances.
Personally, I think that would make more sense, as each of those classes would have already been instantiated.

Conditional Inheritance based on arguments in Python

Being new to OOP, I wanted to know if there is any way of inheriting one of multiple classes based on how the child class is called in Python. The reason I am trying to do this is because I have multiple methods with the same name but in three parent classes which have different functionality. The corresponding class will have to be inherited based on certain conditions at the time of object creation.
For example, I tried to make Class C inherit A or B based on whether any arguments were passed at the time of instantiating, but in vain. Can anyone suggest a better way to do this?
class A:
def __init__(self,a):
self.num = a
def print_output(self):
print('Class A is the parent class, the number is 7',self.num)
class B:
def __init__(self):
self.digits=[]
def print_output(self):
print('Class B is the parent class, no number given')
class C(A if kwargs else B):
def __init__(self,**kwargs):
if kwargs:
super().__init__(kwargs['a'])
else:
super().__init__()
temp1 = C(a=7)
temp2 = C()
temp1.print_output()
temp2.print_output()
The required output would be 'Class A is the parent class, the number is 7' followed by 'Class B is the parent class, no number given'.
Thanks!
Whether you're just starting out with OOP or have been doing it for a while, I would suggest you get a good book on design patterns. A classic is Design Patterns by Gamma. Helm. Johnson and Vlissides.
Instead of using inheritance, you can use composition with delegation. For example:
class A:
def do_something(self):
# some implementation
class B:
def do_something(self):
# some implementation
class C:
def __init__(self, use_A):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A() if use_A else B()
def do_something(self):
# delegate to A or B instance:
self.instance.do_something()
Update
In response to a comment made by Lev Barenboim, the following demonstrates how you can make composition with delegation appear to be more like regular inheritance so that if class C has has assigned an instance of class A, for example, to self.instance, then attributes of A such as x can be accessed internally as self.x as well as self.instance.x (assuming class C does not define attribute x itself) and likewise if you create an instance of C named c, you can refer to that attribute as c.x as if class C had inherited from class A.
The basis for doing this lies with builtin methods __getattr__ and __getattribute__. __getattr__ can be defined on a class and will be called whenever an attribute is referenced but not defined. __getattribute__ can be called on an object to retrieve an attribute by name.
Note that in the following example, class C no longer even has to define method do_something if all it does is delegate to self.instance:
class A:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am A')
class B:
def __init__(self, x):
self.x = x
def do_something(self):
print('I am B')
class C:
def __init__(self, use_A, x):
# assign an instance of A or B depending on whether argument use_A is True
self.instance = A(x) if use_A else B(x)
# called when an attribute is not found:
def __getattr__(self, name):
# assume it is implemented by self.instance
return self.instance.__getattribute__(name)
# something unique to class C:
def foo(self):
print ('foo called: x =', self.x)
c = C(True, 7)
print(c.x)
c.foo()
c.do_something()
# This will throw an Exception:
print(c.y)
Prints:
7
foo called: x = 7
I am A
Traceback (most recent call last):
File "C:\Ron\test\test.py", line 34, in <module>
print(c.y)
File "C:\Ron\test\test.py", line 23, in __getattr__
return self.instance.__getattribute__(name)
AttributeError: 'A' object has no attribute 'y'
I don't think you can pass values to the condition of the class from inside itself.
Rather, you can define a factory method like this :
class A:
def sayClass(self):
print("Class A")
class B:
def sayClass(self):
print("Class B")
def make_C_from_A_or_B(make_A):
class C(A if make_A else B):
def sayClass(self):
super().sayClass()
print("Class C")
return C()
make_C_from_A_or_B(True).sayClass()
which output :
Class A
Class C
Note: You can find information about the factory pattern with an example I found good enough on this article (about a parser factory)

How to modify a object getting from a property decorator?

Let's say, here is a class A. It has a private value _foo which is a json string, and access it with property getter and setter.
The code is as the following:
import json
class A(object):
_foo = '{"name":"name"}'
#property
def foo(self):
return json.loads(self._foo)
#foo.setter
def foo(self, value):
self._foo = json.dumps(value)
Usually, I use foo to do something like following:
a = A()
print(a.foo['name'])
But I'm in trouble when I want to modify it.
a = A()
print(a.foo)
# Out: {'name': 'name'}
a.foo['weight'] = 1
print(a.foo)
# Out: {'name': 'name'} # have no change
What I need to do is:
foo = a.foo
foo['weight'] = 1
a.foo = foo
print(a.foo)
Now, my question is how to implement this more intuitive and pythonic?
I think the correct way for you to do this is like this, dont save the dict as a string, but as an actual dict.
import json
class A(object):
_foo = {"name":"name"}
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, value):
self._foo = value
def dump_foo(self):
jsons.dump(self.foo)
def __del__(self):
self.dump_foo()
I cant see a real reason for you to dump the json file every time, edit it, use it, and when you are done dump it.
If you still wish to print the dict (in a human readable manner) after this all you need to do is print(a.foo), due to the str conversion of a dict.

Find nested sub-classes in a class in the order they're defined

Imagine a case like so:
class A:
pass
class B:
x = 5
class D(A):
pass
class C(A):
pass
What I want is to find all the classes in class B that are subclasses of A:
>>> for cls in dir(B):
if issubclass(cls, A):
print(cls)
<class '__main__.C'>
<class '__main__.D'>
And it works as intended, but the problem is: I need to get them in the order they are defiend in class B definition, so instead of printing C before D, I need to get D before C. Using dir() obviously doesn't work, since it returns alphabetically sorted list.
What are my other options, if any?
EDIT:
The reason I want this is to help "players" make their own heroes/champions (for a video game) as easily as possible. So instead of having to write:
class MyHero(Hero):
def __init__(self, name='My Hero', description='My description', ...):
super().__init__(name, description, ...)
self.spells = [MySpell1(), MySpell2(), MySpell3()]
class MySpell1(Spell):
def __init__(...):
...
They could just write:
class MyHero(Hero):
name = 'My Hero'
description = 'My description'
...
class MySpell1(Spell):
name = ...
class MySpell2(Spell):
...
Obviously the second one looks much better than the first, and even more to a person who doesn't know much of Python.
The metaclass documentation includes a nice example of how to get a class to remember what order its members were defined in:
class OrderedClass(type):
#classmethod
def __prepare__(metacls, name, bases, **kwds):
return collections.OrderedDict()
def __new__(cls, name, bases, namespace, **kwds):
result = type.__new__(cls, name, bases, dict(namespace))
result.members = tuple(namespace)
return result
class A(metaclass=OrderedClass):
def one(self): pass
def two(self): pass
def three(self): pass
def four(self): pass
>>> A.members
('__module__', 'one', 'two', 'three', 'four')
You can adapt this to your case like this:
class A:
pass
class B(metaclass=OrderedClass):
x = 5
class D(A):
pass
class C(A):
pass
print(filter(lambda x: isinstance(getattr(B, x), type), b.members)))
gives:
['D', 'C']
Note that this gives you the names of the classes; if you want the classes themselves, you can do this instead:
print(list(filter(lambda x: isinstance(x, type), (getattr(B, x) for x in B.members))))
May be something like that can be helpful:
import inspect
class Spell(object):
name = "Abstract spell"
class MyHero(object):
name = "BATMAN"
description = "the bat man"
class MySpell1(Spell):
name = "Fly"
class MySpell2(Spell):
name = "Sleep"
for k, v in MyHero.__dict__.iteritems():
if inspect.isclass(v) and issubclass(v, Spell):
print "%s cast the spell %s" % (MyHero.name, v.name)
UPDATE:
Another way to iterate by class attributes is:
for attr_name in dir(MyHero):
attr = getattr(MyHero, attr_name)
if inspect.isclass(attr) and issubclass(attr, Spell):
print "%s cast the spell %s" % (MyHero.name, attr.name)
P.S. Python class is also object

How to keep track of class instances?

Toward the end of a program I'm looking to load a specific variable from all the instances of a class into a dictionary.
For example:
class Foo():
def __init__(self):
self.x = {}
foo1 = Foo()
foo2 = Foo()
...
Let's say the number of instances will vary and I want the x dict from each instance of Foo() loaded into a new dict. How would I do that?
The examples I've seen in SO assume one already has the list of instances.
One way to keep track of instances is with a class variable:
class A(object):
instances = []
def __init__(self, foo):
self.foo = foo
A.instances.append(self)
At the end of the program, you can create your dict like this:
foo_vars = {id(instance): instance.foo for instance in A.instances}
There is only one list:
>>> a = A(1)
>>> b = A(2)
>>> A.instances
[<__main__.A object at 0x1004d44d0>, <__main__.A object at 0x1004d4510>]
>>> id(A.instances)
4299683456
>>> id(a.instances)
4299683456
>>> id(b.instances)
4299683456
#JoelCornett's answer covers the basics perfectly. This is a slightly more complicated version, which might help with a few subtle issues.
If you want to be able to access all the "live" instances of a given class, subclass the following (or include equivalent code in your own base class):
from weakref import WeakSet
class base(object):
def __new__(cls, *args, **kwargs):
instance = object.__new__(cls, *args, **kwargs)
if "instances" not in cls.__dict__:
cls.instances = WeakSet()
cls.instances.add(instance)
return instance
This addresses two possible issues with the simpler implementation that #JoelCornett presented:
Each subclass of base will keep track of its own instances separately. You won't get subclass instances in a parent class's instance list, and one subclass will never stumble over instances of a sibling subclass. This might be undesirable, depending on your use case, but it's probably easier to merge the sets back together than it is to split them apart.
The instances set uses weak references to the class's instances, so if you del or reassign all the other references to an instance elsewhere in your code, the bookkeeping code will not prevent it from being garbage collected. Again, this might not be desirable for some use cases, but it is easy enough to use regular sets (or lists) instead of a weakset if you really want every instance to last forever.
Some handy-dandy test output (with the instances sets always being passed to list only because they don't print out nicely):
>>> b = base()
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> class foo(base):
... pass
...
>>> f = foo()
>>> list(foo.instances)
[<__main__.foo object at 0x0000000002606898>]
>>> list(base.instances)
[<__main__.base object at 0x00000000026067F0>]
>>> del f
>>> list(foo.instances)
[]
You would probably want to use weak references to your instances. Otherwise the class could likely end up keeping track of instances that were meant to have been deleted. A weakref.WeakSet will automatically remove any dead instances from its set.
One way to keep track of instances is with a class variable:
import weakref
class A(object):
instances = weakref.WeakSet()
def __init__(self, foo):
self.foo = foo
A.instances.add(self)
#classmethod
def get_instances(cls):
return list(A.instances) #Returns list of all current instances
At the end of the program, you can create your dict like this:
foo_vars = {id(instance): instance.foo for instance in A.instances}
There is only one list:
>>> a = A(1)
>>> b = A(2)
>>> A.get_instances()
[<inst.A object at 0x100587290>, <inst.A object at 0x100587250>]
>>> id(A.instances)
4299861712
>>> id(a.instances)
4299861712
>>> id(b.instances)
4299861712
>>> a = A(3) #original a will be dereferenced and replaced with new instance
>>> A.get_instances()
[<inst.A object at 0x100587290>, <inst.A object at 0x1005872d0>]
You can also solve this problem using a metaclass:
When a class is created (__init__ method of metaclass), add a new instance registry
When a new instance of this class is created (__call__ method of metaclass), add it to the instance registry.
The advantage of this approach is that each class has a registry - even if no instance exists. In contrast, when overriding __new__ (as in Blckknght's answer), the registry is added when the first instance is created.
class MetaInstanceRegistry(type):
"""Metaclass providing an instance registry"""
def __init__(cls, name, bases, attrs):
# Create class
super(MetaInstanceRegistry, cls).__init__(name, bases, attrs)
# Initialize fresh instance storage
cls._instances = weakref.WeakSet()
def __call__(cls, *args, **kwargs):
# Create instance (calls __init__ and __new__ methods)
inst = super(MetaInstanceRegistry, cls).__call__(*args, **kwargs)
# Store weak reference to instance. WeakSet will automatically remove
# references to objects that have been garbage collected
cls._instances.add(inst)
return inst
def _get_instances(cls, recursive=False):
"""Get all instances of this class in the registry. If recursive=True
search subclasses recursively"""
instances = list(cls._instances)
if recursive:
for Child in cls.__subclasses__():
instances += Child._get_instances(recursive=recursive)
# Remove duplicates from multiple inheritance.
return list(set(instances))
Usage: Create a registry and subclass it.
class Registry(object):
__metaclass__ = MetaInstanceRegistry
class Base(Registry):
def __init__(self, x):
self.x = x
class A(Base):
pass
class B(Base):
pass
class C(B):
pass
a = A(x=1)
a2 = A(2)
b = B(x=3)
c = C(4)
for cls in [Base, A, B, C]:
print cls.__name__
print cls._get_instances()
print cls._get_instances(recursive=True)
print
del c
print C._get_instances()
If using abstract base classes from the abc module, just subclass abc.ABCMeta to avoid metaclass conflicts:
from abc import ABCMeta, abstractmethod
class ABCMetaInstanceRegistry(MetaInstanceRegistry, ABCMeta):
pass
class ABCRegistry(object):
__metaclass__ = ABCMetaInstanceRegistry
class ABCBase(ABCRegistry):
__metaclass__ = ABCMeta
#abstractmethod
def f(self):
pass
class E(ABCBase):
def __init__(self, x):
self.x = x
def f(self):
return self.x
e = E(x=5)
print E._get_instances()
Another option for quick low-level hacks and debugging is to filter the list of objects returned by gc.get_objects() and generate the dictionary on the fly that way. In CPython that function will return you a (generally huge) list of everything the garbage collector knows about, so it will definitely contain all of the instances of any particular user-defined class.
Note that this is digging a bit into the internals of the interpreter, so it may or may not work (or work well) with the likes of Jython, PyPy, IronPython, etc. I haven't checked. It's also likely to be really slow regardless. Use with caution/YMMV/etc.
However, I imagine that some people running into this question might eventually want to do this sort of thing as a one-off to figure out what's going on with the runtime state of some slice of code that's behaving strangely. This method has the benefit of not affecting the instances or their construction at all, which might be useful if the code in question is coming out of a third-party library or something.
Here's a similar approach to Blckknght's, which works with subclasses as well. Thought this might be of interest, if someone ends up here. One difference, if B is a subclass of A, and b is an instance of B, b will appear in both A.instances and B.instances. As stated by Blckknght, this depends on the use case.
from weakref import WeakSet
class RegisterInstancesMixin:
instances = WeakSet()
def __new__(cls, *args, **kargs):
o = object.__new__(cls, *args, **kargs)
cls._register_instance(o)
return o
#classmethod
def print_instances(cls):
for instance in cls.instances:
print(instance)
#classmethod
def _register_instance(cls, instance):
cls.instances.add(instance)
for b in cls.__bases__:
if issubclass(b, RegisterInstancesMixin):
b._register_instance(instance)
def __init_subclass__(cls):
cls.instances = WeakSet()
class Animal(RegisterInstancesMixin):
pass
class Mammal(Animal):
pass
class Human(Mammal):
pass
class Dog(Mammal):
pass
alice = Human()
bob = Human()
cannelle = Dog()
Animal.print_instances()
Mammal.print_instances()
Human.print_instances()
Animal.print_instances() will print three objects, whereas Human.print_instances() will print two.
Using the answer from #Joel Cornett I've come up with the following, which seems to work. i.e. i'm able to total up object variables.
import os
os.system("clear")
class Foo():
instances = []
def __init__(self):
Foo.instances.append(self)
self.x = 5
class Bar():
def __init__(self):
pass
def testy(self):
self.foo1 = Foo()
self.foo2 = Foo()
self.foo3 = Foo()
foo = Foo()
print Foo.instances
bar = Bar()
bar.testy()
print Foo.instances
x_tot = 0
for inst in Foo.instances:
x_tot += inst.x
print x_tot
output:
[<__main__.Foo instance at 0x108e334d0>]
[<__main__.Foo instance at 0x108e334d0>, <__main__.Foo instance at 0x108e33560>, <__main__.Foo instance at 0x108e335a8>, <__main__.Foo instance at 0x108e335f0>]
5
10
15
20
(For Python)
I have found a way to record the class instances via the "dataclass" decorator while defining a class. Define a class attribute 'instances' (or any other name) as a list of the instances you want to record. Append that list with the 'dict' form of created objects via the dunder method __dict__. Thus, the class attribute 'instances' will record instances in the dict form, which you want.
For example,
from dataclasses import dataclass
#dataclass
class player:
instances=[]
def __init__(self,name,rank):
self.name=name
self.rank=rank
self.instances.append(self.__dict__)

Categories

Resources