我知道python函数默认是虚拟的。假设我有这个:
class Foo:
def __init__(self, args):
do some stuff
def goo():
print "You can overload me"
def roo():
print "You cannot overload me"
我不希望他们能够这样做:
class Aoo(Foo):
def roo():
print "I don't want you to be able to do this"
有没有办法防止用户超载roo()?
答案 0 :(得分:32)
您可以使用元类:
class NonOverridable(type):
def __new__(self, name, bases, dct):
if bases and "roo" in dct:
raise SyntaxError, "Overriding roo is not allowed"
return type.__new__(self, name, bases, dct)
class foo:
__metaclass__=NonOverridable
...
每当创建子类时,都会调用元类型的 new ;如果您出现,这将导致错误。只有在没有基类的情况下,它才会接受roo的定义。
通过使用注释声明哪些方法是最终的,您可以使方法更加花哨;然后,您需要检查所有基础并计算所有最终方法,以查看是否有任何基础被覆盖。
这仍然不能阻止某人在定义之后将方法修补到类中;您可以尝试通过使用自定义词典作为类的字典来捕获这些(这可能不适用于所有Python版本,因为类可能要求类字典具有精确的dict类型)。
答案 1 :(得分:8)
由于Python有猴子修补,你不仅不能做任何“私人”。即使你可以,有人仍然可以在方法函数的新版本中进行monkeypatch。
您可以将此类名称用作“不要靠近”警告。
class Foo( object ):
def _roo( self ):
"""Change this at your own risk."""
这是通常的做法。每个人都可以阅读你的来源。他们被警告了。如果他们大胆地去了他们被警告不去的地方,他们就会得到他们应得的。它不起作用,你无法帮助他们。
您可以尝试使用“私有”方法调用的内部类和“隐藏”实现模块来故意隐藏这一点。但是......每个人都有你的来源。你不能阻止任何事情。你只能告诉人们他们行为的后果。
答案 2 :(得分:6)
def non_overridable(f):
f.non_overridable = True
return f
class ToughMeta(type):
def __new__(cls, name, bases, dct):
non_overridables = get_non_overridables(bases)
for name in dct:
if name in non_overridables:
raise Exception ("You can not override %s, it is non-overridable" % name)
return type.__new__(cls, name, bases, dct)
def get_non_overridables(bases):
ret = []
for source in bases:
for name, attr in source.__dict__.items():
if getattr(attr, "non_overridable", False):
ret.append(name)
ret.extend(get_non_overridables(source.__bases__))
return ret
class ToughObject(object):
__metaclass__ = ToughMeta
@non_overridable
def test1():
pass
# Tests ---------------
class Derived(ToughObject):
@non_overridable
def test2(self):
print "hello"
class Derived2(Derived):
def test1(self):
print "derived2"
# --------------------
答案 3 :(得分:2)
Python 3.8(于2019年10月发布)在输入中添加了final
限定词。
一个final
限定词将以最终修饰符和最终类型注释的形式添加到键入模块中,以实现三个相关目的:
from typing import final
class Base:
@final
def foo(self) -> None:
...
class Derived(Base):
def foo(self) -> None: # Error: Cannot override final attribute "foo"
# (previously declared in base class "Base")
...
这似乎更符合您的要求,并且现在得到了核心Python的支持。
有关更多详细信息,请查看PEP-591。
答案 4 :(得分:0)
派对迟到但默认情况下并非所有python方法都是“虚拟” - 请考虑:
class B(object):
def __priv(self): print '__priv:', repr(self)
def call_private(self):
print self.__class__.__name__
self.__priv()
class E(B):
def __priv(self): super(E, self).__priv()
def call_my_private(self):
print self.__class__.__name__
self.__priv()
B().call_private()
E().call_private()
E().call_my_private()
由于名称损坏导致的打击:
B
__priv: <__main__.B object at 0x02050670>
E
__priv: <__main__.E object at 0x02050670>
E
Traceback (most recent call last):
File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 35, in <module>
E().call_my_private()
File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 31, in call_my_private
self.__priv()
File "C:/Users/MrD/.PyCharm2016.3/config/scratches/test_double__underscore", line 27, in __priv
def __priv(self): super(E, self).__priv()
AttributeError: 'super' object has no attribute '_E__priv'
因此,如果你想从语言中获得一些帮助,禁止人们在课堂上覆盖你需要的一些功能,那么这就是你要走的路。如果您想要最终的方法是您的类API的一部分,但是您仍然坚持使用注释方法(或元类黑客)。我个人的观点是,最后一个关键字对于继承非常有用 - 因为你可以避免在被覆盖时以类似的方式破坏类(例如,考虑在超级实现中使用“final”方法然后有人覆盖 - 繁荣,超级破坏) - 并且出于文档目的(没有文档比编译时语法错误更好) - 但是Python的动态性质不允许它和hacks很脆弱 - 所以添加一个文档字符串:
"""DON'T OVERRIDE THIS METHOD"""