代码如下,只是基本结构:
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
,但该方法应该可用于实例A
和B
。
我可以在类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
。
我做错了什么?或者我怎么能做到这一点?
答案 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;和腋窝方法,但我已经删除了他们所有的测试。
任何现实生活中的应用都不应该使用这种技术。