Calling method, classmethod, staticmethod in the same Python class - python

From a famous example, I learned the difference between method, classmethod and staticmethod in a Python class.
Source:
What is the difference between #staticmethod and #classmethod in Python?
class A(object):
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
#classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
#staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
# My Guesses
def My_Question(self,x):
self.foo(x)
A.class_foo(x)
A.static_foo(x)
a=A()
Now I am wondering, how to call a method, #classmethod, and #staticmethod inside the class.
I put my guesses in the My_Question function above, please correct me if I am wrong with any of these.

Yes, your guesses will work. Note that it is also possible/normal to call staticmethods and classmethods outside the class:
class A():
...
A.class_foo()
A.static_foo()
Also note that inside regular instance methods, it's customary to call the staticmethods and class methods directly on the instance (self) rather than the class (A):
class A():
def instance_method(self):
self.class_foo()
self.static_foo()
This allow for inheritance to work as you might expect -- If I create a B subclass from A, if I call B.instance_method(), my class_foo function will get B instead of A as the cls argument -- And possibly, if I override static_foo on B to do something slightly different than A.static_foo, this will allow the overridden version to be called as well.
Some examples might make this more clear:
class A(object):
#staticmethod
def static():
print("Static, in A")
#staticmethod
def staticoverride():
print("Static, in A, overrideable")
#classmethod
def clsmethod(cls):
print("class, in A", cls)
#classmethod
def clsmethodoverrideable(cls):
print("class, in A, overridable", cls)
def instance_method(self):
self.static()
self.staticoverride()
self.clsmethod()
self.clsmethodoverride()
class B(A):
#classmethod
def clsmethodoverrideable(cls):
print("class, in B, overridable", cls)
#staticmethod
def staticoverride():
print("Static, in B, overrideable")
a = A()
b = B()
a.instance_method()
b.instance_method()
...
After you've run that, try it by changing all of the self. to A. inside instance_method. Rerun and compare. You'll see that all of the references to B have gone (even when you're calling b.instance_method()). This is why you want to use self rather than the class.

As #wim said, what you have is right. Here's the output when My_Question is called.
>>> a.My_Question("My_Answer=D")
executing foo(<__main__.A object at 0x0000015790FF4668>,My_Answer=D)
executing class_foo(<class '__main__.A'>,My_Answer=D)
executing static_foo(My_Answer=D)

Related

What is the difference between calling a method from parent class using super() and using self?

class Car:
def __init__(self, car_name, manufacturer, cost):
self.__car_name=car_name
self.__manufacturer=manufacturer
self.__cost=cost
def display_car_details(self):
print(self.__car_name, self.__manufacturer, self.__cost)
class Super_Car(Car):
def __init__(self, car_name, manufacturer, cost,
top_speed, material_used, engine_type):
super().__init__(car_name, manufacturer, cost)
self.__top_speed=top_speed
self.__material_used=material_used
self.__engine_type=engine_type
def display_super_car_details(self):
self.display_car_details() # this?
super().display_car_details() # or that?
print(self.__top_speed, self.__material_used,
self.__engine_type)
Please tell me the difference between calling display_car_details() by using self.… and calling by super().…. The method which calls the above function is in Super_car class with name display_super_car_details().
In your specific case, there is no difference. If the methods had the same name, you would not be calling the parent class using self.…, but your own method again, creating infinite recursion.
With super(), the call is always going to the method in the parent class in Method Resolution Order, thus preventing the infinite recursion. More details on super() itself can also be found in the official documentation.
Generally, you only need super() if you really need the inherited method, such as when re-implementing that exact method.
For example, running this code will lead to RecursionError, due to maximum recursion depth exceeded. The reason is that Bar.method1() calls itself over and over, because we are using self.… instead of super().….
class Foo:
def method1(self):
print("I just want to be called")
class Bar(Foo):
def method1(self):
self.method1() # oops
b = Bar()
b.method1()
This on the other hand has the intended effect:
class Foo:
def method1(self):
print("I just want to be called")
class Bar(Foo):
def method1(self):
super().method1() # sweet
b = Bar()
b.method1()
Again, in your specific example it does not matter, because the other method (display_car_details) is only defined in the parent class, so it is unambiguous which method to call. If you had overridden display_car_details with something different, the use of super() and self would again yield different results:
class Bar(Foo):
def method1(self):
print("You are not supposed to call this")
def method2(self):
super().method1()
def method3(self):
self.method1()
Observe the difference in the interactive interpreter:
>>> b = Bar()
>>> b.method1()
You are not supposed to call this
>>> b.method2()
I just want to be called
>>> b.method3()
You are not supposed to call this

Inherit decorator defined in parent class

Rather than try to explain verbosely, this code snippet should do it.
def decorator(function):
return lambda self: function(self) + 1
# imported from library
class A(object):
# override
def method_1(self):
pass
# override
def method_2(self):
pass
class B(A):
def method_1(self):
return 1
class C(B):
#decorator
def method_2(self):
return 1
class D(B):
#decorator
def method_2(self):
return 2
print C().method_1() # 1
print C().method_2() # 2
print D().method_2() # 3
This works well, but as decorator is only used on method_2, maybe it should be pulled in.
class B(A):
def method_1(self):
return 1
#staticmethod
def decorator(function):
return lambda self: function(self) + 1
class C(B):
#B.decorator
def method_2(self):
return 1
This works, but it's not clear to me if this is actually better. In particular whether Python treats B.decorator like an external function which just happens to be defined on B, or if C inheriting from B makes this more efficient.
What I actually want is some way to define the decorator on B and use it on C like this.
class C(B):
#self.decorator
def method_2(self):
return 1
This doesn't work. Is there a better alternative to either perhaps? Thanks.
Besides the fact that there is no reason to move the decoration definition to inside the class, as pointed in the comments, there goes some clarifications:
when you do use the #staticmethod decorator on your decorator definition, you will have the exact same behavior as if it was defined outside any class body.
If you do use #classmethod instead, as in
class B(A):
#classmethod
def decorator(cls, function):
return lambda self: function(self) + 1
The difference is that the decorator is passed the class it is defined in, as an object as the first parameter. This could be of some use, or not - note that the decorated method itself will still be a regular instance method - unless you make use of #classmethod or #staticmethod decorators inside the decorator body itself, changing the wrapper function it returns.
As for efficient: the most "efficient" thing will be to just leave teh decorator outside any class body - the difference for a "#staticmethod" defiend decorator will be minimal - probably impossible to measure at all, but should involve two or three less attribute accesses on class creation (which won't usually be inside a critical loop in the application) - so, no, there is no difference there.
Now, it is not what you are asking, but someone could come here looking for how to automatically re-apply a decorator in a method in a superclass when overreding this method in a sub-class:
That is not easy to do, but should be possible with specially prepared decorators (which will anotate themselves on the wrapped method)

Extract a mixin from a common function in Python

Consider two classes that each have an existing shared function, but separate inheritance paths:
class ClazzA(SuperClazzX):
def foo(self):
return goo(super(SuperClazzX, self).foo())
class ClazzB(SuperClazzY):
def foo(self):
return goo(super(SuperClazzY, self).foo())
foo is clearly a common function which can be extracted to a mixin, what is the right way to do so, such that the functionality remains even though a different super foo is to be called?
Edit: I removed the other mixin, it was confusing and irrelevant.
EDIT: simpler code
Mixin has access to other bases of (future) child class, here C::Mixin::foo has access to the other base of C, namely C::Base::foo. Authoritative explanation here.
class Base(object): # must be new-style class in py 2.x
def foo(self):
print "base foo called"
class Mixin(object):
def foo(self):
rv = super(Mixin, self).foo() # call actual implementation
# use rv
class C(Mixin, Base):
pass
C().foo()
base foo called
What this does:
self is instance of C, it's __mro__ is (Mixin, Base)
when Mixin calls super(Mixin, self), the resulting object retains bases (Base,)
when .foo attribute is resolved, this object finds it in Base
thus Base.foo is invoked with original self
If you want custom control over implementation, you have access to your own bases, e.g.:
class Foo(...):
def foo(self):
print self.__class__.__bases__
Your mixin could look something like this, super-manual approach:
class Mixin(object):
def foo(self):
assert self.__class__ is not Mixin # no point calling directly
# find the other base
other = [b for b in self.__class__.__bases__ if b is not Mixin]
# what to do if there's more than 1 real base?
# pick base explicitly
base = other[1]
# call it,
return something(base.foo(self, some_args))

Python: possible to call static method from within class without qualifying the name

This is annoying:
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
MyClass.foo()
Is there a way to make this work without naming MyClass in the call? i.e. so I can just say foo() on the last line?
There is no way to use foo and get what you want. There is no implicit class scope, so foo is either a local or a global, neither of which you want.
You might find classmethods more useful:
class MyClass:
#classmethod
def foo(cls):
print "hi"
#classmethod
def bar(cls):
cls.foo()
This way, at least you don't have to repeat the name of the class.
Not possible. It is a question of language design. Compare that to C++, where both this (the same as Python self; in Python you have to write self.var, in C++ you may write just var, not this->var) and own class are used by default in member functions, and you will probably see that sometimes that's good and sometimes that's annoying. The only thing possible is to get used to that feature.
You 'variable-ize' the class name. This will not remove, but shorten the name.
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
c.foo()
c = MyClass
You can do something hacky by making a module level function foo and then adding it to the class namespace with staticmethod:
def foo():
print "hi"
class MyClass(object):
foo = staticmethod(foo)
#classmethod
def bar(cls):
return cls.foo()
def baz(self):
return foo()
c = MyClass()
c.bar()
c.baz()
MyClass.bar()
MyClass.foo()

What is the Python equivalent of a Ruby class method?

In ruby you can do this:
class A
def self.a
'A.a'
end
end
puts A.a #-> A.a
How can this be done in python. I need a method of a class to be called without it being called on an instance of the class. When I try to do this I get this error:
unbound method METHOD must be called with CLASS instance as first argument (got nothing instead)
This is what I tried:
class A
def a():
return 'A.a'
print A.a()
What you're looking for is the staticmethod decorator, which can be used to make methods that don't require a first implicit argument. It can be used like this:
class A(object):
#staticmethod
def a():
return 'A.a'
On the other hand, if you wish to access the class (not the instance) from the method, you can use the classmethod decorator, which is used mostly the same way:
class A(object):
#classmethod
def a(cls):
return '%s.a' % cls.__name__
Which can still be called without instanciating the object (A.a()).
There are two ways to do this:
#staticmethod
def foo(): # No implicit parameter
print 'foo'
#classmethod
def foo(cls): # Class as implicit paramter
print cls
The difference is that a static method has no implicit parameters at all. A class method receives the class that it is called on in exactly the same way that a normal method receives the instance.
Which one you use depends on if you want the method to have access to the class or not.
Either one can be called without an instance.
You can also access the class object in a static method using __class__:
class A() :
#staticmethod
def a() :
return '{}.a'.format( __class__.__name__ )
At least this works in Python 3.1

Categories

Resources