Ram*_*hum 40 python inheritance namespaces class
我有一个子类,我希望它不包含基类上存在的类属性.
我试过这个,但它不起作用:
>>> class A(object):
... x = 5
>>> class B(A):
... del x
Traceback (most recent call last):
File "<pyshell#1>", line 1, in <module>
class B(A):
File "<pyshell#1>", line 2, in B
del x
NameError: name 'x' is not defined
Run Code Online (Sandbox Code Playgroud)
我怎样才能做到这一点?
Bhu*_*han 47
您可以使用delattr(class, field_name)
它从类定义中删除它.
Kei*_*ith 17
您无需删除它.只是覆盖它.
class B(A):
x = None
Run Code Online (Sandbox Code Playgroud)
或者根本不参考它.
或者考虑不同的设计(实例属性?).
Kat*_*iel 12
仔细想想你为什么要这样做; 你可能没有.考虑不要让B从A继承.
子类化的想法是专门化一个对象.特别是,类的子节点应该是父类的有效实例:
>>> class foo(dict): pass
>>> isinstance(foo(), dict)
... True
Run Code Online (Sandbox Code Playgroud)
如果你实现了这种行为(例如x = property(lambda: AttributeError)
),你就破坏了子类化概念,这就是坏事.
也许你可以在有人试图访问它时设置x
为property
并引发AttributeError.
>>> class C:
x = 5
>>> class D(C):
def foo(self):
raise AttributeError
x = property(foo)
>>> d = D()
>>> print(d.x)
File "<pyshell#17>", line 3, in foo
raise AttributeError
AttributeError
Run Code Online (Sandbox Code Playgroud)
没有一个答案对我有用.
例如delattr(SubClass, "attrname")
(或其精确等价物del SubClass.attrname
)不会"隐藏"父方法,因为这不是方法解析的工作方式.AttributeError('attrname',)
相反,它将失败,因为子类没有attrname
.当然,替换属性None
并不会实际删除它.
让我们考虑一下这个基类:
class Spam(object):
# Also try with `expect = True` and with a `@property` decorator
def expect(self):
return "This is pretty much expected"
Run Code Online (Sandbox Code Playgroud)
我知道只有两种方法可以将它子类化,隐藏expect
属性:
使用一个描述符类引起AttributeError
的__get__
.在属性查找时,会出现异常,通常与查找失败无法区分.
最简单的方法就是宣布一个提升的财产AttributeError
.这基本上是@JBernardo所建议的.
class SpanishInquisition(Spam):
@property
def expect(self):
raise AttributeError("Nobody expects the Spanish Inquisition!")
assert hasattr(Spam, "expect") == True
# assert hasattr(SpanishInquisition, "expect") == False # Fails!
assert hasattr(SpanishInquisition(), "expect") == False
Run Code Online (Sandbox Code Playgroud)
但是,这仅适用于实例,而不适用于类(hasattr(SpanishInquisition, "expect") == True
断言会被破坏).
如果您希望上面的所有断言都成立,请使用:
class AttributeHider(object):
def __get__(self, instance, owner):
raise AttributeError("This is not the attribute you're looking for")
class SpanishInquisition(Spam):
expect = AttributeHider()
assert hasattr(Spam, "expect") == True
assert hasattr(SpanishInquisition, "expect") == False # Works!
assert hasattr(SpanishInquisition(), "expect") == False
Run Code Online (Sandbox Code Playgroud)
我相信这是最优雅的方法,因为代码清晰,通用且紧凑.当然,应该真的三思,如果除去该属性是他们真正想要的.
使用__getattribute__
魔术方法覆盖属性查找.您可以在子类中执行此操作(或者在下面的示例中使用mixin,因为我只想编写一次),这会隐藏子类实例上的属性.如果要隐藏子类中的方法,则需要使用元类.
class ExpectMethodHider(object):
def __getattribute__(self, name):
if name == "expect":
raise AttributeError("Nobody expects the Spanish Inquisition!")
return super().__getattribute__(name)
class ExpectMethodHidingMetaclass(ExpectMethodHider, type):
pass
# I've used Python 3.x here, thus the syntax.
# For Python 2.x use __metaclass__ = ExpectMethodHidingMetaclass
class SpanishInquisition(ExpectMethodHider, Spam,
metaclass=ExpectMethodHidingMetaclass):
pass
assert hasattr(Spam, "expect") == True
assert hasattr(SpanishInquisition, "expect") == False
assert hasattr(SpanishInquisition(), "expect") == False
Run Code Online (Sandbox Code Playgroud)
这看起来比上面的方法更糟糕(更冗长,更通用),但也可以考虑这种方法.
请注意,这并没有特殊("魔术")方法(如工作__len__
),因为这些绕行__getproperty__
.有关更多详细信息,请查看Python文档的特殊方法查找部分.如果这是你需要撤消的,只需覆盖它并调用object
实现,跳过父节点.
毋庸置疑,这仅适用于"新式类"(继承自的类object
),因为那里不支持魔术方法和描述符协议.希望这些都是过去的事情.
我也有同样的问题,我认为我有一个有效的理由删除子类中的class属性:我的超类(称之为A)有一个只读属性提供了属性的值,但是我的子类(称之为B),该属性是一个读/写实例变量.我发现Python正在调用属性函数,即使我认为实例变量应该覆盖它.我可以使用一个单独的getter函数来访问底层属性,但这似乎是一个不必要的,不优雅的接口命名空间的混乱(好像这真的很重要).
事实证明,答案是用A的原始公共属性创建一个新的抽象超类(称之为S),并且A和B派生自S.因为Python有鸭子打字,所以B确实不重要不扩展A,我仍然可以在相同的地方使用它们,因为它们隐含地实现了相同的接口.