如何在python中检测子类中的方法重载?

Bri*_*ian 20 python abstract-class overriding class

我有一个类是许多其他类的超类.我想知道(在我的超类的init()中,子类是否已覆盖特定方法.

我尝试使用类方法完成此操作,但结果是错误的:

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
Run Code Online (Sandbox Code Playgroud)

有没有办法让超类知道子类是否覆盖了一个方法?

wbe*_*rry 10

你可以使用自己的装饰.但这是一个技巧,只适用于控制实现的类.

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
Run Code Online (Sandbox Code Playgroud)

  • 我进入了一个稍微不同的方向,使用@native来装饰我的方法,并假设子类不会.我想我会这样做,因为我对子类没有多少控制权.它运作良好,谢谢你的帮助! (7认同)
  • 或更简单地说,将Super.method._original = True用作Super()类的主体,然后检查是否具有hasattr(self.method,'_original')。 (3认同)

Fle*_*exo 7

通过比较实例字典的公共子集和基类本身来做到这一点似乎最简单和充分,例如:

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()
Run Code Online (Sandbox Code Playgroud)

运行并给出:

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()
Run Code Online (Sandbox Code Playgroud)


s0u*_*3ch 6

在回复/sf/answers/660609141/,由于我还没有足够的信用评论它,它将无法在python 3下工作,除非你替换im_func,__func__也将无法在python中工作3.4(并且很可能是向前)因为函数不再具有__func__属性,只有绑定方法.

编辑:这是原始问题的解决方案(适用于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
Run Code Online (Sandbox Code Playgroud)

这是输出:

same
different
same
Run Code Online (Sandbox Code Playgroud)


小智 5

如果要检查 Python 3 中的重写实例方法,可以使用 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
Run Code Online (Sandbox Code Playgroud)

现在 Base() 和 Sub2() 都应该打印“相同”,而 Sub1() 打印“不同”。classmethod 装饰器使第一个参数绑定到 self 的类型,并且由于子类的类型根据定义与其基类不同,因此两个类方法将比较为不相等。通过使该方法成为实例方法并使用 self 类型,您将一个普通函数与另一个普通函数进行比较,并假设函数(或在这种情况下,如果您使用的是 Python 2 的未绑定方法)比较等于它们自己(即他们在 C Python 实现中这样做),将产生所需的行为。