2008-11-26 138 views
10

我知道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" 

有没有办法来防止用户超载小豆()?

+2

为什么你想这样的事情?你害怕有人会重写它,它不会为他们工作吗?这是他们的问题。但有时候,他们知道他们在做什么,他们只需要做。我花了三天的时间解决了Java中的这种限制,在Python中是20秒。 – Pablo 2008-11-26 16:01:59

回答

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 
    ... 

元类型的新只要创建一个子类被调用;这会导致出现错误。只有在没有基类的情况下,它才会接受roo的定义。

您可以通过使用注释来声明哪些方法是最终的;那么你需要检查所有的基础并计算所有的最终方法,看看它们中的任何一个是否被覆盖。

这仍然不能阻止某人在定义一个类后将某个方法修改为类;您可以尝试通过使用自定义字典作为类的字典(它可能不适用于所有Python版本,因为类可能需要类字典才是确切的字典类型)。

+0

+1元类的好例子__new__ – 2008-11-26 16:12:09

8

由于Python有猴子补丁,你不仅不能做任何“私人”的东西。即使你可以,有人仍然可以在方法函数的新版本中使用monkeypatch。

您可以将此类名称用作“不要靠近”警告。

class Foo(object): 
    def _roo(self): 
     """Change this at your own risk.""" 

这是通常的做法。每个人都可以阅读你的来源他们受到警告。如果他们大胆地去他们被警告不要去的地方,他们会得到他们应得的。它不起作用,你不能帮助他们。

您可以尝试使用由“私有”方法调用的内部类和“隐藏”实现模块使其有意隐藏。但是......每个人都有你的来源。你不能阻止什么。你只能告诉人们他们行为的后果。

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" 

# -------------------- 
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的一部分,但你坚持使用评论方法(或metaclass hacks)。我个人的观点是最终的关键字对于继承是非常有用的,因为你可以避免类在被覆盖时以阴险的方式破坏(例如考虑在超级实现中使用“最终”方法,然后有人覆盖 - 繁荣,超级破坏) - 和文档的目的(不文档是不是编译时语法错误更好) - 但是Python的动态特性不会允许它和黑客都是脆弱的 - 那么添加文档字符串:

"""DON'T OVERRIDE THIS METHOD"""