【问题标题】:Is there a way to identify an inherited method in Python?有没有办法在 Python 中识别继承的方法?
【发布时间】:2011-12-06 19:20:51
【问题描述】:

我想将继承的方法与重载或新定义的方法区分开来。用 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'

是否有像示例中那样的“魔术方法”,或者有什么方法可以区分这些类型的方法实现?

【问题讨论】:

    标签: python inheritance


    【解决方案1】:

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

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

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

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

    【讨论】:

    • 很好,这是 OOP 中的一个奇怪要求
    • 这是一种特殊情况,其中一个对象可能必须被扩展而不被子类化。我必须检查是否可以简单地覆盖其中一种方法,或者是否必须保留已经存在的覆盖方法。所以是的,它在某种程度上是一个对象检查器,即使不是用于调试/分析目的。我意识到这可能并不总是一个好主意,但我认为在这种情况下这是合理的。感谢您指出可能的设计错误。
    【解决方案2】:

    我不确定这是一个好主意,但您可以使用 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'
    

    【讨论】:

    • hasattr(super(clazz), method) 仅适用于方法,因为 super(clazz) 返回该类方法的代理类。例如类属性不是代理类的一部分
    【解决方案3】:

    扩展 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】:

      一般方法是(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'
      """}
      

      【讨论】:

        【解决方案5】:

        对于新式类,你有一个方法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 被继承了。

        有了这些,您可以制定自己的启发式方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-16
          • 1970-01-01
          • 2011-01-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多