What's the difference between a #classmethod and invoking a class? - python

Let's say I have a class with two methods, one will be decorated by a classmethod and the other one will not.
class MyClass():
def __init__(self):
self.my_string = 'Hello'
def test1(self):
return self.my_string
#classmethod
def test2(cls):
return cls().my_string
What is the difference between these two calls:
MyClass().test1()
MyClass.test2()
I checked the elapsed time of them and they differ a lot, so it got to be different somehow, but I can't understand why. Is there a preferable way of doing it? Thank you in advance.

They are very different.
MyClass().test1() invokes the instance method test1 with the instance MyClass() as its implicit first argument (bound to the parameter self).
MyClass.test2() invokes the class method test2 with the class MyClass as its implicit first argument (bound to the parameter cls).
You didn't ask about the more interesting MyClass().test2(), which still invokes the class method test2 with the class MyClass (the type of the instance) as its implicit first argument.
You also didn't ask about MyClass.test1(), which would raise a TypeError because MyClass.test1 resolves to an ordinary function, and no argument would be implicitly bound to the required parameter self.
This particular class method is strange. A class method should either be independent of any particular instance of the class, or create and return an instance. Creating an instance only for use in the class method doesn't really make sense.

Related

Getting private attribute in parent class using super(), outside of a method

I have a class with a private constant _BAR = object().
In a child class, outside of a method (no access to self), I want to refer to _BAR.
Here is a contrived example:
class Foo:
_BAR = object()
def __init__(self, bar: object = _BAR):
...
class DFoo(Foo):
"""Child class where I want to access private class variable from parent."""
def __init__(self, baz: object = super()._BAR):
super().__init__(baz)
Unfortunately, this doesn't work. One gets an error: RuntimeError: super(): no arguments
Is there a way to use super outside of a method to get a parent class attribute?
The workaround is to use Foo._BAR, I am wondering though if one can use super to solve this problem.
Inside of DFoo, you cannot refer to Foo._BAR without referring to Foo. Python variables are searched in the local, enclosing, global and built-in scopes (and in this order, it is the so called LEGB rule) and _BAR is not present in any of them.
Let's ignore an explicit Foo._BAR.
Further, it gets inherited: DFoo._BAR will be looked up first in DFoo, and when not found, in Foo.
What other means are there to get the Foo reference? Foo is a base class of DFoo. Can we use this relationship? Yes and no. Yes at execution time and no at definition time.
The problem is when the DFoo is being defined, it does not exist yet. We have no start point to start following the inheritance chain. This rules out an indirect reference (DFoo -> Foo) in a def method(self, ....): line and in a class attribute _DBAR = _BAR.
It is possible to work around this limitation using a class decorator. Define the class and then modify it:
def deco(cls):
cls._BAR = cls.__mro__[1]._BAR * 2 # __mro__[0] is the class itself
return cls
class Foo:
_BAR = 10
#deco
class DFoo(Foo):
pass
print(Foo._BAR, DFoo._BAR) # 10 20
Similar effect can be achieved with a metaclass.
The last option to get a reference to Foo is at execution time. We have the object self, its type is DFoo, and its parent type is Foo and there exists the _BAR. The well known super() is a shortcut to get the parent.
I have assumed only one base class for simplicity. If there were several base classes, super() returns only one of them. The example class decorator does the same. To understand how several bases are sorted to a sequence, see how the MRO works (Method Resolution Order).
My final thought is that I could not think up a use-case where such access as in the question would be required.
Short answer: you can't !
I'm not going into much details about super class itself here. (I've written a pure Python implementation in this gist if you like to read.)
But now let's see how we can call super:
1- Without arguments:
From PEP 3135:
This PEP proposes syntactic sugar for use of the super type to
automatically construct instances of the super type binding to the
class that a method was defined in, and the instance (or class object
for classmethods) that the method is currently acting upon.
The new syntax:
super()
is equivalent to:
super(__class__, <firstarg>)
...and <firstarg> is the first parameter of the method
So this is not an option because you don't have access to the "instance".
(Body of the function/methods is not executed unless it gets called, so no problem if DFoo doesn't exist yet inside the method definition)
2- super(type, instance)
From documentation:
The zero argument form only works inside a class definition, as the
compiler fills in the necessary details to correctly retrieve the
class being defined, as well as accessing the current instance for
ordinary methods.
What were those necessary details mentioned above? A "type" and A "instance":
We can't pass neither "instance" nor "type" which is DFoo here. The first one is because it's not inside the method so we don't have access to instance(self). Second one is DFoo itself. By the time the body of the DFoo class is being executed there is no reference to DFoo, it doesn't exist yet. The body of the class is executed inside a namespace which is a dictionary. After that a new instance of type type which is here named DFoo is created using that populated dictionary and added to the global namespaces. That's what class keyword roughly does in its simple form.
3- super(type, type):
If the second argument is a type, issubclass(type2, type) must be
true
Same reason mentioned in above about accessing the DFoo.
4- super(type):
If the second argument is omitted, the super object returned is
unbound.
If you have an unbound super object you can't do lookup(unless for the super object's attributes itself). Remember super() object is a descriptor. You can turn an unbound object to a bound object by calling __get__ and passing the instance:
class A:
a = 1
class B(A):
pass
class C(B):
sup = super(B)
try:
sup.a
except AttributeError as e:
print(e) # 'super' object has no attribute 'a'
obj = C()
print(obj.sup.a) # 1
obj.sup automatically calls the __get__.
And again same reason about accessing DFoo type mentioned above, nothing changed. Just added for records. These are the ways how we can call super.

Differences in these subclass definitions?

Could someone explain what is the difference between the following class definitions derived from BaseClass and in what cases it would matter how they are defined:
class BaseClass(object):
def __init__(self):
# ...
def as_dict(self):
# ...
class SomeClass(BaseClass):
def as_dict(self):
# Does this somehow change the method compared to 'AnotherClass.as_dict()' below
return super(SomeClass, self).as_dict()
class AnotherClass(BaseClass): pass
SomeOtherClass = BaseClass
Since you add an as_dict method to SomeClass that contains a single super call, there's no difference in the end behavior for that class. There's a difference in the fact that, overall, you've added a couple more function calls that are not necessary.
AnotherClass behaves just like SomeClass since SomeClass doesn't do anything different in as_dict. It inherits the methods of BaseClass as usual.
SomeOtherClass is simply another name for BaseClass, you aren't creating a subclassing relationship there, just attaching another name by which you can refer to that class.
This is using BaseClass with a different name.
class AnotherClass(BaseClass): pass
This is using BaseClass but modifying the method "as_dict". Inside the as_dict method, you can do anything (ie.modify the parameters sent to this method) then run the usual function of the as_dict method with super(SomeClass, self).as_dict()
class SomeClass(BaseClass):
def as_dict(self):
# Does this somehow change the method compared to 'AnotherClass.as_dict()' below
return super(SomeClass, self).as_dict()
This is simply assigning BaseClass to SomeOtherClass, which means they can use BaseClass through both keywords.
SomeOtherClass = BaseClass

When should one use a class method over instance method? [duplicate]

While integrating a Django app I have not used before, I found two different ways to define functions inside the class. The author seems to use them both distinctively and intentionally. The first one is the one that I myself use a lot:
class Dummy(object):
def some_function(self, *args, **kwargs):
# do something here
# self is the class instance
The other one is the one I never use, mostly because I do not understand when and what to use it for:
class Dummy(object):
#classmethod
def some_function(cls, *args, **kwargs):
# do something here
# cls refers to what?
The classmethod decorator in the python documentation says:
A class method receives the class as the implicit first argument, just
like an instance method receives the instance.
So I guess cls refers to Dummy itself (the class, not the instance). I do not exactly understand why this exists, because I could always do this:
type(self).do_something_with_the_class
Is this just for the sake of clarity, or did I miss the most important part: spooky and fascinating things that couldn't be done without it?
Your guess is correct - you understand how classmethods work.
The why is that these methods can be called both on an instance OR on the class (in both cases, the class object will be passed as the first argument):
class Dummy(object):
#classmethod
def some_function(cls,*args,**kwargs):
print cls
#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()
On the use of these on instances: There are at least two main uses for calling a classmethod on an instance:
self.some_function() will call the version of some_function on the actual type of self, rather than the class in which that call happens to appear (and won't need attention if the class is renamed); and
In cases where some_function is necessary to implement some protocol, but is useful to call on the class object alone.
The difference with staticmethod: There is another way of defining methods that don't access instance data, called staticmethod. That creates a method which does not receive an implicit first argument at all; accordingly it won't be passed any information about the instance or class on which it was called.
In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)
In [7]: Foo.some_static(1)
Out[7]: 2
In [8]: Foo().some_static(1)
Out[8]: 2
In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)
In [10]: Bar.some_static(1)
Out[10]: 2
In [11]: Bar().some_static(1)
Out[11]: 2
The main use I've found for it is to adapt an existing function (which doesn't expect to receive a self) to be a method on a class (or object).
One of the most common uses of classmethod in Python is factories, which are one of the most efficient methods to build an object. Because classmethods, like staticmethods, do not need the construction of a class instance. (But then if we use staticmethod, we would have to hardcode the instance class name in the function)
This blog does a great job of explaining it:
https://iscinumpy.gitlab.io/post/factory-classmethods-in-python/
If you add decorator #classmethod, That means you are going to make that method as static method of java or C++. ( static method is a general term I guess ;) )
Python also has #staticmethod. and difference between classmethod and staticmethod is whether you can
access to class or static variable using argument or classname itself.
class TestMethod(object):
cls_var = 1
#classmethod
def class_method(cls):
cls.cls_var += 1
print cls.cls_var
#staticmethod
def static_method():
TestMethod.cls_var += 1
print TestMethod.cls_var
#call each method from class itself.
TestMethod.class_method()
TestMethod.static_method()
#construct instances
testMethodInst1 = TestMethod()
testMethodInst2 = TestMethod()
#call each method from instances
testMethodInst1.class_method()
testMethodInst2.static_method()
all those classes increase cls.cls_var by 1 and print it.
And every classes using same name on same scope or instances constructed with these class is going to share those methods.
There's only one TestMethod.cls_var
and also there's only one TestMethod.class_method() , TestMethod.static_method()
And important question. why these method would be needed.
classmethod or staticmethod is useful when you make that class as a factory
or when you have to initialize your class only once. like open file once, and using feed method to read the file line by line.

Can Python Staticmethod Call Another Local Method?

In Python, within a class, can a staticmethod call on another local function/method defined within the same class?
I tried the following code and obtained an error message saying foo1() is not defined.
class trialOne(object):
#staticmethod
def foo1():
a = 3.1
return a
#staticmethod
def foo():
a = foo1()
return a
obj = trialOne()
b = obj.foo()
class Tester:
def local(self):
print "I'm a local!"
#staticmethod
def another_stat():
print "I'm a static!"
#staticmethod
def stat(inst):
inst.local()
Tester.another_stat()
t = Tester()
Tester.stat(t)
# Out:
# I'm a local!
# I'm a static!
Yes, you can! By definition, instance methods need an instance to associate themselves with, but as long as you have that instance, you can call local methods just as you normally would.
To go into this in a little more depth, there's nothing special about the word self. That's a variable just like any other. Any instance method of a class MUST take in an instance of that class as its first parameter, and it's convention to call that parameter self, but you could just as easily use any other name.
If it helps you understand the distinction, these two statements are semantically equivalent:
t.local()
Tester.local(t)
The first is just syntactic sugar for the second. The second is using the class name to reference a method of the Tester class, then passes in the instance as the first parameter. The first simply pretends that local is a field of t and calls it, but that call is transformed into Tester.local(t) by the Python interpreter.
Thus, calling a static method is the same syntax as Tester.local(t), except the first parameter does not have to be an instance of that class.
So classmethods and staticmethods are called in the same way, but the difference is that a class method "knows" what class it's coming from. The first parameter of a class method is always a variable that contains the class that it's being invoked from. That way if the method is inherited, it knows which method it's coming from, where a staticmethod would not know. In your comment, you said this:
#classmethod
def stat(cls):
cls.another_stat()
In this example, cls is a variable that contains the class that the method is being called from, not an instance of the class that it is being called from. That is why you can call static methods with cls - because it is equivalent to Tester

Python: Class internal definition call

In my class FooBar I want to let one definition call another one. But this leads to an error that I do not understand:
class FooBar:
def __init__(self):
pass
def foo(self):
pass
def bar(self):
return foo()
Most likely my problem has a trivial answer like calling FooBar.foo(). So thank you for giving me a hint.
According to the definition of the class, foo() is an instance method of FooBar class. To access instance methods of the same class, you need to use instances of that class. When you are inside an instance method, the first argument passed to it is the instance, generally the first argument is named self.
So in your case, you should call the instance method using self. Example:
self.foo()

Categories