Mat*_*und 7 python initialization
我正在编辑原始问题,因为我们都专注于你应该做的事情.我的问题是我能做到这一点和如何(理解可能有几种解决方案).所以我只想离开实际问题并删除背景.
假设我有一个基类和一个子类.我可以在基类中做些什么来防止在子类上调用__init__ - 或者至少抛出一个异常甚至是日志,如果__init__存在或在子类上被调用?我确实希望在父类上调用__init__方法.
编辑/结论 - 在探索答案中提出的选项后,我认为这样做会很糟糕.我将以不同的方式解决我的问题.尽管如此,希望下面的答案有助于其他人想要这样做.
JBe*_*rdo 10
这很可行,但我认为你不应该这样做.告诉用户如何使用你的课程,他们应该遵守.此外,如果有人是子类,他应该知道如何调用父的初始化方法.
作为概念证明,这里是如何使用元类(Python 2.x语法)完成的:
>>> class WhoMovedMyInit(object):
class __metaclass__(type):
def __init__(self, *args, **kw):
super(type,self).__init__(*args, **kw)
if self.__init__ is not WhoMovedMyInit.__init__:
raise Exception('Dude, I told not to override my __init__')
>>> class IAmOk(WhoMovedMyInit):
pass
>>> class Lol(WhoMovedMyInit):
def __init__(self):
pass
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
class Lol(WhoMovedMyInit):
File "<pyshell#31>", line 6, in __init__
raise Exception('Dude, I told not to override my __init__')
Exception: Dude, I told not to override my __init__
Run Code Online (Sandbox Code Playgroud)
您还可以将子类__init__方法替换为警告用户或在"运行时"引发错误的方法.
jsb*_*eno 10
"我是否应该或需要这样做是一个单独的讨论:)"
请记住这一点.
但是它可以完成 - 当一个类被实例化时,不仅语法就像一个方法调用 - 类对象名称跟随括号 - 类本身(它是一个Python对象)被称为 - 作为一个可调用对象.
在Python中调用对象会__call__在其类中调用 magic方法.因此,实例化一个类,__call__在其元类上调用该方法.
__call__标准元类("类型")中此方法的内容大致相当于:
def __call__(cls, *args, **kw):
self = cls.__new__(cls, *args, **kw)
cls.__init__(self, *args, **kw)
return self
Run Code Online (Sandbox Code Playgroud)
因此,如果你编写一个元类,覆盖__call__并抑制对它们的调用__init__,它将不会被调用:
class Meta(type):
def __call__(cls, *args, **kw):
return cls.__new__(cls, *args, **kw)
class NoInit(object):
__metaclass__ = Meta
def __init__(self):
print "Hello!"
NoInit()
Run Code Online (Sandbox Code Playgroud)
如果你只想避免sublcasses __init__而不是不调用它,你可以做一个更简单的元类,它只会在类实例化时引发一个异常:
class Meta(type):
def __new__(metacls, name, bases, dct):
if "__init__" in dct:
raise NameError("Classes in this hierarchy should not have an __init__ method")
return type.__new__(metacls, name, bases, dct)
Run Code Online (Sandbox Code Playgroud)