Initialize a subobject of an object in Python - python

Let we have an object x of class A (which may have "private" fields, which I do not know) and I am creating a class B:
class B(A):
# ...
Now I want to create an object y of class B, whose A part is equal to x.
How to do this in Python (both 2.x and 3.x)?

I don't know if I understood well, but I think you need this in the class B:
class A():
def __init__(self, variable):
self.variable = variable
class B(A):
def __init__(self, *args, **kwargs):
super(self.__class__, self).__init__(*args, **kwargs)
Everytime you instantiate a new object from B, it will initialize all attributes in A.__init__ method. If you need the list of attributes:
y = B(variable="123...")
attrs = y.__dict__.keys()

Related

The init values did not inherited to another class with super()

I built 2 classes. first class with its own init value and another class will inherit the init values from the first class. I am wondering whether I understand it correctly of the usage of super().
class testing(testing_2):
def __init__(self, name, c):
super().__init__(name, c)
def check(self):
print(super().name)
class testing_2:
def __init__(self, name, c):
self.name = name
self.c = c
tt = testing("tester", "check")
tt.check()
I thought my code was supposedly printed the "tester" because I initialize the testing class with name and c. since testing class inherit from testing_2 so we can just print the name. Am I confusing something?
My expectation is:
testing_2 will take the value from testing and we can print the values of testing_2 in testing.
Simplify it:
class A:
def __init__(self, name, c):
self.name = name
self.c = c
class B(A):
def check(self):
print(self.name)
tt = B("tester", "check")
tt.check()
The B object will have all the same things as an A object, since it inherits them. No need to implement __init__ on B if it doesn't do anything useful. You can access self.name directly, just as you would within A. The object that has that property is self. It's set on self and you can access it with self.
Remember, self is the object instance, not the class. When doing B(...), the self in A.__init__(self, ...) is actually an instance of B.
You only need to explicitly use super if you are overriding parent methods, like in:
def __init__(self, name, c):
super().__init__(name, c)
Here __init__ is overridden, and in order to execute the parent's __init__ you need to access it through super. Just self.__init__(name, c) would access the child's __init__ method and you'd call it in an endless recursive loop.

How to create a subclass instance from a superclass instance

I would like to create a subclass instance from a superclass instance in Python. Suppose I have something like this:
class A():
def __init__(self, type):
...
self.type = type # this will be something that corresponds to either B or C
class B(A):
def do_something():
# this method is subclass specific
class C(A):
def do_something():
# this method is again subclass specific
I have a function that receives an instance of A, and I need to create an instance of either B or C (or D ...) based on what A's attribute type is.
I'm not sure how to go about this. Is there a way out of this or does the solution need to be redesigned?
Thank you
Start by redefining the classes A, B and C as follows. Note that you also need to pass the type value from subclass to superclass constructor via super().__init__()
class A():
def __init__(self, type):
...
self.type = type # this will be something that corresponds to either B or C
class B:
def __init__(self, type):
super().__init__(type)
def do_something(self):
print('do_something called for B')
class C:
def __init__(self, type):
super().__init__(type)
def do_something(self):
print('do_something called for C')
Then make another class which can make the decision whether to call B and C for you, and save that object locally
class User:
def __init__(self, type):
self.obj = None
if type == 'B':
self.obj = B(type)
elif type == 'C':
self.obj = C(type)
Then you can instantiate user class with different types and see that the correct do_something is called.
user_B = User('B')
user_B.obj.do_something()
#do_something called for B
user_C = User('C')
user_C.obj.do_something()
#do_something called for C
Use a dictionary that maps from types to classes.
class A():
typemap = {}
def __init__(self, typearg): # renamed this argument so it doesn't shadow standard type() function
self.type = typearg
self.typemap[typearg] = type(self)
def create_child(self, *args):
return typemap[self.type](*args)
When the constructor runs, type(self) gets the subclass of the object being created. This is then stored in the dictionary, so we can look it up using self.type.
The create_child() looks up the class in the dictionary, and calls it to create a new instance of that child class.

How can I set override default kwargs in a parent class?

Let's say I have the following parent and child classes:
class A(object):
def __init__(self, *args, **kwargs):
self.a = kwargs.get('a', 'default_A')
self.b = kwargs.get('b', 'default_B')
class B(A):
a = "override_A"
def __init__(self, *args, **kwargs):
super(B, self).__init__(**kwargs)
b = B()
print b.b # this is "default_B", as expected
print b.a # I expected this to be "override_A"
What am I doing wrong here? I've tried to understand how inheritance works via answers like this one but haven't found something that describes this specific requirement.
You're mixing class and instance variables. B.a is a class variable, which is shadowed by the instance variable set in A.__init__().
You could for example use dict.setdefault():
class B(A):
def __init__(self, *args, **kwargs):
# If the key 'a' exists, this'll be effectively no-operation.
# If not, then 'a' is set to 'override_A'.
kwargs.setdefault('a', 'override_A')
super(B, self).__init__(**kwargs)

Overwrite base class attribute with #property of the same name

I am trying to subclass a python class and overwrite a regular attribute with a #property function. The catch is that I can't modify the parent class, and the api for the child class needs to look the same as the parent class (but behave differently). (So my question is different from this one in which the parent class also used a #property method to access the underlying attribute.)
The simplest possible example is
# assume this class can't be overwritten
class Parent(object):
def __init__(self, a):
self.attr = a
# how do I make this work?
class Child(Parent):
def __init__(self, a):
super(Child, self).__init__(a)
# overwrite access to attr with a function
#property
def attr(self):
return super(Child, self).attr**2
c = Child(4)
print c.attr # should be 16
This produces an error when the parent init method is called.
<ipython-input-15-356fb0400868> in __init__(self, a)
2 class Parent(object):
3 def __init__(self, a):
----> 4 self.attr = a
5
6 # how do I make this work?
AttributeError: can't set attribute
Hopefully it is clear what I want to do and why. But I can't figure out how.
This is easily fixed by adding a setter method
class Child(Parent):
def __init__(self, a):
self._attr = None
super(Child, self).__init__(a)
# overwrite access to a with a function
#property
def attr(self):
return self._attr**2
#attr.setter
def attr(self, value):
self._attr = value

How do I get a reference to all classes implementing descriptor object in python

I am creating a descriptor, and I want to create a list inside it that holds references to all objects implementing it, it is supposed to be some kind of a shortcut where I can call the method on the next instance in line from the instances.
The only daft solution I could find is just on __init__ of each objects trigger the setter on descriptor that adds the item to the list, even though that solution does work indeed, I can sense that something is wrong with it.
Does anyone have a better way of adding the class instance to a descriptor list other than setting arbitrary value on __init__, just to trigger the setter?
class GetResult(object):
def __init__(self, value):
self.instances = []
def __get__(self, instance, owner):
return self
def __set__(self, instance, value):
self.instances.append(instance)
def getInstances(self):
return self.instances
class A(object):
result = GetResult(0)
def __init__(self):
self.result = 0
def getAll(self):
print self.result.getInstances()
a1 = A()
a2 = A()
a3 = A()
print a2.result.getInstances()
>> [<__main__.A object at 0x02302DF0>, <__main__.A object at 0x02302E10>, <__main__.Aobject at 0x02302E30>]
If that's all your descriptor do, it's a bit of an abuse of the descriptor protocol. Just overriding your class __new__ or __init__ would be simpler:
class Foo(object):
_instances = []
def __new__(cls, *args, **kw):
instance = object.__new__(cls)
cls._instances.append(instance)
return instance
#classmethod
def get_instances(cls):
return self._instances

Categories