Sorry, may be this is silly question, but its very confusing to me. Let's suppose we have the following classes:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self,*args, **kwargs):
return super(C, self).say(*args, **kwargs)
I am accessing parent method in child, and it prints B, but I want to access method from class A as we are getting access from class B.
I know we can add super in class B, but I don't want to modify class B. so is there any option to get method from A directly in class C?
You can by calling A.say(self) like this:
class A():
def say(self):
print("A")
class B(A):
def say(self):
print("B")
class C(B):
def say(self):
A.say(self)
B.say(self)
print("C")
Then to test it out from a terminal:
>>> a = A()
>>> a.say()
A
>>> b = B()
>>> b.say()
B
>>> c = C()
>>> c.say()
A
B
C
Note: I dropped the args and kwargs because the A and B classes didn't use those arguments. If you wanted to make say take those all the way up though simply call A.say(self, *args, **kwargs) and if A.say returns something you can return it too
Related
So basically my problem seems like this.
class A():
def func(self):
return 3
class B():
def func(self):
return 4
class AA(A):
def func(self):
return super(AA, self).func
class BB(B):
def func(self):
return super(BB, self).func
The func function is doing some work and one of the things it does is getting some attribute(or running method or whatever) from it's parent class.
Since func originally does the same logic at both cases (except that only parent class changes) I'd like to do this with decorators.
Is it possible? if so how to do it? Do I have somehow to pass parent-class as a argument?
I'll be very grateful for answers it's been bothering me for a while now.
There is no need to use super to access data attributes of a parent class.
Neither does a class need a parent in order for access to data attributes to work.
You can use a mixin to do the job:
# A and B stay the same - they still have a c attribute
class A():
c = 3
class B():
c = 4 # I've changed B to make it clear below
#Instead have a mixin which defines func()
class Mixin:
def func(self):
# func has its behaviour here
return self.c
class AA(Mixin, A):
pass
class BB(Mixin, B):
pass
a = AA()
b = BB()
print(a.func())
print(b.func())
Output:
3
4
You could do it with a single class decorator by defining a generic method inside of it that does what you want, and then adding it to the class being decorated. Here's what I mean:
def my_decorator(cls):
def call_super_func(self):
return super(type(self), self).func()
setattr(cls, 'call_super_func', call_super_func)
return cls
class A():
def func(self):
print('in A.func')
return 3
class B():
def func(self):
print('in B.func')
return 4
#my_decorator
class AA(A):
def func(self):
print('in AA.func')
return self.call_super_func()
#my_decorator
class BB(B):
def func(self):
print('in BB.func')
return self.call_super_func()
aa = AA()
aa.func()
bb = BB()
bb.func()
Output:
in AA.func
in A.func
in BB.func
in B.func
Of course you could eliminate the need to do this by just defining baseclass for A and B that has a call_super_func() method in it that they would then both inherit.
I wonder if there is a way in Python to access the class which the object which the method belongs to is being called from. For example:
class A:
def __init__(self):
self.b = B()
def foo(self):
print('A')
class B:
def bar(self):
<something here>.foo()
a = A()
a.b.bar()
Basically I would like B's method bar to invoke A's method foo. And if b was an attribute of some other class C, to invoke C's version of foo instead.
You could add a reference to the class which instantiates B:
class A:
def __init__(self):
# pass self while instantiating B
self.b = B(self)
def foo(self):
print('A')
class B:
def __init__(self, rel_obj):
self.rel_obj = rel_obj
def bar(self):
self.rel_obj.foo() # access foo() using self.rel_obj
Similarly, you could pass an object of class C to invoke C's version of foo method.
Are there any side-effects of adding grandparent to the MRO? Purpose is I would like to get grandchildren classes by using grandparent.__subclasses__()
class A(object):
def work(self):
print 'A'
class B(A):
def work(self):
print 'B'
super(B, self).work()
class C(B):
def work(self):
print 'C'
super(C, self).work()
class D(B, A):
def work(self):
print 'D'
super(D, self).work()
>>> C().work()
C
B
A
>>> D().work()
D
B
A
>>> A.__subclasses__()
[<class 'test.B'>, <class 'test.D'>]
We have come up a recursive function to work out the subclasses
def get_all_subclasses(cls):
all_subclasses = []
for subclass in cls.__subclasses__():
all_subclasses.append(subclass)
all_subclasses.extend(get_all_subclasses(subclass))
return all_subclasses
I was wandering if you have any suggestions on how I should perform the following task in python:
Suppose I have the following classes:
class A(object):
self._classes = []
def magic(self):
c.foo() for c in self._classes
class B(object):
def foo():'''some cool stuff here'''
class C(B):
def foo():'''very cool stuff'''
class D(B):
def foo():'''very cool stuff'''
What I want to do is when class A is instantiated all classes of type B - (C and D) will be insantiated in self._classes, meaning _classes is [C(),D()].
The general motivation for this, is that I want the user to easily add classes without the need to know about class that uses them. Any help will be appricated.
Voila (thanks to this answer for all_subclasses()):
# recursively get all subclasses of a given class
def all_subclasses(cls):
return cls.__subclasses__() + [g for s in cls.__subclasses__()
for g in all_subclasses(s)]
class B(object):
def foo(self): print '''some cool stuff here in B'''
class C(B):
def foo(self): print '''very cool stuff in C'''
class D(B):
def foo(self): print '''very cool stuff in D'''
class E(D):
def foo(self): print '''very cool stuff in E'''
class A(object):
def __init__(self):
self._classes = [cls() for cls in all_subclasses(B)]
def magic(self):
for c in self._classes: c.foo()
# usage:
A().magic()
Output:
very cool stuff in C
very cool stuff in D
very cool stuff in E
If you know the module in question for example modulex, you can use dir(modulex) to list all the names in the module and then for each name x you can use modulex.__dict__.get(x) to get the actual object.
Then just check if it is of type of B.
In python you can store objects like other methods in list , so first note that you need to define other class then store them in a list , also you need to using self as your foo functions argument! if you haven't subclasses you can use this :
class B(object):
def foo(self):
print 'B'
class C(B):
def foo(self):
print 'C'
class D(B):
def foo(self):
print 'D'
class A(object):
def __init__(self):
self._classes = [B(),C(),D()]
def magic(self):
for c in self._classes:
c.foo()
A().magic()
resoult:
B
C
D
What is wrong with the following code?
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): super(B).A_M()
error (Python 2.7.3):
>>> a = A()
>>> a.B.C()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "..x.py", line 36, in C
def C(): super(B).A_M()
NameError: global name 'B' is not defined
Edit:
the solution was simple as this:
class A:
def A_M(self): pass
class B:
#staticmethod
def C(): A().A_M() #use of A() instead of supper, etc.
Important Note that there is an issue with this solution. If you change the name of super class (i.e. A) then you will have to update all uses inside itself as A :)).
class A(object):
def foo(self):
print('foo')
#staticmethod
def bar():
print('bar')
class B(object):
#staticmethod
def bar(obj):
# A.foo is not staticmethod, you can't use A.foo(),
# you need an instance.
# You also can't use super here to get A,
# because B is not subclass of A.
obj.foo()
A.foo(obj) # the same as obj.foo()
# A.bar is static, you can use it without an object.
A.bar()
class B(A):
def foo(self):
# Again, B.foo shouldn't be a staticmethod, because A.foo isn't.
super(B, self).foo()
#staticmethod
def bar():
# You have to use super(type, type) if you don't have an instance.
super(B, B).bar()
a, b = A(), B()
a.B.bar(a)
b.foo()
B.bar()
See this for details on super(B, B).
You need to use a fully-qualified name. Also, in python 2.7, you need to use (object), else super(A.B) will give TypeError: must be type, not classobj
class A(object):
def A_M(self):
pass
class B(object):
#staticmethod
def C():
super(A.B).A_M()
Finally, super(A.B) is essentially object here. Did you mean for B to inherit from A? Or were you simply looking for A.A_M()?
A latecommer, to just encapsulate B in A the easy way is this:
class A:
def A_M(self):
return "hi"
class B:
#staticmethod
def C():
return A().A_M()
a = A()
print a.B().C()
Not sure this is what you need, but the question was still unsolved, so I guessed.