从子类中删除从父类继承的特定方法

sku*_*led 9 python inheritance metaclass

代码如下,只是基本结构:

class FooType(type):
    def __new__( cls, name, bases, classdict ):
        instance = type.__new__( cls, name, bases, classdict )
        # What can I do here?
        return instance

class FooBase( object, metaclass=FooType ):
    def __init__( self ):
        pass

class Foo( FooBase ):
    def __init__( self, name ):
        self.name = name

    def method1( self ):
        pass

    def method2( self ):
        pass

    def specialmethod( self ):
        pass

class A( Foo ):
    pass

class B( Foo ):
    pass

class C( Foo ):
    _disallowed_methods = ['specialmethod']
Run Code Online (Sandbox Code Playgroud)

我想要做的是类的实例C不应该有specialmethod,但该方法应该可用于实例AB.

我可以在类中重写此方法C并引发错误,但我不想这样做.

我意识到我可以在该检查的基础上添加代码来检查是否_disallowed_methods在输出中有任何一个.但我似乎无法从删除方法的使用到目前为止,我还没有尝试过任何方法.我试过的方法是,和.FooTypeinstancedir(instance)__dict__Cdelattr(instance, 'specialmethod')del instance.__dict__['specialmethod']

delattr方法导致"AttributeError:specialmethod",并且该del方法导致"TypeError:'dict_proxy'对象不支持项删除"

基本上许多不同的类将继承Foo,但是其中一些不C应该具有specialmethod可用的特定方法,就像它们不可用的那样.

我究竟做错了什么?或者我怎么能做到这一点?

tho*_*nev 6

如果您有一个不想被修改的父级,以及一个具有一个或多个您希望无法访问的继承方法的子级,则可以使用描述符来实现。最简单的方法之一是使用property内置:

class Parent:
    def good_method(self):
        print('Good one')

    def bad_method(self):
        print('Bad one')

class Child(Parent):
    bad_method = property(doc='(!) Disallowed inherited')

one = Parent()
one.good_method()  # > 'Good one'
one.bad_method()   # > 'Bad one'

two = Child()
two.good_method()  # > 'Good one'
two.bad_method()   # > AttributeError: unreadable attribute
two.bad_method     # > AttributeError: unreadable attribute
two.bad_method = 'Test'  # > AttributeError: can't set attribute
Run Code Online (Sandbox Code Playgroud)

帮助(两个)如何打印它:

class Child(Parent)
 |  Method resolution order:
 |      Child
 |      Parent
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  bad_method
 |      (!) Disallowed inherited
 |  
 |  ----------------------------------------------------------------------
 |  Methods inherited from Parent:
 |  
 |  good_method(self)
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors inherited from Parent:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
Run Code Online (Sandbox Code Playgroud)

相当不错,在我看来。但是你应该小心,如果其他方法依赖它们,你应该小心不要以这种方式定义继承的方法(这可以通过使用代理类来避免,代理类从父类继承并重新定义这些方法以使用super().bad_method()而不是仅仅使用self.bad_method()并将其bad_method自身指向不允许使用的描述符)。如果需要,您可以编写更复杂的描述符逻辑


Rom*_*huk 5

好吧,你不能以这种方式实现这一点,因为你必须修改不是C类,而是修改Foo真正包含的类specialmethod.但实际上你不能这样做,因为class是全局可变对象,任何更改Foo都会影响所有子类.

试着以另一种方式思考.例如,您可以修改访问C类属性的逻辑:

class C( Foo ):
    def __getattribute__(self, name):
        if name in ['specialmethod']:
            raise AttributeError('no such method')
        return super(C, self).__getattribute__(name)
Run Code Online (Sandbox Code Playgroud)

之后C('a').specialmethod()产生追溯:

Traceback (most recent call last):
  File "meta.py", line 37, in <module>
    C('a').specialmethod()
  File "meta.py", line 34, in __getattribute__
    raise AttributeError('no such method')
AttributeError: no such method
Run Code Online (Sandbox Code Playgroud)


mac*_*mac 4

或者我还能怎样实现这个目标?

您可以通过使用多重继承获得类似的结果。

将您只希望部分子级拥有的方法从Foo移至ExtraFoo。然后使用 class A(Foo, ExtraFoo)class C(Foo)。这样,您甚至可以在子层次结构中进一步“重新附加”给定方法。

如果重新附加该方法不是您感兴趣的事情,那么您可以简单地将 和 作为ExtraFoo的子级Foo(因此:添加方法,而不是分离它们)并拥有class A(ExtraFoo)class C(Foo)