I have one weird problem. I have following code:
class A:
def f():
return __class__()
class B(A):
pass
a = A.f()
b = B.f()
print(a, b)
And output is something like this:
<__main__.A object at 0x01AF2630> <__main__.A object at 0x01B09B70>
So how can I get B instead of second A?
The magic __class__ closure is set for the method context and only really meant for use by super().
For methods you'd want to use self.__class__ instead:
return self.__class__()
or better still, use type(self):
return type(self)()
If you want to be able to call the method on a class, then use the classmethod decorator to be handed a reference to the class object, rather than remain unbound:
#classmethod
def f(cls):
return cls()
classmethods are always bound to the class they are called on, so for A.f() that'd be A, for B.f() you get handed in B.
Related
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)
Is it possible for a class to call a method of another class through super() if they are both parents of the same class?
class A:
def a(self, x):
return x * 2
class B:
def b(self, x):
tmp = super().a(x) # <---
return tmp + 2
class C(A, B):
def c(self):
return super().b(20)
print(C().c())
Result:
AttributeError: 'super' object has no attribute 'a'
I thought this would work because C.mro() is [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>] (so A is in it) and it's the callee's MRO that's supposed to be defining.
Yes, but not quite like this.
A class's MRO is a total order over all ancestors of a class, including ancestors with no superclass relation between them. A and B aren't treated equally; A comes first in C's MRO (required because A was listed as a base class before B in the class statement), so the super lookup will start after B in C's MRO and skip past A entirely.
For your b method's super lookup to work, C would have had to be created as class C(B, A): .... Depending on your goal, you might instead want to just replace all those super().whatever calls with self.whatever, if you don't actually want the override-skipping behavior of super. If you do want override-skipping, but you want it in a way where A and B are treated symmetrically, you may have to build your own mechanism for that.
I believe you can just use tmp = self.a(x) and it should work as expected. Using super() is for accessing base classes. Here you just need an instance variable.
It's difficult to imagine a situation where this is genuinely something you would want to do. Such a method can only be called on objects which are instances of both A and B. #user2357112 has given the strictly correct answer to this question, but as pointed out in a comment, the solution using super() is not good design. So I will give an answer in case this isn't an abstract language-lawyer puzzler, and you (or others with the same question) are writing real code.
If C is the only class which will extend both A and B, then the simplest thing you can do is write the b method in class C.
Otherwise, if multiple classes might extend both A and B, then you can declare a "base" class for all such extensions, put the b method there, and make other classes inherit from that instead of A and B separately:
class A:
def a(self, x):
return x * 2
class B:
pass
class A_and_B(A, B):
def b(self, x):
tmp = self.a(x)
return tmp + 2
class C(A_and_B):
def c(self):
return self.b(20)
This way, instances of B which are not instances of A won't have the b method, which is desirable because the method can't be called on non-instances of A anyway.
The code above calls whichever implementation of a the object has, which could be overridden by a subclass. If you absolutely must call the A class's implementation of a, not some overridden version of it, then you can invoke A.a directly:
tmp = A.a(self, x)
This is still bad design, but not quite as bad as hacking super() to call a method on a class which is not actually a superclass.
If we override parent class's method, we can use super() to avoid mention of parent class's name - that's clear.
But what about case, when we just use in subclass some function defined in parent class? What is preferable way: to use super().parent_method() or self.parent_method()? Or there's no difference?
class A:
def test1(self):
pass
def test_a(self):
pass
class B(A):
def test1(self):
super().test1() # That's clear.
def test_b(self):
# Which option is better, when I want to use parent's func here?
# 1) super().test_a()
# 2) self.test_a()
pass
Usually you will want to use self.test_a() to call an inherited method. However, in some rare situations you might want to use super().test_a() even though it seems to do the same thing. They're not equivalent, even though they have the same behavior in your example.
To explore the differences, lets make two versions of your B class, one with each kind of call, then make two C classes that further extend the B classes and override test_a:
class A(object):
def test_a(self):
return "A"
class B1(A):
def test_b(self):
return self.test_a() + "B"
class B2(A):
def test_b(self):
return super().test_a() + "B"
class C1(B1):
def test_a(self):
return "C"
class C2(B2):
def test_a(self):
return "C"
When you call the test_b() method on C1 and C2 instances you'll get different results, even though B1 and B2 behave the same:
>>> B1().test_b()
'AB'
>>> B2().test_b()
'AB'
>>> C1().test_b()
'CB'
>>> C2().test_b()
'AB'
This is because the super() call in B2.test_b tells Python that you want to skip the version of test_a in any more derived class and always call an implementation from a parent class. (Actually, I suppose it could be a sibling class in a multiple inheritance situation, but that's getting even more obscure.)
Like I said at the top, you usually want to allow a more-derived class like the Cs to override the behavior of the inherited methods you're calling in your less-derived class. That means that most of the time using self.whatever is the way to go. You only need to use super when you're doing something fancy.
Since B is an A, it has a member test_a. So you call it as
self.test_a()
B does not overwrite A.test_a so there is no need to use super() to call it.
Since B overwrites A.test1, you must explicitly name the method you want to call.
self.test1()
will call B.test1, while
super().test1()
will call A.test1.
Firstly both the ways super().test_a() and self.test_a() will result in execution of method test_a().
Since Class B does not override or overwrite test_a() I think use of self.test_a() will be much efficient as self is a mere reference to the current object which is there in memory.
As per documentation, super() results in creation of proxy object which contains other methods also. Owing to this reason I feel self will be the correct approach in your case.
If we override parent class's method, we can use super() to avoid
mention of parent class's name - that's clear.
actually super() is not syntactic sugar, its purpose is to invoke parent implementation of a certain method.
You have to use super() when you want to override a parent method, you don't have to use super() when instead you want to overwrite a method. The difference is that in the first case you want to add extra behavior (aka code execution) before or after the original implementation, in the second you want a completely different implementation.
You can't use self.method_name() in an override, the result will be a recursion error! (RuntimeError: maximum recursion depth exceeded)
Example:
class A:
def m(self):
print('A.m implementation')
class B(A):
def m(self):
super().m()
print('B.m implementation')
class C(A):
def m(self):
print('C.m implementation')
class D(A):
def m(self):
self.m()
a = A()
a.m()
b = B()
b.m()
c = C()
c.m()
d = D()
d.m()
Given a base class A, with a method m, B extends A by overriding m, C extends A by overwriting m, and D generates an error!
EDIT:
I just realized that you actually have 2 different methods (test_a and test_b). My answer is still valid, but regarding your specific scenario:
you should use self.test_a() unless you override/overwrite that method in your class B and you want to execute the original implementation... so we can say that calling super().test_a() or self.test_a() it's the same given that you'll never override/overwrite the original test_a() in your subclasses... however is a nonsense to use super() if not for an override/overwrite
Assume you define a class, which has a method which does some complicated processing:
class A(object):
def my_method(self):
# Some complicated processing is done here
return self
And now you want to use that method on some object from another class entirely. Like, you want to do A.my_method(7).
This is what you'd get: TypeError: unbound method my_method() must be called with A instance as first argument (got int instance instead).
Now, is there any possibility to hack things so you could call that method on 7? I'd want to avoid moving the function or rewriting it. (Note that the method's logic does depend on self.)
One note: I know that some people will want to say, "You're doing it wrong! You're abusing Python! You shouldn't do it!" So yes, I know, this is a terrible terrible thing I want to do. I'm asking if someone knows how to do it, not how to preach to me that I shouldn't do it.
Of course I wouldn't recommend doing this in real code, but yes, sure, you can reach inside of classes and use its methods as functions:
class A(object):
def my_method(self):
# Some complicated processing is done here
return 'Hi'
print(A.__dict__['my_method'](7))
# Hi
You can't. The restriction has actually been lifted in Python 3000, but I presume you are not using that.
However, why can't you do something like:
def method_implementation(self, x,y):
# do whatever
class A():
def method(self, x, y):
return method_implementation(self, x, y)
If you are really in the mood for python abuse, write a descriptor class that implements the behavior. Something like
class Hack:
def __init__(self, fn):
self.fn = fn
def __get__(self, obj, cls):
if obj is None: # called staticly
return self.fn
else:
def inner(*args, **kwargs):
return self.fn(obj, *args, **kwargs)
return inner
Note that this is completely untested, will probably break some corner cases, and is all around evil.
def some_method(self):
# Some complicated processing is done here
return self
class A(object):
my_method = some_method
a = A()
print some_method
print a.my_method
print A.my_method
print A.my_method.im_func
print A.__dict__['my_method']
prints:
<function some_method at 0x719f0>
<bound method A.some_method of <__main__.A object at 0x757b0>>
<unbound method A.some_method>
<function some_method at 0x719f0>
<function some_method at 0x719f0>
It sounds like you're looking up a method on a class and getting an unbound method. An unbound method expects a object of the appropriate type as the first argument.
If you want to apply the function as a function, you've got to get a handle to the function version of it instead.
You could just put that method into a superclass of the two objects that need to call it, couldn't you? If its so critical that you can't copy it, nor can you change it to not use self, thats the only other option I can see.
>>> class A():
... me = 'i am A'
...
>>> class B():
... me = 'i am B'
...
>>> def get_name(self):
... print self.me
...
>>> A.name = get_name
>>> a=A()
>>> a.name()
i am A
>>>
>>> B.name = get_name
>>> b=B()
>>> b.name()
i am B
>>>
Why cant you do this
class A(object):
def my_method(self,arg=None):
if (arg!=None):
#Do Some Complicated Processing with both objects and return something
else:
# Some complicated processing is done here
return self
In Python functions are not required to be enclosed in classes. It sounds like what you need is utility function, so just define it as such:
def my_function(object):
# Some complicated processing is done here
return object
my_function(7)
my_function("Seven")
As long as your processing is using methods and attribute available on all objects that you pass to my_function through the magic of duck typing everything will work fine.
That's what's called a staticmethod:
class A(object):
#staticmethod
def my_method(a, b, c):
return a, b, c
However in staticmethods, you do not get a reference to self.
If you'd like a reference to the class not the instance (instance implies reference to self), you can use a classmethod:
class A(object):
classvar = "var"
#classmethod
def my_method(cls, a, b, c):
print cls.classvar
return a, b, c
But you'll only get access to class variables, not to instance variables (those typically created/defined inside the __init__ constructor).
If that's not good enough, then you will need to somehow pass a "bound" method or pass "self" into the method like so:
class A(object):
def my_method(self):
# use self and manipulate the object
inst = A()
A.my_method(inst)
As some people have already said, it's not a bad idea to just inherit one class from the other:
class A(object):
... methods ...
class B(A):
def my_method(self):
... use self
newA = B()
Based on this answer, of how __new__ and __init__ are supposed to work in Python,
I wrote this code to dynamically define and create a new class and object.
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = C()
return self
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A()
a.foo()
a.bar()
Basically, because the __new__ of A returns a dynamically created C that inherits A and B, it should have an attribute bar.
Why does C not have a bar attribute?
Resolve the infinite recursion:
class A(object):
def __new__(cls):
class C(cls, B):
pass
self = object.__new__(C)
return self
(Thanks to balpha for pointing out the actual question.)
Since there is no actual question in the question, I am going to take it literally:
Whats wrong doing it dynamically?
Well, it is practically unreadable, extremely opaque and non-obvious to the user of your code (that includes you in a month :P).
From my experience (quite limited, I must admit, unfortunately I don't have 20 years of programming under the belt), a need for such solutions indicates, that the class structure is not well defined, - means, there's almost always a better, more readable and less arcane way to do such things.
For example, if you really want to define base classes on the fly, you are better off using a factory function, that will return appropriate classes according to your needs.
Another take on the question:
Whats wrong doing it dynamically?
In your current implementation, it gives me a "maximum recursion depth exceeded" error. That happens, because A.__new__ calls itself from within itself indefinitely (since it inherits from itself and from B).
10: Inside A.__new__, "cls" is set to <class '.A'>. Inside the constructor you define a class C, which inherits from cls (which is actually A) and another class B. Upon instantiating C, its __new__ is called. Since it doesn't define its own __new__, its base class' __new__ is called. The base class just happens to be A.
20: GOTO 10
If your question is "How can I accomplish this" – this works:
class A(object):
#classmethod
def get_with_B(cls):
class C(B, cls):
pass
return C()
def foo(self):
print 'foo'
class B(object):
def bar(self):
print 'bar'
a = A.get_with_B()
a.foo()
a.bar()
If your question is "Why doesn't it work" – that's because you run into an infinite recursion when you call C(), which leads to A.__new__ being called, which again calls C() etc.