Python: nested class with static method fails - python

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.

Related

Call method of base class from derived class object python

I have two class and methods having same name .I have the object of derived class. When i call the method (foo) from derived class object it should call the base class method.
class A:
def foo(self):
print "A Foo"
class B(A):
def foo(self):
print "B Foo"
b = B()
b.foo() # "B Foo"
After doing some search i got some solution as below and not sure whether it is proper way of doing it or not
a = A()
b.__class__.__bases__[0].foo(a) # A Foo
Is there any better way of doing it.
If you're using Python 3, use super:
class A:
def talk(self):
print('Hi from A-land!')
class B(A):
def talk(self):
print('Hello from B-land!')
def pass_message(self):
super().talk()
b = B()
b.talk()
b.pass_message()
Output:
Hello from B-land!
Hi from A-land!
You can do the same thing in Python 2 if you inherit from object and specify the parameters of super:
class B(A):
def talk(self):
print('Hello from B-land!')
def pass_message(self):
super(B, self).talk()
b = B()
b.talk()
b.pass_message()
Output:
Hello from B-land!
Hi from A-land!
You can also call the method as if it were a free function:
A.talk(b)
B.talk(b) # the same as b.talk()
Output:
Hi from A-land!
Hello from B-land!
When you call the method (foo) from derived class object, it won't call the base class method, because you're overriding it. You can use another method name for your base class or derived class to solve the interference.

Access class which object is being called from within method belonging to object

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.

How the below program is possible in python

I came with a situation where the method of class A to be called from class B.
class A(object):
def __init__(self, a):
self.a = a
def abc(self):
print self.a
class B(A):
def __init__(self):
super(B, self).abc()
def method1():
a = A(2)
method1()
b = B()
Expecting Output: 2
Is it possible to call method 'abc' from class B with changing class A and should not create class A object in class B. If yes, then please let me know the solution.
The above program which I tried is giving error.
And the error I am getting is below
Traceback (most recent call last):
File "a.py", line 12, in <module>
b = B()
File "a.py", line 10, in __init__
super(B, self).abc()
File "a.py", line 6, in abc
print self.a
AttributeError: 'B' object has no attribute 'a'
Your B class __init__ method is not taking any argument, while the __init__ of class A require you to pass one (named "a"), and yet, you are not providing it. Neither in your B class or by passing it to A.
However, this would work.
class A(object):
def __init__(self, a):
self.a = a
def abc(self):
print self.a
class B(A):
def __init__(self):
self.a = 10
super(B, self).abc()
Or:
class B(A):
def __init__(self):
super(B, self).__init__(10)
inst = B()
inst.abc() # 10
Here:
class B(A):
def __init__(self):
super(B, self).abc()
The constructor of A is never called, so the initialization done in A.__init__ is missing. It fails in print self.a, because there is no a.
The super constructor should be called.
Furthermore, super(B, self).abc() is the same as self.abc().
If there was a method named abc defined in B, then self.abc() would call the method from B, whereas super(B, self).abc() would call the method from the superclass.
So, since those are the same, I would not use the ugly one. It just makes the code less readable.
With those two fixes:
class B(A):
def __init__(self):
super(B, self).__init__(1000) # whatever default value
self.abc()

How to copy a member function of another class into myclass in python?

I have a utility class from which I want to use one of the member function in another class. I don't want to inherit from that class. I just want to re-use the code from one of the member function of the other class. Kind of partial inheritance.
class HugeClass():
def interestedFunc(self,arg1):
doSomething(self.someMember1)
def OtherFunctions(self):
...
class MyClass():
def __init__(self):
self.someMember1 = "myValue"
self.interestedFunc = MagicFunc(HugeClass.interestedFunc)
c = MyClass()
print c.interestedFunc(arg)
Is there such a MagicFunc in python?
You can do what you want ie.:
class Foo(object):
def foo(self):
print self.a
class Bar(object):
foo = Foo.__dict__['foo']
b = Bar()
b.a = 1
b.foo()
But are you sure that this is good idea?
It seems like the __dict__ part from the older answer is not required in Python 3
This works fine:
class Foo:
def foo(self):
print self.a
class Bar:
foo = Foo.foo
b = Bar()
b.a = 1
b.foo()

name of the class that contains the method code

I'm trying to find the name of the class that contains method code.
In the example underneath I use self.__class__.__name__, but of course this returns the name of the class of which self is an instance and not class that contains the test() method code. b.test() will print 'B' while I would like to get 'A'.
I looked into the inspect module documentation but did not find anything directly useful.
class A:
def __init__(self):
pass
def test(self):
print self.__class__.__name__
class B(A):
def __init__(self):
A.__init__(self)
a = A()
b = B()
a.test()
b.test()
In Python 3.x, you can simply use __class__.__name__. The __class__ name is mildly magic, and not the same thing as the __class__ attribute of self.
In Python 2.x, there is no good way to get at that information. You can use stack inspection to get the code object, then walk the class hierarchy looking for the right method, but it's slow and tedious and will probably break when you don't want it to. You can also use a metaclass or a class decorator to post-process the class in some way, but both of those are rather intrusive approaches. And you can do something really ugly, like accessing self.__nonexistant_attribute, catching the AttributeError and extracting the class name from the mangled name. None of those approaches are really worth it if you just want to avoid typing the name twice; at least forgetting to update the name can be made a little more obvious by doing something like:
class C:
...
def report_name(self):
print C.__name__
inspect.getmro gives you a tuple of the classes where the method might come from, in order. As soon as you find one of them that has the method's name in its dict, you're done:
for c in inspect.getmro(self.__class__):
if 'test' in vars(c): break
return c.__name__
Use __dict__ of class object itself:
class A(object):
def foo(self):
pass
class B(A):
pass
def find_decl_class(cls, method):
if method in cls.__dict__:
return cls
for b in cls.__bases__:
decl = find_decl_class(b, method)
if decl:
return decl
print 'foo' in A.__dict__
print 'foo' in B.__dict__
print find_decl_class(B, 'foo').__name__
Will print True, False, A
You can use (abuse?) private name mangling to accomplish this effect. If you look up an attribute on self that starts with __ from inside a method, python changes the name from __attribute to _classThisMethodWasDefinedIn__attribute.
Just somehow stash the classname you want in mangled-form where the method can see it. As an example, we can define a __new__ method on the base class that does it:
def mangle(cls, attrname):
if not attrname.startswith('__'):
raise ValueError('attrname must start with __')
return '_%s%s' % (cls.__name__, attrname)
class A(object):
def __new__(cls, *args, **kwargs):
obj = object.__new__(cls)
for c in cls.mro():
setattr(obj, mangle(c, '__defn_classname'), c.__name__)
return obj
def __init__(self):
pass
def test(self):
print self.__defn_classname
class B(A):
def __init__(self):
A.__init__(self)
a = A()
b = B()
a.test()
b.test()
which prints:
A
A
You can do
>>> class A(object):
... def __init__(self):
... pass
... def test(self):
... for b in self.__class__.__bases__:
... if hasattr(b, 'test'):
... return b.__name__
... return self.__class__.__name__
...
>>> class B(A):
... def __init__(self):
... A.__init__(self)
...
>>> B().test()
'A'
>>> A().test()
'A'
>>>
Keep in mind that you could simplify it by using __class__.__base__, but if you use multiple inheritance, this version will work better.
It simply checks first on its baseclasses for test. It's not the prettiest, but it works.

Categories