I'm trying to write a decorator that can be used to override a method during inheritance, but externally.
Something like:
class A:
def some_method(self):
print('does stuff')
def override(method):
# override decorator
....
def some_method_override():
print('does other stuff')
#override(method, some_method_override)
class B:
#overridden
a = A()
b = B()
a.some_method() # prints 'does stuff'
b.some_method() # prints 'does other stuff'
If anyone could share some ideas on this, that would be great!
Here is how I would go about solving the issue based on use-case;
FOR TESTS - I would look into the mock library if you are trying to dynamically override methods. Here is a resource - https://docs.python.org/3/library/unittest.mock.html
FOR SEPARATE CLASS - If it is class-wide change I would go with a child class that overrides the original method; this will make your code much more explicit
class A:
def some_method(self):
print('do_stuff_a')
class B(A):
def some_method(self):
print('do_stuff_b')
a = A()
a.some_method() # print 'do_stuff_a'
b = B()
a.some_method() # prints 'do_stuff_b'
FOR SPECIFIC SITUATION - If you only want this behavior to occur sometimes, I would use the state-observer code pattern - here is an example
class A:
def __init__(self)
self._use_method_a = True
def use_method_a(self, use_method_a):
self._use_method_a = use_method_a
def some_method(self):
if self._use_method_a:
return self._method_a()
else:
return self._method_b()
def _method_a(self):
print('do_stuff_a')
def _method_b(self):
print('do_other_stuff_b')
a = A()
a.some_method() # print 'do_stuff_a'
a.use_method_a(False)
a.some_method() # prints 'do_other_stuff_b'
As mentioned by others in the comments, I don't see any need for a decorator here. It's just a matter of class-attribute assignment.
Inheritance doesn't happen when a class is defined; methods from the parent aren't "pulled in" to the child class. Rather, it happens during attribute lookup. If B.some_method isn't defined, then the value of A.some_method is used. So to override a parent-class method, you simply provide a definition of the desired class attribute. Methods are just class attributes with values of type function.
class A:
def some_method(self):
print('does stuff')
def some_method_override(self):
print('does other stuff')
class B(A):
some_method = some_method_override
a = A()
b = B()
a.some_method() # prints 'does stuff'
b.some_method() # prints 'does other stuff'
If you did want a decorator, it would simply be something like
def override(old: str, new: Callable):
def _(cls):
setattr(cls, old, new)
return cls
return _
def some_method_override(self):
print('does other stuff')
class A:
def some_method(self):
print('does stuff')
#override('some_method', some_method_override)
class B(A):
pass
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 have the following two classes:
class A(object):
def caller(self,name):
# want to invoke call() here when name="call"
class B(A):
def call(self):
print("hello")
Given the following:
x= B()
x.caller("call") # I want to have caller() invoke call() on the name.
I don't want to check the value of name I want it to automatically invoke the the given string as a function on self.
Use __getattribute__
class A(object):
def caller(self,name):
self.__getattribute__(name)()
class B(A):
def call(self):
print("hello")
x= B()
x.caller("call")
Output
hello
can also use eval
class A(object):
def caller(self,name):
eval('self.%s()' % name)
class B(A):
def call(self):
print("hello")
x= B()
x.caller("call")
output
hello
[Finished in 0.6s]
I have been searching an answer to my question but could not hit the related answer.
Basically i am trying to call a variable from a Class A thats actually GUI to another Class B my code goes like this:
class CLASSA(wx.Frame):
def Method(self):
self.Var = anyvalue
import CLASSA
class CLASSB():
def __init__(self):
self.Var = CLASSA().Method.Var
i have tried as above but its not working out. Isn't it possible to carry out as mentioned ?
At the very least, you need to actually call CLASSA.Method first:
class CLASSB():
def __init__(self):
self.Var = CLASSA().Method().Var
in order for the Var attribute of the CLASSA object to be initialized.
You do not give enough detail to know if Method is necessary. You could, for instance, simply initialize Var in CLASSA.__init__.
# With recommended capitalization
class A(wx.Frame):
def __init__(self):
self.var = any value
class B(object):
def __init__(self):
sef.var = A().var
It's also possible that B should be a subclass of A, in which case B simply inherits var from A:
>>> class B(A):
... pass
>>> print B().var
anyvalue
I have a class that is a super-class to many other classes. I would like to know (in the __init__() of my super-class) if the subclass has overridden a specific method.
I tried to accomplish this with a class method, but the results were wrong:
class Super:
def __init__(self):
if self.method == Super.method:
print 'same'
else:
print 'different'
#classmethod
def method(cls):
pass
class Sub1(Super):
def method(self):
print 'hi'
class Sub2(Super):
pass
Super() # should be same
Sub1() # should be different
Sub2() # should be same
>>> same
>>> different
>>> different
Is there any way for a super-class to know if a sub-class has overridden a method?
It seems simplest and sufficient to do this by comparing the common subset of the dictionaries of an instance and the base class itself, e.g.:
def detect_overridden(cls, obj):
common = cls.__dict__.keys() & obj.__class__.__dict__.keys()
diff = [m for m in common if cls.__dict__[m] != obj.__class__.__dict__[m]]
print(diff)
def f1(self):
pass
class Foo:
def __init__(self):
detect_overridden(Foo, self)
def method1(self):
print("Hello foo")
method2=f1
class Bar(Foo):
def method1(self):
print("Hello bar")
method2=f1 # This is pointless but not an override
# def method2(self):
# pass
b=Bar()
f=Foo()
Runs and gives:
['method1']
[]
If you want to check for an overridden instance method in Python 3, you can do this using the type of self:
class Base:
def __init__(self):
if type(self).method == Base.method:
print('same')
else:
print('different')
def method(self):
print('Hello from Base')
class Sub1(Base):
def method(self):
print('Hello from Sub1')
class Sub2(Base):
pass
Now Base() and Sub2() should both print "same" while Sub1() prints "different". The classmethod decorator causes the first parameter to be bound to the type of self, and since the type of a subclass is by definition different to its base class, the two class methods will compare as not equal. By making the method an instance method and using the type of self, you're comparing a plain function against another plain function, and assuming functions (or unbound methods in this case if you're using Python 2) compare equal to themselves (which they do in the C Python implementation), the desired behavior will be produced.
You can use your own decorator. But this is a trick and will only work on classes where you control the implementation.
def override(method):
method.is_overridden = True
return method
class Super:
def __init__(self):
if hasattr(self.method, 'is_overridden'):
print 'different'
else:
print 'same'
#classmethod
def method(cls):
pass
class Sub1(Super):
#override
def method(self):
print 'hi'
class Sub2(Super):
pass
Super() # should be same
Sub1() # should be different
Sub2() # should be same
>>> same
>>> different
>>> same
In reply to answer https://stackoverflow.com/a/9437273/1258307, since I don't have enough credits yet to comment on it, it will not work under python 3 unless you replace im_func with __func__ and will also not work in python 3.4(and most likely onward) since functions no longer have the __func__ attribute, only bound methods.
EDIT: Here's the solution to the original question(which worked on 2.7 and 3.4, and I assume all other version in between):
class Super:
def __init__(self):
if self.method.__code__ is Super.method.__code__:
print('same')
else:
print('different')
#classmethod
def method(cls):
pass
class Sub1(Super):
def method(self):
print('hi')
class Sub2(Super):
pass
Super() # should be same
Sub1() # should be different
Sub2() # should be same
And here's the output:
same
different
same
You can compare whatever is in the class's __dict__ with the function inside the method
you can retrieve from the object -
the "detect_overriden" functionbellow does that - the trick is to pass
the "parent class" for its name, just as one does in a call to "super" -
else it is not easy to retrieve attributes from the parentclass itself
instead of those of the subclass:
# -*- coding: utf-8 -*-
from types import FunctionType
def detect_overriden(cls, obj):
res = []
for key, value in cls.__dict__.items():
if isinstance(value, classmethod):
value = getattr(cls, key).im_func
if isinstance(value, (FunctionType, classmethod)):
meth = getattr(obj, key)
if not meth.im_func is value:
res.append(key)
return res
# Test and example
class A(object):
def __init__(self):
print detect_overriden(A, self)
def a(self): pass
#classmethod
def b(self): pass
def c(self): pass
class B(A):
def a(self): pass
##classmethod
def b(self): pass
edit changed code to work fine with classmethods as well:
if it detects a classmethod on the parent class, extracts the underlying function before proceeding.
--
Another way of doing this, without having to hard code the class name, would be to follow the instance's class ( self.__class__) method resolution order (given by the __mro__ attribute) and search for duplicates of the methods and attributes defined in each class along the inheritance chain.
I'm using the following method to determine if a given bound method is overridden or originates from the parent class
class A():
def bla(self):
print("Original")
class B(A):
def bla(self):
print("Overridden")
class C(A):
pass
def isOverriddenFunc(func):
obj = func.__self__
prntM = getattr(super(type(obj), obj), func.__name__)
return func.__func__ != prntM.__func__
b = B()
c = C()
b.bla()
c.bla()
print(isOverriddenFunc(b.bla))
print(isOverriddenFunc(c.bla))
Result:
Overridden
Original
True
False
Of course, for this to work, the method must be defined in the base class.
You can also check if something is overridden from its parents, without knowing any of the classes involved using super:
class A:
def fuzz(self):
pass
class B(A):
def fuzz(self):
super().fuzz()
class C(A):
pass
>>> b = B(); c = C()
>>> b.__class__.fuzz is super(b.__class__, b).fuzz.__func__
False
>>> c.__class__.fuzz is super(c.__class__, c).fuzz.__func__
True
See this question for some more nuggets of information.
A general function:
def overrides(instance, function_name):
return getattr(instance.__class__, function_name) is not getattr(super(instance.__class__, instance), function_name).__func__
>>> overrides(b, "fuzz")
True
>>> overrides(c, "fuzz")
False
You can check to see if the function has been overridden by seeing if the function handle points to the Super class function or not. The function handler in the subclass object points either to the Super class function or to an overridden function in the Subclass. For example:
class Test:
def myfunc1(self):
pass
def myfunc2(self):
pass
class TestSub(Test):
def myfunc1(self):
print('Hello World')
>>> test = TestSub()
>>> test.myfunc1.__func__ is Test.myfunc1
False
>>> test.myfunc2.__func__ is Test.myfunc2
True
If the function handle does not point to the function in the Super class, then it has been overridden.
Not sure if this is what you're looking for but it helped me when I was looking for a similar solution.
class A:
def fuzz(self):
pass
class B(A):
def fuzz(self):
super().fuzz()
assert 'super' in B.__dict__['fuzz'].__code__.co_names
The top-trending answer and several others use some form of Sub.method == Base.method. However, this comparison can return a false negative if Sub and Base do not share the same import syntax. For example, see discussion here explaining a scenario where issubclass(Sub, Base) -> False.
This subtlety is not apparent when running many of the minimal examples here, but can show up in a more complex code base. The more reliable approach is to compare the method defined in the Sub.__bases__ entry corresponding to Base because __bases__ is guaranteed to use the same import path as Sub
import inspect
def method_overridden(cls, base, method):
"""Determine if class overriddes the implementation of specific base class method
:param type cls: Subclass inheriting (and potentially overriding) the method
:param type base: Base class where the method is inherited from
:param str method: Name of the inherited method
:return bool: Whether ``cls.method != base.method`` regardless of import
syntax used to create the two classes
:raises NameError: If ``base`` is not in the MRO of ``cls``
:raises AttributeError: If ``base.method`` is undefined
"""
# Figure out which base class from the MRO to compare against
base_cls = None
for parent in inspect.getmro(cls):
if parent.__name__ == base.__name__:
base_cls = parent
break
if base_cls is None:
raise NameError(f'{base.__name__} is not in the MRO for {cls}')
# Compare the method implementations
return getattr(cls, method) != getattr(base_cls, method)