[英]Removing specific methods from child class which are inherited from parent class
代码如下,只是基本结构:
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']
我想要做的是 class C
的实例不应该有specialmethod
,但该方法应该适用于实例A
和B
。
我可以在 class C
中覆盖此方法并引发错误,但我不想这样做。
我意识到我可以添加代码来检查_disallowed_methods
中的FooType
,并在此基础上检查instance
是否在dir(instance)
的 output 中有任何一个。 但我似乎无法使用迄今为止我尝试过的任何方法从C
的__dict__
中删除该方法。 我尝试的方法是delattr(instance, 'specialmethod')
和del instance.__dict__['specialmethod']
。
delattr
方法导致“AttributeError: specialmethod”, del
方法导致“TypeError: 'dict_proxy' object不支持删除项目”
基本上许多不同的类将从Foo
继承,但其中一些不应该有特定的方法可用,比如C
不应该有specialmethod
的特殊方法。
我究竟做错了什么? 或者我还能如何做到这一点?
好吧,您不能以这种方式完成此操作,因为您必须修改的不是C
class,而是Foo
class,它确实包含specialmethod
。 但实际上你不能这样做,因为class
是全局可变的 object 并且对Foo
的任何更改都会影响所有子类。
尝试以另一种方式思考。 例如,您可以修改访问C
class 属性的逻辑:
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
或者我还能如何做到这一点?
您可以通过使用多个 inheritance来获得类似的结果。
将您只希望某些子级拥有的方法从Foo
移动到ExtraFoo
。 然后使用class A(Foo, ExtraFoo)
或class C(Foo)
。 这样,您甚至可以在子层次结构的下方“重新附加”给定方法。
如果重新附加该方法不是您感兴趣的,那么您可以简单地将ExtraFoo
作为Foo
的子项(因此:添加方法,而不是分离它们)并拥有class A(ExtraFoo)
和class C(Foo)
。
如果您有一个不想被修改的父级,以及一个具有一个或多个继承方法的子级,您希望它无法访问,您可以使用描述符来实现。 最简单的方法之一是使用内置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
help(two) 如何打印它:
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)
相当不错,在我看来。 但是如果其他方法依赖于它们,你应该小心不要以这种方式定义继承方法(这可以通过使用代理 class 来避免,它从父级继承并将此类方法重新定义为使用super().bad_method()
而不仅仅是self.bad_method()
并将bad_method
本身指向不允许的描述符)。 如果需要,您可以编写更复杂的描述符逻辑
我进行过测试并偶然发现了完全相同的问题。
我发现只有一种真正的方法可以从继承的 class 中删除“不必要的方法”:从父级中删除它。 (这是个坏主意,因为如果 function 至少被调用一次,它将破坏所有父 class 的所有实例以及所有继承类的所有实例)。
示例代码:
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")
原因是“继承”的方法没有存储在父级中(作为代码或链接),而是保存在父级中。 当有人调用一个方法时,python 会遍历所有父类,直到找到一个或停止。
就我而言,我能够使用这种技术是因为我使用了其他人的测试来达到我的目的,并且我保留了他们的“setUp/tearDown”和腋窝方法,但我已经删除了他们所有的测试。
任何现实生活中的应用程序都不应该使用这种技术。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.