First off this question is based around PySide, but it is a general question of inheritance for class attributes.
So I have an inheritance problem. I basically want to inherit from 2 PySide GUI classes. Multiple inheritance had major conflicts and gave errors. Basically, I made a custom widget and want to make that same widget into a dock widget (floating window).
One way that I found easy to implement was to override the getattr method to redirect attribute calls, like below.
class DockWidget(QtGui.QDockWidget):
def __init__(self):
super().__init__()
self.test = Test()
# Container is a custom widget containing the Test widget and a toolbar.
self.setWidget(self.test.getCustomContainer())
def __getattr__(self, name):
"""Call a property's method when the given attribute name is not found.
Note: Gives full access to the test attribute.
Args:
name (str): Method or property name.
"""
if hasattr(self.test, name):
return self.test.__getattribute__(name)
# end __getattr
# end class DockWidget
class Test(QtGui.QWidget):
def doSomething(self, msg):
print(msg)
# end doSomething
# end Test
widg = DockWidget()
widg.doSomething("Test")
I would like to know if this is considered really bad, and if there is a better way.
Since DockWidget and Test both inherit QWidget, you can use a mixin. This would allow you to do things like reimplement virtual methods, which would not be possible using __getattr__.
class WidgetMixin(object):
def doSomething(self, msg):
print(msg)
def closeEvent(self, event):
print(self.__class__.__name__)
class Test(WidgetMixin, QtGui.QWidget):
def __init__(self):
super().__init__()
class DockWidget(WidgetMixin, QtGui.QDockWidget):
def __init__(self):
super().__init__()
Related
I have a Parent and a Child class, both should execute their own fct in init but Child have to execute first the Parent fct :
class Parent(object):
def __init__(self):
self.fct()
def fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
self.fct()
def fct(self):
# add other stuff
Problem is that super().init() calls the Child fct and not the Parent one as I would like. Of course I could rename Child function as fct2 but I was wondering if I can do what I want to do without changing names (because fct and fct2 do the same thing conceptually speaking, they just apply on different things). It would be nice if I could call super().__init() as if were Parent object.
The idea of subclassining is this: if you ever need to use a method to the parent class, just do not create it in the child class.
Otherwise, in a hierarchy with complicated classes and mixins, and you really need the methods to have the same name, there is the name mangling mechanism, triggered by Python when using two underlines __ as a method or attribute prefix:
class Parent(object):
def __init__(self):
self.__fct()
def __fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
self.__fct()
def __fct(self):
# add other stuff
Using the __ prefix makes Python change the name of this method, both in declaration and where it is used when the class is created (at the time the class statement with its block is itself executed) - and both methods work as if they were named differently, each one only accessible, in an ordinary way, from code in its own class.
Some documentation, mainly older docs, will sometimes refer to this as the mechanism in Python to create "private methods". It is not the samething, although it can serve the same purpose in some use cases (like this). The __fct method above will be renamed respectively to Parent._Parent__fct and Child._Child__fct when the code is executed.
second way, without name mangling:
Without resorting to this name mangling mechanism, it is possible to retrieve attributes from the class where a piece of code is declared by using the __class__ special name (not self.__class__, just __class__) - it is part of the same mechanism Python uses to make argumentless super() work:
class Parent(object):
def __init__(self):
__class__.fct(self) # <- retrieved from the current class (Parent)
def fct(self):
# do some basic stuff
class Child(Parent):
def __init__(self):
super().__init__()
__class__.fct(self)
def fct(self):
# add other stuff
This will also work - just note that as the methods are retrieved from the class object, not from an instance, the instance have to be explicitly passed as an argument when calling the methods.
The name __class__ is inserted automatically in any methods that use it, and will always refer to the class that has the body were it appears - the class itself will be created "in the future", when all the class body is processed and the class command itself is resolved.
I have a class inherited from project.task named ProjectTask
The class has a copy method that overrides the copy function from project.task it's named Task
I need to run the base copy function from my class instead of the one of the parents class
this is my class code:
#api.multi
#api.returns('self', lambda value: value.id)
def copy(self, default=None):
if default is None:
default = {}
if not default.get('name'):
default['name'] = self.name.id
return super(ProjectTask, self).copy(default) #<-- I don't want to call the inherited class method I want to call the base class method instead
This is the copy method from the base class (Task)
#api.multi
#api.returns('self', lambda value: value.id)
def copy(self, default=None):
if default is None:
default = {}
if not default.get('name'):
default['name'] = _("%s (copy)") % self.name
return super(Task, self).copy(default) # <-- I want to run this method from my class (ProjectTask) which is the child class
Any advice will be more than welcome
With the parent class implementation you show, calling it with your own default should do what you want, as it will just pass it through to its own parent with no changes. (At least, that's true with the bare method code, I don't know what the odoo decorators do to change things.)
But if you really do need to skip over it for some non-obvious reason, you probably can do it. Generally speaking, these approaches will only work as intended if you don't expect your class to ever be used with multiple inheritance. If your MRO gets complicated, then you really want to be doing the normal thing with super and making all your methods play nicely together.
One option for skipping an inherited method is to directly name the class you want your call to go to (i.e. your grandparent class).
class Base():
def foo(self):
print("Base")
class Parent(Base):
def foo(self):
print("Parent")
super().foo() # super() in Python 3 is equivalent to super(Parent, self)
class Child(Parent):
def foo(self):
print("Child")
Base.foo(self) # call Base.foo directly, we need to pass the self argument ourselves
Another option would be to change the argument you give to super to name the parent class instead of your own class. Usually that's a newbie error, but if that's really what you want, it's allowed (though I'd strongly recommend adding a comment to the code explaining that you really do want that behavior!
class Child(Parent):
def foo(self):
print("Child")
super(Parent, self).foo() # Note: Deliberately skipping over Parent.foo here!
A final note: If you find yourself wanting to skip a parent class's implementation of some of its methods, perhaps you should reconsider if you should really be inheriting from it at all. It may be that you really want to be inheriting from the same base class as it instead, and skipping the middle class altogether. Obviously, this has its own limitations (maybe some library code does type checking for that class), but if you find yourself fighting the inheritance machinery, it may be that you're doing things the hard way, and there's an easier alternative.
This is a feature I miss in several languages and wonder if anyone has any idea how it can be done in Python.
The idea is that I have a base class:
class Base(object):
def __init__(self):
self.my_data = 0
def my_rebind_function(self):
pass
and a derived class:
class Child(Base):
def __init__(self):
super().__init__(self)
# Do some stuff here
self.my_rebind_function() # <==== This is the line I want to get rid of
def my_rebind_function(self):
# Do stuff with self.my_data
As can be seen above, I have a rebound function which I want called after the Child.__init__ has done its job. And I want this done for all inherited classes, so it would be great if it was performed by the base class, so I do not have to retype that line in every child class.
It would be nice if the language had a function like __finally__, operating similar to how it operates with exceptions. That is, it should run after all __init__-functions (of all derived classes) have been run, that would be great. So the call order would be something like:
Base1.__init__()
...
BaseN.__init__()
LeafChild.__init__()
LeafChild.__finally__()
BaseN.__finally__()
...
Base1.__finally__()
And then object construction is finished. This is also kind of similar to unit testing with setup, run and teardown functions.
You can do this with a metaclass like that:
class Meta(type):
def __call__(cls, *args, **kwargs):
print("start Meta.__call__")
instance = super().__call__(*args, **kwargs)
instance.my_rebind_function()
print("end Meta.__call__\n")
return instance
class Base(metaclass=Meta):
def __init__(self):
print("Base.__init__()")
self.my_data = 0
def my_rebind_function(self):
pass
class Child(Base):
def __init__(self):
super().__init__()
print("Child.__init__()")
def my_rebind_function(self):
print("Child.my_rebind_function")
# Do stuff with self.my_data
self.my_data = 999
if __name__ == '__main__':
c = Child()
print(c.my_data)
By overwriting Metaclass.__call__ you can hook after all __init__ ( and __new__) methods of the class-tree have run an before the instance is returned. This is the place to call your rebind function. To understand the call order i added some print statements. The output will look like this:
start Meta.__call__
Base.__init__()
Child.__init__()
Child.my_rebind_function
end Meta.__call__
999
If you want to read on and get deeper into details I can recommend following great article: https://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/
I may still not fully understand, but this seems to do what I (think) you want:
class Base(object):
def __init__(self):
print("Base.__init__() called")
self.my_data = 0
self.other_stuff()
self.my_rebind_function()
def other_stuff(self):
""" empty """
def my_rebind_function(self):
""" empty """
class Child(Base):
def __init__(self):
super(Child, self).__init__()
def other_stuff(self):
print("In Child.other_stuff() doing other stuff I want done in Child class")
def my_rebind_function(self):
print("In Child.my_rebind_function() doing stuff with self.my_data")
child = Child()
Output:
Base.__init__() called
In Child.other_stuff() doing other stuff I want done in Child class
In Child.my_rebind_function() doing stuff with self.my_data
If you want a "rebind" function to be invoked after each instance of a type which inherits from Base is instantiated, then I would say this "rebind" function can live outside the Base class(or any class inheriting from it).
You can have a factory function that gives you the object you need when you invoke it(for example give_me_a_processed_child_object()). This factory function basically instantiates an object and does something to it before it returns it to you.
Putting logic in __init__ is not a good idea because it obscures logic and intention. When you write kid = Child(), you don't expect many things to happen in the background, especially things that act on the instance of Child that you just created. What you expect is a fresh instance of Child.
A factory function, however, transparently does something to an object and returns it to you. This way you know you're getting an already processed instance.
Finally, you wanted to avoid adding "rebind" methods to your Child classes which you now you can since all that logic can be placed in your factory function.
I've attempted to create a Python interface class hierachy that looks something like:
class Axis(object, metaclass=ABCMeta):
def __init__(self):
# Do stuff...
class LinearAxis(Axis, metaclass=ABCMeta):
#abstractmethod
def move_linear(self, move_um):
pass
def __init__(self):
# Do stuff...
Axis.__init__(self)
class RotationalAxis(Axis, metaclass=ABCMeta):
#abstractmethod
def move_rotate(self, move_degree):
pass
def __init__(self):
# Do stuff...
Axis.__init__(self)
class XAxis(LinearAxis, metaclass=ABCMeta):
def __init__(self):
# Do stuff...
LinearAxis.__init__(self)
So basically an interface sort of like that with a bunch more functions everywhere and stuff in the constructors etc...
Then I go to derive off my interface:
class AnAxis(Axis):
def __init__(self):
# Do stuff...
Axis.__init__(self)
class AnLinearAxis(AnAxis, LinearAxis):
def move_linear(self, move_um):
pass
def __init__(self):
# Do stuff...
AnAxis.__init__(self)
LinearAxis.__init__(self)
class AnRotationalAxis(AnAxis, RotationalAxis):
def move_rotate(self, move_degree):
pass
def __init__(self):
# Do stuff...
AnAxis.__init__(self)
RotationalAxis.__init__(self)
class AnXAxis(AnLinearAxis, XAxis):
def __init__(self):
# Do stuff...
AnLinearAxis.__init__(self)
XAxis.__init__(self)
I'm trying to work out how to call the constructors properly. The way I have it, I'm pretty sure I call the interface constructors many times... So it's wrong... Is there a preferred way to do it? (Perhaps I don't call constructors in the interface classes, or I only call the interface constructor at the end up my implementation class.)
Also, I've never coded in this style and am open to better ways to code this.
You're probably looking for the super() function.
Calling super().something() calls the method something() of the parent class. It makes sure (using __mro__) to call the parent classes' method only once.
i.e. your code will look like this:
class AnLinearAxis(AnAxis, LinearAxis):
def move_linear(self, move_um):
pass
def __init__(self):
# Do stuff...
super().__init__()
Keep in mind you do not need to pass self or the metaclass. The metaclass passes by the inheritance. Also, you do not need to call super more than once. Super will call all of the parent classes' methods automatically.
Regarding the interface, it looks good but there's no need to pass metaclass=ABCMeta if the class you're inheriting from already has it. The metaclass is passed on by inheritance.
I want to be able to create an instance of a parent class X, with a string "Q" as an extra argument.
This string is to be a name being an identifier for a subclass Q of the parent class X.
I want the instance of the parent class to become (or be replaced with) an instance of the subclass.
I am aware that this is probably a classic problem (error?). After some searching I haven't found a suitable solution though.
I came up with the following solution myself;
I added a dictionary of possible identifiers as keys for their baseclass-instances to the init-method of the parent class.
Then assigned the class-attribute of the corresponding subclass to the current instances class-attribute.
I required the argument of the init-method not to be the default value to prevent infinite looping.
Following is an example of what the code looks like in practice;
class SpecialRule:
""""""
name="Special Rule"
description="This is a Special Rule."
def __init__(self, name=None):
""""""
print "SpecialInit"
if name!=None:
SPECIAL_RULES={
"Fly" : FlyRule(),
"Skirmish" : SkirmishRule()
} #dictionary coupling names to SpecialRuleclasses
self.__class__= SPECIAL_RULES[name].__class__
def __str__(self):
""""""
return self.name
class FlyRule(SpecialRule):
""""""
name="Fly"
description="Flies."
def __init__(self):
""""""
print "FlyInit"+self.name
SpecialRule.__init__(self)
def addtocontainer(self, container):
"""this instance messes with the attributes of its containing class when added to some sort of list"""
class SkirmishRule(SpecialRule):
""""""
name="Skirmish"
description="Skirmishes."
def __init__(self):
""""""
SpecialRule.__init__(self)
def addtocontainer(self, container):
"""this instance messes with the attributes of its containing class when added to some sort of list"""
test=SpecialRule("Fly")
print "evaluating resulting class"
print test.description
print test.__class__
</pre></code>
output:
>
SpecialInit
FlyInitFly
SpecialInit
evaluating resulting class
Flies.
main.FlyRule
>
Is there a more pythonic solution and are there foresee-able problems with mine?
(And am I mistaken that its a good programming practice to explicitly call the .__init__(self) of the parent class in .__init__ of the subclass?).
My solution feels a bit ... wrong ...
Quick recap so far;
Thanks for the quick answers
# Mark Tolonen's solution
I've been looking into the __new__-method, but when I try to make A, B and C in Mark Tolonen's example subclasses of Z, I get the error that class Z isn't defined yet. Also I'm not sure if instantiating class A the normal way ( with variable=A() outside of Z's scope ) is possible, unless you already have an instance of a subclass made and call the class as an attribute of an instance of a subclass of Z ... which doesn't seem very straightforward. __new__ is quite interesting so I'll fool around with it a bit more, your example is easier to grasp than what I got from the pythondocs.
# Greg Hewgill's solution
I tried the staticmethod-solution and it seems to work fine. I looked into using a seperate function as a factory before but I guessed it would get hard to manage a large program with a list of loose strands of constructor code in the main block, so I'm very happy to integrate it in the class.
I did experiment a bit seeing if I could turn the create-method into a decorated .__call__() but it got quite messy so I'll leave it at that.
I would solve this by using a function that encapsulates the choice of object:
class SpecialRule:
""""""
name="Special Rule"
description="This is a Special Rule."
#staticmethod
def create(name=None):
""""""
print "SpecialCreate"
if name!=None:
SPECIAL_RULES={
"Fly" : FlyRule,
"Skirmish" : SkirmishRule
} #dictionary coupling names to SpecialRuleclasses
return SPECIAL_RULES[name]()
else:
return SpecialRule()
I have used the #staticmethod decorator to allow you to call the create() method without already having an instance of the object. You would call this like:
SpecialRule.create("Fly")
Look up the __new__ method. It is the correct way to override how a class is created vs. initialized.
Here's a quick hack:
class Z(object):
class A(object):
def name(self):
return "I'm A!"
class B(object):
def name(self):
return "I'm B!"
class C(object):
def name(self):
return "I'm C!"
D = {'A':A,'B':B,'C':C}
def __new__(cls,t):
return cls.D[t]()