Inheriting from variable class in python - python

I have a class foo that inherits from bar. However I also want to have the option when initializing foo to have it inherit from wall instead of bar. I am thinking something like this:
class Foo():
def __init__(self, pclass):
self.inherit(pclass)
super().__init__()
Foo(Bar) # child of Bar
Foo(Wall) # child of Wall
Is this possible in Python?

It's not really possible easily, because classes are defined at the time of executing the class block, not at the time of creating an instance.
A popular design pattern to use instead would be to put the common code into a mixin:
class FooMixin:
# stuff needed by both Foo(Bar) and Foo(Wall)
class FooBar(FooMixin, Bar):
...
class FooWall(FooMixin, Wall):
...
Then you can use some sort of factory function:
def make_foo(parent, *init_args, **init_kwargs):
if parent is Bar:
Foo = FooBar
elif parent is Wall:
Foo = FooWall
return Foo(*init_args, **init_kwargs)

Related

python method override with multiple inheritance and instancing

Here is my code - my base_file.py
class modify_file(object):
def modify_file_delete_obj():
print "modify file here"
def modify_file_add_attributes():
print "modify file here"
return ["data"]
class task_list(object):
modify_file_instance = modify_file() #problem part when accessing from project1.py
def check_topology():
data = modify_file_instance.modify_file_add_attributes()
#use this data further in this method
def check_particles():
print "check for particles"
project1.py file
import base_file as base_file
class project1(base_file.modify_file,base_file.task_list):
#overriding method of modify_file class
def modify_file_add_attributes(self):
print "different attributes to modify"
return ["different data"]
The idea is to run base_file.py for most projects and the project specific ones when required.
But when i run the method
"check_topology" from project1.py
the modify_file class is being derived from the base_file.py not project1.py
So the output is still ["data"] not ["different data"]
If you want to correctly use inheritance, define a base class Pet which provides a method to be overridden by a specific kind of pet.
class Pet(object):
def talk(self):
pass
class Cat(Pet):
def talk(self):
return "meow"
class Dog(Pet):
def talk(self):
return "woof"
pets = [Cat(), Dog(), Cat()]
for p in pets:
print(p.talk())
# Outputs
# meow
# woof
# meow
(I leave the issue of what Pet.talk should do, if anything, as a topic for another question.)
You are mixing up object composition with multiple inheritance.
The task_list class uses object composition when it creates an internal instance of the modify_file class. But there is a problem here in that you are creating it as a class attribute, which means it will be shared by all instances of task_list. It should instead be an instance attribute that is created in an __init__ method:
class task_list(object):
def __init__(self):
super(task_list, self).__init__()
self.modify_file_instance = modify_file()
def check_topology(self):
data = self.modify_file_instance.modify_file_add_attributes()
The project1 class uses multiple inheritance, when in fact it should use single inheritance. It is a kind of task_list, so it makes no sense for it to inherit modify_file as well. Instead, it should create it's own internal sub-class of modify_file - i.e. use object composition, just like task_list class does:
# custom modify_file sub-class to override methods
class project1_modify_file(base_file.modify_file):
def modify_file_add_attributes(self):
print "different attributes to modify"
return ["different data"]
class project1(base_file.task_list):
def __init__(self):
super(project1, self).__init__()
self.modify_file_instance = project1_modify_file()
Now you have a consistent interface. So when project1.check_topology() is called, it will in turn call task_list.check_topology() (by inheritance), which then accessses self.modify_file_instance (by composition):
>>> p = project1()
>>> p.check_topology()
different attributes to modify
In your dog class you're re-constructing an instance of cat, this instance (and the cat type) does not know they are inherited elsewhere by pets.
So you can naturally try:
class cat(object):
def meow(self):
self.sound = "meow"
return self.sound
class dog(object):
def woof(self):
return self.meow()
class pets(cat,dog):
def meow(self):
self.sound = "meow meow"
return self.sound
print(pets().woof())
Which still make no sense with those actual names, but you told they are fake names so it make be OK.

Python Classes: turn all inherited methods private

Class Bar inherits from Foo:
class Foo(object):
def foo_meth_1(self):
return 'foometh1'
def foo_meth_2(self):
return 'foometh2'
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
Is there a way of turning all methods inherited from Foo private?
class Bar(Foo):
def bar_meth(self):
return 'bar_meth'
def __foo_meth_1(self):
return 'foometh1'
def __foo_meth_2(self):
return 'foometh2'
Python doesn't have privates, only obfuscated method names. But I suppose you could iterate over the methods of the superclass when creating the instance, removing them from yourself and creating new obfuscatingly named method names for those functions. setattr and getattr could be useful if you use a function to create obfuscated names.
With that said, it's a pretty cthuhlu-oid thing to do. You mention the intent is to keep the namespace cleaner, but this is more like mixing ammonia and chlorine. If the method needs to be hidden, hide it in the superclass. The don't create instances of the superclass -- instead create a specific class that wraps the hidden methods in public ones, which you could name the same thing but strip the leading whitespace.
Assuming I understand your intent correctly, I would suggest doing something like this:
class BaseFoo(object):
def __init__(self):
raise NotImplementedError('No instances of BaseFoo please.')
def _foo(self):
return 'Foo.'
def _bar(self):
return 'Bar.'
class HiddenFoo(BaseFoo):
def __init__(self): pass
class PublicFoo(BaseFoo):
def __init__(self): pass
foo = BaseFoo._foo
bar = BaseFoo._bar
def try_foobar(instance):
print 'Trying ' + instance.__class__.__name__
try:
print 'foo: ' + instance.foo
print 'bar: ' + instance.bar
except AttributeError, e:
print e
foo_1 = HiddenFoo()
foo_2 = PublicFoo()
try_foobar(foo_1)
try_foobar(foo_2)
And if PublicFoo.foo would do something more than BaseFoo.foo, you would write a wrapper that does whatever is needed, and then calls foo from the superclass.
This is only possible with Pyhtons's metaclasses. But this is quite sophisticated and I am not sure if it is worth the effort. For details have a look here
Why would you like to do so?
Since foo() and __foo() are completely different methods with no link between them, Python is unable to understand what you want to do. So you have to explain to it step by step, meaning (like sapth said) to remove the old methods and add new ones.
This is an Object Oriented Design flaw and a better approach would be through delegation:
class Basic:
def meth_1(self):
return 'meth1'
def meth_2(self):
return 'meth2'
class Foo(Basic):
# Nothing to do here
pass
class Bar:
def __init__(self):
self.dg = Basic()
def bar_meth(self):
return 'bar_meth ' + self.__meth_1()
def __meth_1(self):
return self.dg.meth_1()
def __meth_2(self):
return self.dg.meth_2()
While Foo inherits the Basic class because he wants the public methods from him, Bar will only delegate the job to Basic because he doesn't want to integrate Basic's interface into its own interface.
You can use metaclasses, but Boo will no longer be an actual subclass of Foo, unless you want Foo's methods to be both 'private' and 'public' in instances of Bar (you cannot selectively inherit names or delattr members inherited from parent classes). Here is a very contrived example:
from inspect import getmembers, isfunction
class TurnPrivateMetaclass(type):
def __new__(cls, name, bases, d):
private = {'__%s' % i:j for i,j in getmembers(bases[0]) if isfunction(j)}
d.update(private)
return type.__new__(cls, name, (), d)
class Foo:
def foo_meth_1(self): return 'foometh1'
def foo_meth_2(self): return 'foometh2'
class Bar(Foo, metaclass=TurnPrivateMetaclass):
def bar_meth(self): return 'bar_meth'
b = Bar()
assert b.__foo_meth_1() == 'foometh1'
assert b.__foo_meth_2() == 'foometh2'
assert b.bar_meth() == 'bar_meth
If you wanted to get attribute access working, you could create a new Foo base class in __new__ with all renamed methods removed.

How can I get the name of a child class?

class Foo():
class Bar(Foo):
A method of Foo have to know the name of the child class. How can I get the name?
In this example I want to get "Bar".
I'm sorry for my english.
If it needs to be an instancemethod:
def meth(self): print self.__class__
If you want a classmethod:
#classmethod
def meth(cls): print cls
Extremely old, but since i stumbled upon this by duckduck'ing the topic...
Consider you have:
class Foo():
pass
class Bar(Foo):
pass
Python 3
my_bar = Bar()
type(my_bar).__name__
# Bar
Python 2
my_bar = Bar()
my_bar.__class__.__name__
# Bar

Question about python and classes

I have a base class and a few derived in Python:
class Base:
def Foo(self):
pass
# First derived class
class Der1(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
# Second derived class
class Der2(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
The question is:
I have some predefined code in Der1. Almost all functions from Der2 do the same. How can I write this with less code?
I can't add that code to the parent. Parent class shouldn't be touched.
For example, Der2.OwnFoo does the same as Der1.OwnFoo, maybe there is some construction in python just to call OwnFoo from first class and not to write that code again?
I can't change the parent of Der1 and Der2! It should be Base.
Since you can't change the inheritance structure, make a helper class that contains the common code and include it by composition rather than inheritance.
# Common code goes in this new class
class DerHelper:
def __init__(self, parent):
self._parent = parent
def OwnFoo(self):
print 'Do something 1', self._parent
def OwnFoo2(self):
print 'Do something 2', self._parent
def Foo(self):
print 'Do something 3', self._parent
# First derived class
class Der1(Base):
def __init__(self):
# include helper class by composition
self._helper = DerHelper('Der1')
def OwnFoo(self):
self._helper.OwnFoo()
def OwnFoo2(self):
self._helper.OwnFoo2()
def Foo(self):
self._helper.Foo()
# Second derived class
class Der2(Base):
def __init__(self):
# include helper class by composition
self._helper = DerHelper('Der2')
def OwnFoo(self):
self._helper.OwnFoo()
def OwnFoo2(self):
self._helper.OwnFoo2()
def Foo(self):
self._helper.Foo()
Of course, you could pass a reference to the parent instead of a string. I just did it this way for demonstration purposes.
Usage:
d = Der1()
d.OwnFoo()
d.OwnFoo2()
d.Foo()
d = Der2()
d.OwnFoo()
d.OwnFoo2()
d.Foo()
Output:
Do something 1 Der1
Do something 2 Der1
Do something 3 Der1
Do something 1 Der2
Do something 2 Der2
Do something 3 Der2
Make Der2 a subclass of Der1 and you're done.
class Base:
def Foo(self):
pass
# First derived class
class Der1(Base):
def OwnFoo(self):
# Do something 1
def OwnFoo2(self):
# Do something 2
def Foo(self):
# Do something 3
# Second derived class (subclasses Der1)
class Der2(Der1):
pass
Any behavior within Der2 you'd like to specialize can added within the class definition. If you create a new method of the same name in Der2 (e.g. Der2.OwnFoo()), then it will overload the default method that is inherited from Der1.
EDIT: If you can't change the parent, put all of the behavior you want to inherit in the base class keeping in mind that you can overload or customize any of the methods in the subclasses.
In code:
# Base class
class Base:
def Foo1(self):
# Do something 1
def Foo2(self):
# Do something 2
def Foo(self):
# Do something 3
# First derived class, inherits everything from Base
class Der1(Base):
pass
# Second derived class
class Der2(Base):
pass
There is a "trick" you can do to call the original method inherited from the parent, capture the return value and then customize the behavior. This will only work if the method actually returns a value, and can be dangerous if the method manipulates attributes within the class, unless that's what you want and expect it.
In code:
# Second derived class, with customized methods
class Der2(Base):
# Anything that is not explicitly define is inherited from parent
# as-is.
def Foo(self):
# My Foo() overloads Base.Foo() inherited from parent class.
# Do something "special" 3
def Foo1(self):
# Calls parent Base.Foo1() and then manipulates return data.
base_output = Base.Foo1(self)
# Do something "special" 1 with 'base_output'
Is this a homework?
Look at the first line of Der2:
class Der2(Base):
What says what is its parent (e.g. a class it descends and herits methods and attributes from)? How could you change this?
If Der1 and Der2 share a lot of code, then you should put that in a superclass; since Base cannot be touched, introduce a class in between:
class Der(Base):
def OwnFoo(self):
...
class Der1(Der):
...
class Der2(Der):
...
(Depending on you class hierachy, the "derive Der2 from Der1" option that others recommend may also be valid.)
How about making Der2 subclass Der1?

How do I call a parent class's method from a child class in Python?

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