Instantiate an child object directly from a parent object - python

I have two objects one inherits from the other and the only difference between them is a few attribute fields:
class Parent:
def __init__(self,a, b):
self.a = a
self.b = b
def methodA(self):
# do something
pass
class Child(Parent):
def __init__(self,c,**kwargs):
self.c = c
super().__init__(**kwargs)
I have an instance of the parent object and I want to find a fast way in python to create an instance of the child object which only has one additional field by using the already existing parent object.
Is there a python way or module that lets you do that easily. IN my real code the parent class has hundreds of fields and it is a bit inefficient to just reassign its value.

The canonical solution is to add a class method to Child that works as a constructor. It takes a Parent instance and returns the Child instance with the proper attributes.
For example:
class Parent:
def __init__(self,a, b):
self.a = a
self.b = b
class Child(Parent):
def __init__(self,c,**kwargs):
self.c = c
super().__init__(**kwargs)
#classmethod
def from_parent(cls, parent, c):
return cls(a=parent.a, b=parent.b, c=c)
p = Parent(a=1, b=2)
c = Child.from_parent(parent=p, c=3)
print(c.a, c.b, c.c) # output: 1 2 3
I would argue that your Parent class having hundreds of attributes is irrelevant to the answer. Yes, it's tedious having to explicitly write every attribute of the Parent instance in the from_parent method, but that's simply a limitation of having a class with that many attributes anyway. Possibly, a better design choice would be to encapsulate groups of Parent attributes into proper classes, so that only those instances need to be delivered to the Child class upon initialization.

Ok the other suggestions for making a method that takes in parent attributes and creates a child object is ok but adds unnecessary code I think. I made this solution, which I ended up using. It doesnt accept the parent object directly in as an argument but it is more concise I think:
class Parent:
def __init__(self, a, b):
self.a = a
self.b = b
class Child(Parent):
def __init__(self,c, **kwargs):
self.c = c
super().__init__(**kwargs)
# So if I start with this parent object
parent_args = {"a":23,"b":"iuhsdg"}
parent =Parent(**parent_args)
# I then make child with all the parent attributes plus some more
child_args = {"c":567}
child_args.update(vars(parent))
child = Child(**child_args)

Related

Am I able to call a submethod of a class's attribute from that class using the class as an attribute?

I am very sorry for the confusing title, I did not know how else to phrase the question.
Let's say I have a class, A. It is described as shown:
class A:
def __init__(self, argument):
self.value = argument
def submethod(self, argumentThatWillBeAClass):
print(dir(argumentThatWillBeAClass))
And then I initialize it as shown below:
classAInstance = A('42.0')
Now, I have a class, B. Let's add a submethod that calls A's submethod with B as an argument.
class B:
def __init__(self, argumentThatIsAClassAInstance):
self.classAInstance = argumentThatIsAClassAInstance
def submethod(self):
self.classAInstance.submethod(self)
Let's initialize it with classInstance:
classBInstance = B(classAInstance)
My desired result is that all the attributes of B are printed when B.submethod is called. Is this possible, and if not, how would I achieve something like this?
Now, I have a class, B. Let's add a submethod that calls A's submethod
with B as an argument.
But that isn't what your code does. On the following line:
self.classAInstance.submethod(self)
You are calling the method (I don't know what you mean by "sub" method, these are all just normal methods) with *an instance of B, not B.
Two different ways you could do this:
self.classAInstance.submethod(type(self))
Or:
self.classAInstance.submethod(B)
The semantics aren't exactly the same, since the first dynamically retreives the instance, if some other class inherits from B, it will call dir on that class. The second always prints dir(B), regardless of inheritance.
So:
class A:
def method(self, klass: type) -> None:
print(dir(klass))
class B:
def __init__(self, a: A) -> None:
self.a = a
def method(self) -> None:
self.a.method(type(self))
b = B(A())
As one potential solution, you can use inheritance. This allows class B to inherit everything from class A
class A:
def __init__(self, argument):
self.value = argument
def submethod(self, argumentThatWillBeAClass):
print(dir(argumentThatWillBeAClass))
class B(A):
def __init__(self, value):
super().__init__(value)
def submethod(self, argumentThatWillBeAClass): # You can override the method and do extra code too.
super().submethod(argumentThatWillBeAClass) # Calls A's submethod function

How to override only one variable inside parent class's method?

Let's suppose that Parent class is:
class Parent:
def __init__(self, a):
self.a = a
def do_something(self):
a = self.a
b = self.a
print('The a is ', a)
print('The b is ', b)
I want to create a Child class that will redefine only b
Something like:
class Child(Parent):
def do_something(self, custom_param):
#some_exotic_decorator_or_something_else(b=custom_param)
super().do_something()
And get output like:
obj = Child('the_a')
obj.do_something('the_b')
The a is the_a
The b is the_b
Of course original method has many lines and complicated logic to override whole method. Also that is one of common python libraries so I want to minimise intrusion inside method.
Here is any common way in python to do that?
To be more clear, the method what I want to override is _write_end_record
I want to redefine only centDirOffset. All other logic is working good. I may copy and paste whole method inside my code and change only one line, but it don't looking like a smart idea
A clean and easy way would be to make your parent class more general by adding a parameter to your method and assign a default value to it.
class Parent:
def __init__(self, a):
self.a = a
def do_something(self, b=None):
if b is None:
b = self.a
a = self.a
print('The a is ', a)
print('The b is ', b)
By doing this, you do not even need a child class.

Inherit properties from an already constructed parent class in a child class

I'm stuck on this point about class inheritance, and I haven't been able to figure out a clean way forward. I have some base class:
class Foo:
""" Parent class. """
def __init__(self,a,b):
self.a = a
self.b = b
def product(self):
return self.a * self.b
This class contains information I've loaded in from some data file. I want to generate different kinds of information related to this data, using class properties to store that information. For example, if I wanted to create a report that tells me the quotient of a and b, I would want to create something like:
class Bar(Foo):
""" Child class. """
def __init__(self,foo_object):
# What I want to avoid:
self.a = foo_object.a
self.b = foo_object.b
def quotient(self):
return self.a / self.b
Obviously there are many more class properties in my real application. It becomes very tedious to assign all of the properties from the Foo object into the new Bar object.
Is there a more elegant way to "extend" a Foo object into a Bar object once the Foo object has already been created?
EDIT:
Sorry if I didn't state my objective clearly enough; I see that there's some confusion about what I'm asking for. I've already created a Foo object with a number of properties. I want to create a child class of Foo, called Bar, later, that contains those properties but also some additional properties that are specific to one "area" of my application.
So, I want to be able to pass in an already instantiated Foo object, and pass the values of its properties into identical properties in Bar, without doing this manually item-by-item.
I believe Flob's answer is what I'm looking for. Thank you!
You can inherit the Information directly by initiating the parent class inside the child class. Once you have created an instance of the parent class, you can Access all it's properties by using vars(object), which will return a dictionary of all properties assiciated with the object. For example, let's say you have a class Foo:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
and test_parent is an instance of this class.
test_parent = Foo(a='Hello', b='World')
now, when creating the Bar child class, do it like this:
class Bar(Foo):
def __init__(self, foo_object):
a, b = vars(foo_object).values() #get all properties of parent class object
Foo.__init__(self, a, b) # initiate parent class
def say_hello(self):
print('{} {}'.format(self.a, self.b))
Create an instance of the Bar class and call say_hello:
test_child = Bar(test_parent)
test_child.say_hello()
Output:
"Hello World"
I'm not sure I understand what you mean by "once the Foo object has already been created".
For initialization of the attributes defined by the parent class, use this:
class Bar(Foo):
""" Child class. """
def __init__(self,a,b):
super().__init__(a,b)
def quotient(self):
return self.a / self.b
Let the __init__() method of the super-class continue to do its job of initializing a and b.
Note that b = B() creates only one object, not two.
In the code you posted, Bar.__init__() seems to take a Foo object as one of its arguments. Technically, that is a case of wrapping a Foo object in a Bar object -- and if you're doing that, there really is no need for Bar to be a child class of Foo:
class Bar:
""" Wrapper class. """
def __init__(self, foo_object):
self.foo_object = foo_object
def quotient(self):
return self.foo_object.a / self.foo_object.b
It is possible to change the class of the object after it is created. Instead of unpacking the contents of the object into a new one, you change the class that it uses to look up methods:
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
class Bar(Foo):
def quotient(self):
return self.a/self.b
f = Foo(1, 2)
f.__class__ = Bar
f.quotient() # 0.5
This usually isn't necessary (I woudln't recommend using it here). Instead, you could create a Bar object directly:
b = Bar(1, 2)
b.quotient()
Bar inherits the __init__ method of Foo, so you don't have to redefine it.
Another option is to use a function that's not a method:
def quotient(obj):
return obj.a/obj.b
Now you can compute quotient(Foo(1,2)) even though your Foo object doesn't know about the quotient function.
A class can inherit from a base class, but an object cannot inherit from another object. It can either be a copy (with possibly additional attributes) or wraps the original object. The first case is for a true inheritance strategy (the child instance has to be an instance of the base class and must initialize itself), the second if for an aggregation or containment strategy.
But beware, there are some caveats with the second one, mainly because the child object is not an instance of the base class (isinstance(child, Foo) is false). That means that there is no one size fits all way here, and you will have to choose one pattern, inheritance vs aggregation.

Inheriting a virtual class method - how to call it from base class?

Let B inherit from A. Suppose that some of B's behavior depends on the class attribute cls_x and we want to set up this dependency during construction of B objects. Since it is not a simple operation, we want to wrap it in a class method, which the constructor will call. Example:
class B(A):
cls_x = 'B'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = B.cm()
Problem: cm as well as __init__ will always be doing the same things and their behavior must stay the same in each derived class. Thus, we would like to put them both in the base class and not define it in any of the derived classes. The only difference will be the caller of cm - either A or B (or any of B1, B2, each inheriting from A), whatever is being constructed. So what we'd like to have is something like this:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = ClassOfWhateverIsInstantiated.cm() #how to do this?
class B(A):
cls_x = 'B'
I feel like it's either something very simple I'm missing about Python's inheritance mechanics or the whole issue should be handled entirely differently.
This is different than this question as I do not want to override the class method, but move its implementation to the base class entirely.
Look at it this way: Your question is essentially "How do I get the class of an instance?". The answer to that question is to use the type function:
ClassOfWhateverIsInstantiated = type(self)
But you don't even need to do that, because classmethods can be called directly through an instance:
def __init__(self):
self.attr = self.cm() # just use `self`
This works because classmethods automatically look up the class of the instance for you. From the docs:
[A classmethod] can be called either on the class (such as C.f()) or on an instance
(such as C().f()). The instance is ignored except for its class.
For ClassOfWhateverIsInstantiated you can just use self:
class A:
cls_x = 'A'
#classmethod
def cm(cls):
return cls.cls_x
def __init__(self):
self.attr = self.cm() # 'self' refers to B, if called from B
class B(A):
cls_x = 'B'
a = A()
print(a.cls_x) # = 'A'
print(A.cls_x) # = 'A'
b = B()
print(b.cls_x) # = 'B'
print(B.cls_x) # = 'B'
To understand this, just remember that class B is inheriting the methods of class A. So when __init__() is called during B's instantiation, it's called in the context of class B, to which self refers.

Inheritance method overwrite in some conditions [duplicate]

When creating a simple object hierarchy in Python, I'd like to be able to invoke methods of the parent class from a derived class. In Perl and Java, there is a keyword for this (super). In Perl, I might do this:
package Foo;
sub frotz {
return "Bamf";
}
package Bar;
#ISA = qw(Foo);
sub frotz {
my $str = SUPER::frotz();
return uc($str);
}
In Python, it appears that I have to name the parent class explicitly from the child.
In the example above, I'd have to do something like Foo::frotz().
This doesn't seem right since this behavior makes it hard to make deep hierarchies. If children need to know what class defined an inherited method, then all sorts of information pain is created.
Is this an actual limitation in python, a gap in my understanding or both?
Use the super() function:
class Foo(Bar):
def baz(self, **kwargs):
return super().baz(**kwargs)
For Python < 3, you must explicitly opt in to using new-style classes and use:
class Foo(Bar):
def baz(self, arg):
return super(Foo, self).baz(arg)
Python also has super as well:
super(type[, object-or-type])
Return a proxy object that delegates method calls to a parent or sibling class of type.
This is useful for accessing inherited methods that have been overridden in a class.
The search order is same as that used by getattr() except that the type itself is skipped.
Example:
class A(object): # deriving from 'object' declares A as a 'new-style-class'
def foo(self):
print "foo"
class B(A):
def foo(self):
super(B, self).foo() # calls 'A.foo()'
myB = B()
myB.foo()
ImmediateParentClass.frotz(self)
will be just fine, whether the immediate parent class defined frotz itself or inherited it. super is only needed for proper support of multiple inheritance (and then it only works if every class uses it properly). In general, AnyClass.whatever is going to look up whatever in AnyClass's ancestors if AnyClass doesn't define/override it, and this holds true for "child class calling parent's method" as for any other occurrence!
Python 3 has a different and simpler syntax for calling parent method.
If Foo class inherits from Bar, then from Bar.__init__ can be invoked from Foo via super().__init__():
class Foo(Bar):
def __init__(self, *args, **kwargs):
# invoke Bar.__init__
super().__init__(*args, **kwargs)
Many answers have explained how to call a method from the parent which has been overridden in the child.
However
"how do you call a parent class's method from child class?"
could also just mean:
"how do you call inherited methods?"
You can call methods inherited from a parent class just as if they were methods of the child class, as long as they haven't been overwritten.
e.g. in python 3:
class A():
def bar(self, string):
print("Hi, I'm bar, inherited from A"+string)
class B(A):
def baz(self):
self.bar(" - called by baz in B")
B().baz() # prints out "Hi, I'm bar, inherited from A - called by baz in B"
yes, this may be fairly obvious, but I feel that without pointing this out people may leave this thread with the impression you have to jump through ridiculous hoops just to access inherited methods in python. Especially as this question rates highly in searches for "how to access a parent class's method in Python", and the OP is written from the perspective of someone new to python.
I found:
https://docs.python.org/3/tutorial/classes.html#inheritance
to be useful in understanding how you access inherited methods.
Here is an example of using super():
#New-style classes inherit from object, or from another new-style class
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self):
self.moves.append('walk')
self.moves.append('run')
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super(Superdog, self).moves_setup()
self.moves.append('fly')
dog = Superdog('Freddy')
print dog.name # Freddy
dog.moves_setup()
print dog.get_moves() # ['walk', 'run', 'fly'].
#As you can see our Superdog has all moves defined in the base Dog class
There's a super() in Python too. It's a bit wonky, because of Python's old- and new-style classes, but is quite commonly used e.g. in constructors:
class Foo(Bar):
def __init__(self):
super(Foo, self).__init__()
self.baz = 5
I would recommend using CLASS.__bases__
something like this
class A:
def __init__(self):
print "I am Class %s"%self.__class__.__name__
for parentClass in self.__class__.__bases__:
print " I am inherited from:",parentClass.__name__
#parentClass.foo(self) <- call parents function with self as first param
class B(A):pass
class C(B):pass
a,b,c = A(),B(),C()
If you don't know how many arguments you might get, and want to pass them all through to the child as well:
class Foo(bar)
def baz(self, arg, *args, **kwargs):
# ... Do your thing
return super(Foo, self).baz(arg, *args, **kwargs)
(From: Python - Cleanest way to override __init__ where an optional kwarg must be used after the super() call?)
There is a super() in python also.
Example for how a super class method is called from a sub class method
class Dog(object):
name = ''
moves = []
def __init__(self, name):
self.name = name
def moves_setup(self,x):
self.moves.append('walk')
self.moves.append('run')
self.moves.append(x)
def get_moves(self):
return self.moves
class Superdog(Dog):
#Let's try to append new fly ability to our Superdog
def moves_setup(self):
#Set default moves by calling method of parent class
super().moves_setup("hello world")
self.moves.append('fly')
dog = Superdog('Freddy')
print (dog.name)
dog.moves_setup()
print (dog.get_moves())
This example is similar to the one explained above.However there is one difference that super doesn't have any arguments passed to it.This above code is executable in python 3.4 version.
In this example cafec_param is a base class (parent class) and abc is a child class. abc calls the AWC method in the base class.
class cafec_param:
def __init__(self,precip,pe,awc,nmonths):
self.precip = precip
self.pe = pe
self.awc = awc
self.nmonths = nmonths
def AWC(self):
if self.awc<254:
Ss = self.awc
Su = 0
self.Ss=Ss
else:
Ss = 254; Su = self.awc-254
self.Ss=Ss + Su
AWC = Ss + Su
return self.Ss
def test(self):
return self.Ss
#return self.Ss*4
class abc(cafec_param):
def rr(self):
return self.AWC()
ee=cafec_param('re',34,56,2)
dd=abc('re',34,56,2)
print(dd.rr())
print(ee.AWC())
print(ee.test())
Output
56
56
56
In Python 2, I didn't have a lot luck with super(). I used the answer from
jimifiki on this SO thread how to refer to a parent method in python?.
Then, I added my own little twist to it, which I think is an improvement in usability (Especially if you have long class names).
Define the base class in one module:
# myA.py
class A():
def foo( self ):
print "foo"
Then import the class into another modules as parent:
# myB.py
from myA import A as parent
class B( parent ):
def foo( self ):
parent.foo( self ) # calls 'A.foo()'
class department:
campus_name="attock"
def printer(self):
print(self.campus_name)
class CS_dept(department):
def overr_CS(self):
department.printer(self)
print("i am child class1")
c=CS_dept()
c.overr_CS()
If you want to call the method of any class, you can simply call Class.method on any instance of the class. If your inheritance is relatively clean, this will work on instances of a child class too:
class Foo:
def __init__(self, var):
self.var = var
def baz(self):
return self.var
class Bar(Foo):
pass
bar = Bar(1)
assert Foo.baz(bar) == 1
class a(object):
def my_hello(self):
print "hello ravi"
class b(a):
def my_hello(self):
super(b,self).my_hello()
print "hi"
obj = b()
obj.my_hello()
This is a more abstract method:
super(self.__class__,self).baz(arg)

Categories

Resources