有没有办法在Python中识别继承的方法?

时间:2011-10-13 09:18:51

标签: python inheritance

除了重载或新定义的方法之外,我想告诉继承的方法。这可能与Python有关吗?

示例:

class A(object):
  def spam(self):
    print 'A spam'
  def ham(self):
    print 'A ham'

class B(A):
  def spam(self):
    print 'Overloaded spam'
  def eggs(self):
    print 'Newly defined eggs'

所需功能:

>>> magicmethod(B.spam)
'overloaded'
>>> magicmethod(B.ham)
'inherited'
>>> magicmethod(B.eggs)
'newly defined'

是否存在类似示例中的“魔术方法”,或者某种方式将这些类型的方法实现区分开来?

5 个答案:

答案 0 :(得分:17)

我不确定这是个好主意,但您可以使用hasattr__dict__来完成。

def magicmethod(clazz, method):
    if method not in clazz.__dict__:  # Not defined in clazz : inherited
        return 'inherited'
    elif hasattr(super(clazz), method):  # Present in parent : overloaded
        return 'overloaded'
    else:  # Not present in parent : newly defined
        return 'newly defined'

答案 1 :(得分:7)

如果你了解祖先,你可以简单地测试一下:

>>> B.spam == A.spam
False
>>> B.ham == A.ham
True

要查找所有基类的列表,请查看此处:List all base classes in a hierarchy of given class?

我还要指出,如果你需要这个,你的班级设计可能是错的。你不应该关心OOP中的这些东西(除非你正在创建一个对象检查器或类似的东西)。

答案 2 :(得分:6)

一般方法是(python 2。*):

def _getclass(method):
    try:
        return method.im_class
    except AttributeError:
        return method.__class__

def magicmethod(method):
    method_cls = _getclass(method)
    if method.__name__ not in method_cls.__dict__:
        return 'inherited'
    for cls in method_cls.__mro__[1:]:
        if method.__name__ in cls.__dict__:
            return 'overloaded'
    return 'newly defined'


__test__ = {"example": """

    >>> class A(object):
    ...     def spam(self):
    ...         print 'A spam'
    ...     def ham(self):
    ...         print 'A ham'

    >>> class B(A):
    ...     def spam(self):
    ...         print 'Overloaded spam'
    ...     def eggs(self):
    ...         print 'Newly defined eggs'

    >>> magicmethod(B.spam)
    'overloaded'
    >>> magicmethod(B.ham)
    'inherited'
    >>> magicmethod(B.eggs)
    'newly defined'
    >>> magicmethod(B.__init__)
    'inherited'
"""}

答案 3 :(得分:1)

扩大hamstergene的答案;类将其基类存储在类变量__bases__中。

所以:

>>> B.spam == B.__bases__[0].spam
False
>>> B.ham == B.__bases__[0].ham
True
>>> B.eggs == B.__bases__[0].eggs
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'A' has no attribute 'eggs'
>>> hasattr(B,"eggs")
True
>>> hasattr(B.__bases__[0],"eggs")
False

答案 4 :(得分:1)

对于新式类,您有一个方法mro(),返回方法结果顺序列表。 [0]是班级本身。

所以你可以做到

>>> any(hasattr(i, 'ham') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'spam') for i in B.mro()[1:])
True
>>> any(hasattr(i, 'eggs') for i in B.mro()[1:])
False

所以eggs是新定义的。

>>> any(getattr(B, 'ham') == getattr(i, 'ham', None) for i in B.mro()[1:])
True
>>> any(getattr(B, 'spam') == getattr(i, 'spam', None) for i in B.mro()[1:])
False

所以ham是继承的。

通过这些,您可以制作自己的启发式方法。