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

时间:2011-07-14 13:22:40

标签: 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']

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

我可以在类C中覆盖此方法并引发错误,但我不想这样做。

我意识到我可以添加代码来检查_disallowed_methods中的FooType,并根据该检查instance是否在{{1}的输出中有任何一个}}。但我似乎无法使用我迄今为止尝试过的任何方法从dir(instance)的{​​{1}}中删除该方法。我尝试过的方法是__dict__C

delattr(instance, 'specialmethod')方法导致“AttributeError:specialmethod”,del instance.__dict__['specialmethod']方法导致“TypeError:'dict_proxy'对象不支持项删除”

基本上很多不同的类都会从delattr继承,但其中一些不应该有像del这样的特定方法,它们不应该有Foo

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

4 个答案:

答案 0 :(得分: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)

之后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

答案 1 :(得分:2)

  

或者我怎么能做到这一点?

使用multiple inheritance可以获得类似的结果。

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

如果重新附加方法不是你感兴趣的东西,那么你可以简单地将ExtraFoo作为Foo的孩子(所以:添加方法,而不是分离它们)并且{{1 }和class A(ExtraFoo)

答案 2 :(得分:1)

如果您有一个您不想修改的父级,并且您希望无法访问具有一个或多个继承方法的子级,则可以使用描述符执行此操作。 最简单的方法之一是使用HtmlListItemElement内置:

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

在我看来,相当不错。但是如果其他方法依赖于它们,你应该注意不要以这种方式定义继承的方法(这可以通过使用代理类来避免,代理类继承自父级并重新定义此类方法以使用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) 而不仅仅是{{1}并指出super().bad_method()本身不允许描述符)。 如果需要,您可以编写更复杂的描述符逻辑

答案 3 :(得分:0)

我已经完成了测试并且遇到了完全相同的问题。

我发现只有一种真正的方法可以删除不必要的方法&#39;来自继承类:从父类中删除它。 (这是个坏主意,因为如果该函数被调用至少一次,它将破坏所有父类的所有实例和所有继承类的所有实例。)

示例代码:

class Base(object):
    def excessive(self):
        pass

class Inher(Base):
    def __init__(self):
        #import pdb
        #pdb.set_trace()
        del Base.excessive

b=Base()
example = Inher()
try:
    example.excessive()
except  AttributeError:
    print("Removed!")
else:
    raise Exception("Not removed!")
try:
    b.excessive()
except AttributeError:
    print("Unfortunately, all instances of Base no longer have .excessive() method")

原因是&#39;继承了&#39;方法不存储在父级中(作为代码或链接),但保留在父级内。当有人调用方法时,python会遍历所有父类,直到找到一个或停止。

在我的情况下,我能够使用这种技术,因为我使用其他人测试我的目的,我保持他们的&#39; setUp / tearDown&#39;和腋窝方法,但我已经删除了他们所有的测试。

任何现实生活中的应用都不应该使用这种技术。