python - 如何定义仅超类的方法?
问题描述
片段:
class Base:
def superclass_only(self):
return 'yes'
class Foo(Base):
pass
foo = Foo()
>>> foo.superclass_only()
yes
# Expection is to raise error
>>> foo.superclass_only()
traceback
...
AttributeError: 'Foo' object has no attribute 'superclass_only'
如果我只想定义一个仅限超类的方法,我该怎么办?
解决方案
TL;DR : 为方法名称添加前缀__
以触发 Python 的名称修改机制。
回答:
你通常不能这样做:继承不应该是这样工作的。如果您需要在“子类”中“隐藏”方法,您应该重新调整您的方法。
第一件事是使用命名约定来指示该方法是私有的,在 Python 中,我们通过在方法名称中添加“_”前缀来做到这一点:这应该向您的Foo
类的用户指示应该使用保留的方法只有编写代码的人Base
才能放心。
另一件事是考虑在这种情况下,如果你的组合不会比继承更好:如果你的Base
类知道do things
Foo 不能对自己做,你真的可以说“Foo 对象也是 Base 对象”吗?(这就是继承的意义)。
也许,更好的设计是:
class Base:
...
class Bar:
def method_foo_cant_do(...):
...
class Foo(Base):
def __init__(self, ...):
self.bar = Bar()
...
最后,虽然不是为此而设计的,而是为了避免复杂层次结构中的方法名冲突,Python 有一种“名称修改”机制,它可以透明地将方法名更改为包含类名作为前缀的方法名。这将避免在子类中随意使用该方法,并且是一个更强有力的指标,表明它应该在“Base”中一起使用 - 但不会“不惜一切代价阻止”它被调用。
要走的路就是在方法前面加上两个下划线。在编译时,Python 将方法转换为 f"_{class_name}__{method_name}",在方法声明处以及在声明它的类中对它的所有引用中。所以Foo.__superclass_only
不会到达Base.__superclass_only
,因为后者的名字已经被修改为Base._Base__superclass_only
:
class Base:
def __superclass_only(self):
return 'yes'
class Foo(Base):
pass
在交互式解释器上:
In [3]: f= Foo()
In [4]: f.__superclass_only()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-19c8185aa9ad> in <module>
----> 1 f.__superclass_only()
但它仍然可以通过使用转换后的名称来访问:f._Base__superclass_only()
会起作用。
Python 允许的另一件事是自定义为给定类检索属性的方式:对类中的属性和方法的某种搜索是由__getattribute__
每个类中的方法执行的(不要误认为__getattr__
哪个更简单且旨在被击中仅当未找到属性时)。
重新实现__getattribute__
很容易出错,并且可能会让您比开始的方式更糟,并且给定一个对象,仍然可以通过做事
foo
来调用(即:从基类本身检索该方法作为未绑定的方法(函数)并手动传入实例以成为“self”参数),并减轻这种情况需要您在元类上实现正确的 - (并且最终仍然可以被可以阅读源代码的人绕过)superclass_only
Base.superclass_only(foo, ...)
foo
__get_attribute__
推荐阅读
- c - 如何在C中找到一定数量的随机生成数字的平均值?
- php - 尝试修复 ParseError 语法错误,laravel 中的文件意外结束
- r - 将迷你图添加到 R 中的 flextable
- java - Prim算法中的循环检测
- postgresql - 在 Chrome 中打开 PgAdmin 4
- python - 我无法使用 Selenium 发送 WhatsApp 消息:/ 出现这些错误
- java - Mac OS 11.0 上的 JFrame 窗口边缘是圆形的
- jquery - 将带有 jquery 的“live” css 应用到许多具有相同类的标签上
- arrays - 遍历将 12 个对象划分为 4 个组的所有可能方式
- android - Koin - 确保所有“通过注入”都是有效的