I need to write a base class (in this example, class A) that will likely, but not always, be subclassed. I want to call the 'Run' method from the base class only if its not subclassed, else only call the the 'Run' method from the subclasses.
This is what I have, it seems to work but I'm wondering if there is an easier or more Pythonic way.
class A(object):
def __init__(self):
pass
def Run(self):
print "Calling A.Run()"
class B(A):
def __init__(self):
A.__init__(self)
pass
def Run(self):
print "Calling B.Run()"
subs = A.__subclasses__()
if subs: inst = [i() for i in subs]
else: inst = [A()]
[each.Run() for each in inst]
What you have looks correct, except that most programmers would look at the B.Run method and think: "Oh, he forgot to call super. Let me just add that..." but I'm sure you'd explain what you're doing in your real implementation :)
If you're worried about something like slicing in C++, then be reassured. What you have is good.
As for making it "easier", I'm not sure how you could simplify it aside from removing A's empty __init__ function and removing pass from B's __init__.
I want to call the 'Run' method from the base class only if its not subclassed, else only call the the 'Run' method from the subclasses.
This is what happens by default, the most specific method is called.
If you really don't want the base method to be available from subclasses, you can write something like this:
class C(object):
def Run(self):
if self.__class__ != C:
raise NotImplementedError("You need to override this method")
Related
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.
I'm learning about classes and design in Python, and I have a question of how to implement the following pattern:
I would like the class to initialise with some code, some of which I would like to be able to call later on via a function, e.g.:
class c:
def __init__(self):
print('1')
m()
def m(self):
print('2')
print('3')
I am after something like the above, but I cannot use m() in init as it will not have been declared at this point. Is there anyway of implementing this without having to use the same code twice?
You need to use self.m()
class c:
def __init__(self):
print('1')
self.m()
def m(self):
print('2')
print('3')
cannot use m() in init as it will not have been declared at this point
This is not the case. Python's execution does not work that way; it will not care where the m definition is until it is actually needed.
The reason you got an error is because there is no "implicit this" in Python; writing m here looks for the global m and not a method m belonging to the instance. Just as you must accept an explicit self parameter, so you must explicitly look for methods on self: thus, self.m().
You may be looking at #staticmethod or #classmethod decorators.
class c:
def __init__(self):
print('1')
m()
#staticmethod
def m():
# You don't rely on any class method initialised attributes
print('2')
print('3')
#classmethod
def m(cls):
# You may use cls to refer to the class itself
print('2')
print('3')
You can choose which suits your case better for your particular method.
Both would allow you to call a function as c.m()
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'm using Python 3.
I know about the #classmethod decorator. Also, I know that classmethods can be called from instances.
class HappyClass(object):
#classmethod
def say_hello():
print('hello')
HappyClass.say_hello() # hello
HappyClass().say_hello() # hello
However, I don't seem to be able to create class methods dynamically AND let them be called from instances. Let's say I want something like
class SadClass(object):
def __init__(self, *args, **kwargs):
# create a class method say_dynamic
SadClass.say_dynamic() # prints "dynamic!"
SadClass().say_dynamic() # prints "dynamic!"
I've played with cls.__dict__ (which produces exceptions), and with setattr(cls, 'say_dynamic', blahblah) (which only makes the thingie callable from the class and not the instance).
If you ask me why, I wanted to make a lazy class property. But it cannot be called from instances.
#classmethod
def search_url(cls):
if hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url
Maybe because the property hasn't been called from the class yet...
In summary, I want to add a lazy, class method that can be called from the instance... Can this be achieved in an elegant (nottoomanylines) way?
Any thoughts?
How I achieved it
Sorry, my examples were very bad ones :\
Anyway, in the end I did it like this...
#classmethod
def search_url(cls):
if not hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url
And the setattr does work, but I had made a mistake when testing it...
You can add a function to a class at any point, a practice known as monkey-patching:
class SadClass:
pass
#classmethod
def say_dynamic(cls):
print('hello')
SadClass.say_dynamic = say_dynamic
>>> SadClass.say_dynamic()
hello
>>> SadClass().say_dynamic()
hello
Note that you are using the classmethod decorator, but your function accepts no arguments, which indicates that it's designed to be a static method. Did you mean to use staticmethod instead?
If you want to create class methods, do not create them in the __init__ function as it is then recreated for each instance creation. However, following works:
class SadClass(object):
pass
def say_dynamic(cls):
print("dynamic")
SadClass.say_dynamic = classmethod(say_dynamic)
# or
setattr(SadClass, 'say_dynamic', classmethod(say_dynamic))
SadClass.say_dynamic() # prints "dynamic!"
SadClass().say_dynamic() # prints "dynamic!"
Of course, in the __init__ method the self argument is an instance, and not the class: to put the method in the class there, you can hack something like
class SadClass(object):
def __init__(self, *args, **kwargs):
#classmethod
def say_dynamic(cls):
print("dynamic!")
setattr(self.__class__, 'say_dynamic', say_dynamic)
But it will again reset the method for each instance creation, possibly needlessly. And notice that your code most probably fails because you are calling the SadClass.say_dynamic() before any instances are created, and thus before the class method is injected.
Also, notice that a classmethod gets the implicit class argument cls; if you do want your function to be called without any arguments, use the staticmethod decorator.
As a side note, you can just use an instance attribute to hold a function:
>>> class Test:
... pass
...
>>> t=Test()
>>> t.monkey_patch=lambda s: print(s)
>>> t.monkey_patch('Hello from the monkey patch')
Hello from the monkey patch
How I achieved it:
#classmethod
def search_url(cls):
if not hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url
I have a class hierarchy where __init__ in class Base performs some pre-initialization and then calls method calculate. The calculate method is defined in class Base, but it's expected to be redefined in derived classes. The redefined calculate will use some of the attributes that are only available in class Derived:
class Base:
def __init__(self, args):
# perform some pre-initialization
...
# now call method "calculate"
self.calculate()
class Derived(Base):
def __init__(self, args, additional_attr):
super().__init__(args)
# do some work and create new instance attributes
...
self.additional_attr = additional_attr
This is not going to work because calculate method in class Derived will be invoked before self.additional_attr is assigned.
I can't move super().__init__(args) call to the end of the __init__ method because some of the work it does has to happen before processing additional_attr.
What to do?
Perhaps you shouldn't have the calculate() call in your constructor then. If you can't construct a derived object by allowing the base constructor to complete first, then you must be doing something wrong IMHO. A sensible approach would be to move that call out of the constructor and perhaps create a factory method to make that call automatically. Then use that method if you need precalculated instances.
class Base(object):
def __init__(self, args):
# perform some initialization
pass
def calculate(self):
# do stuff
pass
#classmethod
def precalculated(cls, args):
# construct first
newBase = cls(args)
# now call method "calculate"
newBase.calculate()
return newBase
class Derived(Base):
def __init__(self, args, additional_attr):
super(Derived, self).__init__(args)
# do some work and create new instance attributes
self.additional_attr = additional_attr
#classmethod
def precalculated(cls, args, additional_attr): # also if you want
newDerived = cls(args, additional_attr)
newDerived.calculate()
return newDerived
newBase = Base('foo')
precalculatedBase = Base.precalculated('foo')
newDerived = Derived('foo', 'bar')
precalculatedDerived = Derived.precalculated('foo', 'bar')
This is bad design, IMHO, and you're obusing the object system of Python. Consider that in other OO languages like C++, you don't even have control over the creation of base classes. The derived class's constructor calls the base constructor before your code runs. Such behavior is almost always expected of well-behaved class hierarchies, and changing it can only lead to problems.
Sure, you can do some patching (such as assigning self.additional_attr before the call to super's constructor, or other tricks), but the better way would be to change your design so that it won't require such hacks. Since you've presented an abstract example here, it's hard to give more comprehensive design advice.
In order for something like this to work, you need to design a protocol that allows the base and derived class(es) to cooperate with each other to accomplish the object initialization task:
class Base:
def __init__(self, args, *additional_args):
# perform some pre-initialization
# ...
# perform any futher initialization needed by derived classes
self.subclass_setup(*additional_args)
# now call method "calculate"
self.calculate()
def subclass_setup(self, *args):
pass
class Derived(Base):
def __init__(self, args, additional_attr):
super().__init__(args, additional_attr)
def subclass_setup(self, additional_attr):
# do some work and create new instance attributes
# ...
self.additional_attr = additional_attr
Can you pass the additional_attr as a parameter to __init__ method of base class and propogate it from there to calculate method?
Say something like:
class Base(object):
def __init__(self, args,additional_attr):
print 'Args for base class:%s' %(args)
self.calculate(additional_attr)
class Derived(Base):
def __init__(self, args, additional_attr):
super(Derived,self).__init__(args,additional_attr)
def calculate(self,val):
print 'Arg for calculate:%s' %(val)
self.additional_attr = val
>>> d = Derived(['test','name'],100)
Args for base class:['test', 'name']
Arg for calculate:100
This is roundabout way, but with no information about what the pre-initialisation steps are, it is hard to say whether the above approach would help you.