如何定义超类专用方法?
How to define a superclass-only method?
片段:
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的名字修饰机制。
答案:
您通常不能这样做:这不是继承的工作方式。
如果你需要在“subclasses”中“隐藏”方法,你应该重新考虑你的方法。
第一件事是使用命名约定来指示该方法是私有的,在 Python 中,我们通过在方法名称中添加“_”前缀来做到这一点:这应该是对用户的指示您的 Foo
class 保留方法只能由编写 Base
中的代码的人使用,不要管。
另一件事是想想在这种情况下你是否会比继承更好地使用组合:如果你的 Base
class 知道 do things
Foo 做不到就其本身而言,您真的可以说“Foo 对象也是 Base 对象”吗? (这就是继承的意义所在)。
也许,更好的设计是:
class Base:
...
class Bar:
def method_foo_cant_do(...):
...
class Foo(Base):
def __init__(self, ...):
self.bar = Bar()
...
最后,虽然不是为此设计的,而是为了避免复杂层次结构中的方法名称冲突,Python 有一个“名称修改”机制,它会透明地将方法名称更改为包括class 名称作为前缀。这将避免在 subclasses 中随意使用该方法,并成为一个更强有力的指标,表明它应该在“Base”中一起使用——但不会“不惜一切代价”阻止它被调用。
方法就是在方法前加上两个下划线。在编译时,Python 将方法转换为 f"_{class_name}__{method_name}",在方法声明中以及 [=65= 中对它的所有引用中] 声明的地方。所以 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 允许的另一件事是自定义为给定的 class 检索属性的方式:class 中对属性和方法的某种搜索是由 [每个 class 中的 =22=] 方法(不要将其与 __getattr__
混淆,后者更简单,仅在未找到属性时才命中)。
重新实现 __getattribute__
很容易出错,可能会让你比开始时的方式更糟,并且给定一个 foo
对象,仍然可以调用 superclass_only
通过做
Base.superclass_only(foo, ...)
(即:从 Base class 本身检索方法作为未绑定方法(函数)并手动传入 foo
实例以成为“self”参数),并减轻这种情况将要求您在 metaclass 上实现正确的 __get_attribute__
-(并且最终仍然可以被能够阅读源代码的人绕过)
您可以使用装饰器函数包装 superclass-only 方法,该函数根据方法的 class 名称验证当前实例的 class 名称,该名称可以从方法的__qualname__
属性:
def superclass_only(method):
def wrapper(self, *args, **kwargs):
if self.__class__.__name__ != method.__qualname__.split('.')[-2]:
raise NotImplementedError
return method(self, *args, **kwargs)
return wrapper
因此:
class Base:
@superclass_only
def method(self):
return 'yes'
class Foo(Base):
pass
调用 Base().method()
returns 'yes'
,同时调用 Foo().method()
引发 NotImplementedError
.
演示:https://replit.com/@blhsing/SpringgreenHonorableCharacters
片段:
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的名字修饰机制。
答案:
您通常不能这样做:这不是继承的工作方式。 如果你需要在“subclasses”中“隐藏”方法,你应该重新考虑你的方法。
第一件事是使用命名约定来指示该方法是私有的,在 Python 中,我们通过在方法名称中添加“_”前缀来做到这一点:这应该是对用户的指示您的 Foo
class 保留方法只能由编写 Base
中的代码的人使用,不要管。
另一件事是想想在这种情况下你是否会比继承更好地使用组合:如果你的 Base
class 知道 do things
Foo 做不到就其本身而言,您真的可以说“Foo 对象也是 Base 对象”吗? (这就是继承的意义所在)。
也许,更好的设计是:
class Base:
...
class Bar:
def method_foo_cant_do(...):
...
class Foo(Base):
def __init__(self, ...):
self.bar = Bar()
...
最后,虽然不是为此设计的,而是为了避免复杂层次结构中的方法名称冲突,Python 有一个“名称修改”机制,它会透明地将方法名称更改为包括class 名称作为前缀。这将避免在 subclasses 中随意使用该方法,并成为一个更强有力的指标,表明它应该在“Base”中一起使用——但不会“不惜一切代价”阻止它被调用。
方法就是在方法前加上两个下划线。在编译时,Python 将方法转换为 f"_{class_name}__{method_name}",在方法声明中以及 [=65= 中对它的所有引用中] 声明的地方。所以 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 允许的另一件事是自定义为给定的 class 检索属性的方式:class 中对属性和方法的某种搜索是由 [每个 class 中的 =22=] 方法(不要将其与 __getattr__
混淆,后者更简单,仅在未找到属性时才命中)。
重新实现 __getattribute__
很容易出错,可能会让你比开始时的方式更糟,并且给定一个 foo
对象,仍然可以调用 superclass_only
通过做
Base.superclass_only(foo, ...)
(即:从 Base class 本身检索方法作为未绑定方法(函数)并手动传入 foo
实例以成为“self”参数),并减轻这种情况将要求您在 metaclass 上实现正确的 __get_attribute__
-(并且最终仍然可以被能够阅读源代码的人绕过)
您可以使用装饰器函数包装 superclass-only 方法,该函数根据方法的 class 名称验证当前实例的 class 名称,该名称可以从方法的__qualname__
属性:
def superclass_only(method):
def wrapper(self, *args, **kwargs):
if self.__class__.__name__ != method.__qualname__.split('.')[-2]:
raise NotImplementedError
return method(self, *args, **kwargs)
return wrapper
因此:
class Base:
@superclass_only
def method(self):
return 'yes'
class Foo(Base):
pass
调用 Base().method()
returns 'yes'
,同时调用 Foo().method()
引发 NotImplementedError
.
演示:https://replit.com/@blhsing/SpringgreenHonorableCharacters