使功能无法覆盖

Ube*_*per 16 python

我知道python函数默认是虚拟的.假设我有这个:

class Foo:
    def __init__(self, args):
        do some stuff
    def goo():
        print "You can overload me"
    def roo():
        print "You cannot overload me"
Run Code Online (Sandbox Code Playgroud)

我不希望他们能够做到这一点:

class Aoo(Foo):
    def roo():
        print "I don't want you to be able to do this"
Run Code Online (Sandbox Code Playgroud)

有没有办法防止用户超载roo()?

Mar*_*wis 38

您可以使用元类:

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
    ...
Run Code Online (Sandbox Code Playgroud)

每当创建子类时,都会调用元类型的new ; 如果您出现,这将导致错误.只有在没有基类的情况下,它才会接受roo的定义.

通过使用注释声明哪些方法是最终的,您可以使方法更加花哨; 然后,您需要检查所有基础并计算所有最终方法,以查看是否有任何基础被覆盖.

这仍然不能阻止某人在定义之后将方法修补到类中; 您可以尝试通过使用自定义词典作为类的字典来捕获这些(这可能不适用于所有Python版本,因为类可能要求类字典具有精确的dict类型).

  • 如果我不得不使用你的课,我会恨你的 (2认同)

Tag*_*gar 36

Python 3.8(2019 年 10 月发布)final为输入添加了限定符。

一个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")
        ...

Run Code Online (Sandbox Code Playgroud)

它符合您的要求,现在由核心 Python 支持。

查看PEP-591了解更多细节。

  • 请注意,它不是在运行时强制执行的,它需要一个静态类型检查器:“可以在类上使用“@final”装饰器动态地防止在运行时子类化。不过,“typing”中的任何其他内容都不会执行任何运行时强制,因此“final”也不会。 (7认同)
  • 遗憾的是没有办法有两个被接受的答案:) (2认同)

S.L*_*ott 10

由于Python有猴子修补,你不仅可以做任何"私人".即使你可以,有人仍然可以在新版本的方法函数中进行monkeypatch.

您可以将此类名称用作"不要靠近"警告.

class Foo( object ):
    def _roo( self ):
       """Change this at your own risk."""
Run Code Online (Sandbox Code Playgroud)

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

您可以尝试使用"私有"方法调用的内部类和"隐藏"实现模块来故意使用此方法.但是......每个人都有你的来源.你不能阻止任何事情.你只能告诉人们他们行为的后果.


M. *_*AYA 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"

# --------------------
Run Code Online (Sandbox Code Playgroud)