Why use classmethod instead of staticmethod? [duplicate] - python

This question already has answers here:
Difference between #staticmethod and #classmethod
(35 answers)
Closed 9 years ago.
I know what they do and I've seen many examples of both, but I haven't found a single example where I would have to use classmethod instead of replacing it with a staticmethod.
The most common example of classmethod I've seen is for creating a new instance of the class itself, like this (very simplified example, there's no use of the method atm. but you get the idea):
class Foo:
#classmethod
def create_new(cls):
return cls()
This would return a new instance of Foo when calling foo = Foo.create_new().
Now why can't I just use this instead:
class Foo:
#staticmethod
def create_new():
return Foo()
It does the exact same, why should I ever use a classmethod over a staticmethod?

There's little difference in your example, but suppose you created a subclass of Foo and called the create_new method on the subclass...
class Bar(Foo):
pass
obj = Bar.create_new()
...then this base class would cause a new Bar object to be created...
class Foo:
#classmethod
def create_new(cls):
return cls()
...whereas this base class would cause a new Foo object to be created...
class Foo:
#staticmethod
def create_new():
return Foo()
...so the choice would depend which behavior you want.

Yes, those two classes would do the same.
However, now imagine a subtype of that class:
class Bar (Foo):
pass
Now calling Bar.create_new does something different. For the static method, you get a Foo. For the class method, you get a Bar.
So the important difference is that a class method gets the type passed as a parameter.

From the docs, a class method receives its class as an implicit argument, while static methods are unaware of the class in which they reside.
This can be useful in situations where you have an inherited static method that you want to override with different behaviour in the subclass.

Related

Python get child class inside parent class static/class method [duplicate]

This question already has answers here:
Difference between #staticmethod and #classmethod
(35 answers)
Class (static) variables and methods
(27 answers)
Closed 9 months ago.
The output of:
class Dog():
def get_class():
return __class__
class Cat():
def get_class():
return __class__
print(Dog.get_class())
print(Cat.get_class())
is:
<class '__main__.Dog'>
<class '__main__.Cat'>
I want to DRY up my code with a subclass. But the output of:
class BaseClass():
def get_class():
return __class__
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Cat.get_class())
is
<class '__main__.BaseClass'>
<class '__main__.BaseClass'>
How do I change the code in the second case to obtain the same output as the first case?
you are almost there :
class BaseClass:
#classmethod
def get_class(cls):
return cls
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Cat.get_class())
<class '__main__.Dog'>
<class '__main__.Cat'>
There are a few different issues here.
The logic we are implementing is simply "get the class". If you want to do this starting specifically and only from the class, then there is nothing to do, and no reason to implement anything inside the BaseClass or Dog or Cat to get that result - because you already have it.
class BaseClass:
pass
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog)
print(Cat)
__class__ is a special local variable that is used for the implementation of super(). It names the class where the method is defined, regardless of how that method was looked up, or even if it was used as a plain function:
>>> class x:
... def example(self):
... print(__class__)
...
>>> class y(x): pass
...
>>> x().example()
<class '__main__.x'>
>>> y().example()
<class '__main__.x'>
>>> x.example(42)
<class '__main__.x'>
Normally, a method that does not expect to receive an instance of the class should be decorated with either #classmethod or #staticmethod. This way, the code can still be used with either a class or an instance.
The rules are:
#classmethod - called with a class, the first argument is that class itself; called with an instance, the first argument is the instance's class. The parameters should include one at the start to receive that argument. By convention, we call that parameter cls.
#staticmethod - called with either a class or an instance, no argument is added for the call. The parameters should only list what will be explicitly passed.
No decorator - called with a class, no argument is added; called with an instance, the instance is added. This should be used only for instances, thus there should be a parameter to receive the instance argument. By convention, we call that parameter self.
Trying to use a function inside a class without either a decorator or self violates the standard expectations. It tries to treat the class as simply a namespace. This is not what they are for, even thought it sort of works.
Supposing that we want the code to work with either a class (giving us back that class) or an instance (giving us back that instance's class), the code is trivial: a #classmethod-decorated method already receives a parameter that is exactly what we want, in every case, so we simply return that. Thus:
class BaseClass:
#classmethod
def get_class(cls):
return cls
class Dog(BaseClass):
pass
class Cat(BaseClass):
pass
print(Dog.get_class())
print(Dog().get_class())
print(Cat.get_class())
print(Cat().get_class())

calling Python static methods objects [duplicate]

This question already has answers here:
How can I use a static method as a default parameter for the strategy design pattern?
(1 answer)
Python decorator as a staticmethod
(4 answers)
Closed 8 years ago.
I hoped this would work:
class A(object):
#classmethod
def do_it(cls, spam, eggs):
if spam in A.ways_to_do_it:
A.ways_to_do_it[spam](eggs)
super(A, cls).do_it(spam, eggs)
#staticmethod
def do_it_somehow(eggs):
...
#staticmethod
def do_it_another_way(eggs):
...
ways_to_do_it = {
'somehow': do_it_somehow,
'another_way': do_it_another_way,
}
But it raises TypeError: 'staticmethod' object is not callable. I wanted to inspect staticmethod to find out something, but it's a built in. I hope that it's clear what I want to achieve here.
Do you have any ideas how to do it nicely? I know that making these #staticmethods global would solve the problem, but that would be a mess in my module.
P. S. do_it_somehow and do_it_another_way will be called from A.do_it only.
Python has a concept of descriptor objects, which are objects having at least the __get__ method. These objects behave differently when retrieved from a class, or an instance, as attributes (their __get__ method is called.)
The #staticmethod decorator transforms the subsequent function declaration in a descriptor that has the static method behavior - but said behavior will only be available when retrieving the object as a class attribute. The code above makes a direct reference to the object as it is, instead.
Since it is you also have other (class) methods for your dictionary to work, you'd better
retrieve yoiur desired methods after class creation, so that each method is retrieved via descriptor protocol:
class A(object):
#classmethod
def do_it(cls, spam, eggs):
if spam in A.ways_to_do_it:
A.ways_to_do_it[spam](eggs)
super(A, cls).do_it(spam, eggs)
#staticmetod
def do_it_somehow(eggs):
...
#staticmetod
def do_it_another_way(eggs):
...
A.ways_to_do_it = {
'somehow': A.do_it_somehow,
'another_way': A.do_it_another_way,
}
You could retrieve your static method before class creation, calling do_it_another_way.__get__(object, None) - since it does not need the class reference (but needs a valid class as first parameter nonetheless). But if you want your dictionary to also point to the classmethods defined, they definitely have to be fetched after class creation: there is no way Python can create you a "bound class method" before class creation.
Creating other direct references to the class/static methods inside the class body works:
class A(object):
#staticmethod
def foo(): ...
bar = foo
because in this way, bar would also be fetched through the descriptor protocol. But since you have an indirect dictionary, you have to take care of the descriptor __get__ call yourself.
Check http://docs.python.org/2/reference/datamodel.html#implementing-descriptors for more information. (This is what the classmethod, staticmethod decorators do, since you also wanted to know).
Try it like this:
class A(object):
#classmethod
def do_it(cls, spam, eggs):
if spam in A.ways_to_do_it:
A.ways_to_do_it[spam](eggs)
super(A, cls).do_it(spam, eggs)
#staticmethod
def do_it_somehow(eggs):
...
#staticmethod
def do_it_another_way(eggs):
...
A.ways_to_do_it = {
'somehow': A.do_it_somehow,
'another_way': A.do_it_another_way,
}
It gets tricky to reference a class before you've completed construction of the class, so it's simplest to add stuff to it right after the end of the class definition.

Difference between #classmethod and a method in python [duplicate]

This question already has answers here:
What's an example use case for a Python classmethod?
(7 answers)
Closed 9 years ago.
What is the difference between #classmethod and a 'classic' method in python,
When should I use the #classmethod and when should I use a 'classic' method in python.
Is the classmethod must be an method who is referred to the class (I mean it's only a method who handle the class) ?
And I know what is the difference between a #staticmethod and classic method
Thx
Let's assume you have a class Car which represents the Car entity within your system.
A classmethod is a method that works for the class Car not on one of any of Car's instances. The first parameter to a function decorated with #classmethod, usually called cls, is therefore the class itself. Example:
class Car(object):
colour = 'red'
#classmethod
def blue_cars(cls):
# cls is the Car class
# return all blue cars by looping over cls instances
A function acts on a particular instance of the class; the first parameter usually called self is the instance itself:
def get_colour(self):
return self.colour
To sum up:
use classmethod to implement methods that work on a whole class (and not on particular class instances):
Car.blue_cars()
use instance methods to implement methods that work on a particular instance:
my_car = Car(colour='red')
my_car.get_colour() # should return 'red'
If you define a method inside a class, it is handled in a special way: access to it wraps it in a special object which modifies the calling arguments in order to include self, a reference to the referred object:
class A(object):
def f(self):
pass
a = A()
a.f()
This call to a.f actually asks f (via the descriptor protocol) for an object to really return. This object is then called without arguments and deflects the call to the real f, adding a in front.
So what a.f() really does is calling the original f function with (a) as arguments.
In order to prevent this, we can wrap the function
with a #staticmethod decorator,
with a #classmethod decorator,
with one of other, similiar working, self-made decorators.
#staticmethod turns it into an object which, when asked, changes the argument-passing behaviour so that it matches the intentions about calling the original f:
class A(object):
def method(self):
pass
#staticmethod
def stmethod():
pass
#classmethod
def clmethod(cls):
pass
a = A()
a.method() # the "function inside" gets told about a
A.method() # doesn't work because there is no reference to the needed object
a.clmethod() # the "function inside" gets told about a's class, A
A.clmethod() # works as well, because we only need the classgets told about a's class, A
a.stmethod() # the "function inside" gets told nothing about anything
A.stmethod() # works as well
So #classmethod and #staticmethod have in common that they "don't care about" the concrete object they were called with; the difference is that #staticmethod doesn't want to know anything at all about it, while #classmethod wants to know its class.
So the latter gets the class object the used object is an instance of. Just replace self with cls in this case.
Now, when to use what?
Well, that is easy to handle:
If you have an access to self, you clearly need an instance method.
If you don't access self, but want to know about its class, use #classmethod. This may for example be the case with factory methods. datetime.datetime.now() is such an example: you can call it via its class or via an instance, but it creates a new instance with completely different data. I even used them once for automatically generating subclasses of a given class.
If you need neither self nor cls, you use #staticmethod. This can as well be used for factory methods, if they don't need to care about subclassing.
#classmethod takes the class as first argument while function takes instance of the class
>>> class Test(object):
... def func(self):
... print self
... #classmethod
... def meth(self):
... print self
>>> t = Test()
>>> t.func()
<__main__.Test object at 0x00000000027238D0>
>>> t.meth()
<class '__main__.Test'>
I've used self argument in meth intentionally so it would be very close in syntax to the func. But usually you'd better use cls as argument:
... #classmethod
... def meth(cls):
... print cls

Is there a way apply a decorator to a Python method that needs informations about the class?

When you decorate a method, it is not bound yet to the class, and therefor doesn't have the im_class attribute yet. I looking for a way to get the information about the class inside the decorator. I tried this:
import types
def decorator(method):
def set_signal(self, name, value):
print name
if name == 'im_class':
print "I got the class"
method.__setattr__ = types.MethodType(set_signal, method)
return method
class Test(object):
#decorator
def bar(self, foo):
print foo
But it doesn't print anything.
I can imagine doing this:
class Test(object):
#decorator(klass=Test)
def bar(self, foo):
print foo
But if I can avoid it, it would make my day.
__setattr__ is only called on explicit object.attribute = assignments; building a class does not use attribute assignment but builds a dictionary (Test.__dict__) instead.
To access the class you have a few different options though:
Use a class decorator instead; it'll be passed the completed class after building it, you could decorate individual methods on that class by replacing them (decorated) in the class. You could use a combination of a function decorator and a class decorator to mark which methods are to be decorated:
def methoddecoratormarker(func):
func._decorate_me = True
return func
def realmethoddecorator(func):
# do something with func.
# Note: it is still an unbound function here, not a method!
return func
def classdecorator(klass):
for name, item in klass.__dict__.iteritems():
if getattr(item, '_decorate_me', False):
klass.__dict__[name] = realmethoddecorator(item)
You could use a metaclass instead of a class decorator to achieve the same, of course.
Cheat, and use sys._getframe() to retrieve the class from the calling frame:
import sys
def methoddecorator(func):
callingframe = sys._getframe(1)
classname = callingframe.f_code.co_name
Note that all you can retrieve is the name of the class; the class itself is still being built at this time. You can add items to callingframe.f_locals (a mapping) and they'll be made part of the new class object.
Access self whenever the method is called. self is a reference to the instance after all, and self.__class__ is going to be, at the very least, a sub-class of the original class the function was defined in.
My strict answer would be: It's not possible, because the class does not yet exist when the decorator is executed.
The longer answer would depend on your very exact requirements. As I wrote, you cannot access the class if it does not yet exists. One solution would be, to mark the decorated method to be "transformed" later. Then use a metaclass or class decorator to apply your modifications after the class has been created.
Another option involves some magic. Look for the implementation of the implements method in zope.interfaces. It has some access to the information about the class which is just been parsed. Don't know if it will be enough for your use case.
You might want to take a look at descriptors. They let you implement a __get__ that is used when an attribute is accessed, and can return different things depending on the object and its type.
Use method decorators to add some marker attributes to the interesting methods, and use a metaclass which iterates over the methods, finds the marker attributes, and does the logic. The metaclass code is run when the class is created, so it has a reference to the newly created class.
class MyMeta(object):
def __new__(...):
...
cls = ...
... iterate over dir(cls), find methods having .is_decorated, act on them
return cls
def decorator(f):
f.is_decorated = True
return f
class MyBase(object):
__metaclass__ = MyMeta
class MyClass(MyBase):
#decorator
def bar(self, foo):
print foo
If you worry about that the programmer of MyClass forgets to use MyBase, you can forcibly set the metaclass in decorator, by exampining the globals dicitionary of the caller stack frame (sys._getframe()).

Python - Multiple inheritance: does a keyword exist to execute the method on all ancestors? [duplicate]

This question already has answers here:
Python - calling ancestor methods when multiple inheritance is involved
(2 answers)
Closed 8 years ago.
Consider:
class X:
def some_method(self):
print("X.some_method called")
class Y:
def some_method(self):
print("Y.some_method called")
class Foo(X,Y):
def some_method(self):
super().some_method()
# plus some Foo-specific work to be done here
foo_instance = Foo()
foo_instance.some_method()
Output:
X.some_method called
Switching the class declaration of Foo to instead be:
class Foo(Y,X):
Alters the output to:
Y.some_method called
If I want both ancestor methods to be called I could alter Foo's implementation as:
def some_method(self):
X().some_method()
Y().some_method()
# plus some Foo-specific work to be done here
This leads to my question. Is there any uber secret way to cause Python to invoke the method on all ancestors without me doing so explicitly like the code, such as (I'm making up the all_ancestors keyword here - does such a thing actually exist?):
def some_method(self):
all_ancestors().some_method()
# plus some Foo-specific work to be done here
with an expected output of:
X.some_method called
Y.some_method called
No, there is no secret way to do that. As I mentioned in your other question, the usual way to do this is not to call all ancestor methods from the single descendant class. Instead, each class should use super to call just one ancestor method, namely the next one up the inheritance chain. If every class in the tree does this (except the topmost base class), then all methods will get called in order. In other words, Foo should use super(), which will call X's method; and then X should also use super(), which will call Y's method.
To make this work right, it is usually best to have a single topmost class in the inheritance tree. In your example this would be a class that is the base of both X and Y. You need such a class to serve as a final stop to the sequence of super calling; this base class should not call super. If you just keep calling super everywhere, eventually it will try to call up to the base object class, and then fail because object doesn't provide the method you're trying to call.
If you can provide X & Y with a common base class or mix-in, this should work:
class ISomeMethod:
def some_method(self):
pass
class X(ISomeMethod):
def some_method(self):
print("X.some_method called")
super(X, self).some_method()
class Y(ISomeMethod):
def some_method(self):
print("Y.some_method called")
super(Y, self).some_method()
some_method should then be called in the order which you declare the base classes in Foo.

Categories

Resources