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.
我有一个类,是许多其他类的超类。我想知道(在我的超类的init()中,子类是否覆盖了特定的方法。
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?
有没有办法让超类知道子类是否覆盖了一个方法?
4 个解决方案
#1
8
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
#2
5
In reply to answer https://*.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.
在回答https://*.com/a/9437273/1258307的回复中,因为我还没有足够的信用评论它,除非你用__func__替换im_func并且也无法工作,否则它将无法在python 3下工作在python 3.4中(很可能是向前),因为函数不再具有__func__属性,只有绑定方法。
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):
编辑:这是原始问题的解决方案(适用于2.7和3.4,我假设其他所有版本):
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
#3
4
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']
[]
#4
3
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:
你可以将类__dict__中的任何东西与你可以从对象中检索的方法中的函数进行比较 - “detect_overriden”函数可以做到这一点 - 诀窍是传递“父类”作为其名称,就像在调用“super” - 否则从父类本身而不是从子类中检索属性并不容易:
# -*- 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.
编辑更改的代码以使用classmethods也可以正常工作:如果它在父类上检测到类方法,则在继续之前提取基础函数。
-- 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.
- 另一种方法是在不必对类名进行硬编码的情况下,遵循实例的类(self .__ class__)方法解析顺序(由__mro__属性给出),并搜索在中定义的方法和属性的副本。继承链中的每个类。
#1
8
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
#2
5
In reply to answer https://*.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.
在回答https://*.com/a/9437273/1258307的回复中,因为我还没有足够的信用评论它,除非你用__func__替换im_func并且也无法工作,否则它将无法在python 3下工作在python 3.4中(很可能是向前),因为函数不再具有__func__属性,只有绑定方法。
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):
编辑:这是原始问题的解决方案(适用于2.7和3.4,我假设其他所有版本):
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
#3
4
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']
[]
#4
3
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:
你可以将类__dict__中的任何东西与你可以从对象中检索的方法中的函数进行比较 - “detect_overriden”函数可以做到这一点 - 诀窍是传递“父类”作为其名称,就像在调用“super” - 否则从父类本身而不是从子类中检索属性并不容易:
# -*- 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.
编辑更改的代码以使用classmethods也可以正常工作:如果它在父类上检测到类方法,则在继续之前提取基础函数。
-- 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.
- 另一种方法是在不必对类名进行硬编码的情况下,遵循实例的类(self .__ class__)方法解析顺序(由__mro__属性给出),并搜索在中定义的方法和属性的副本。继承链中的每个类。