这个问题不是讨论单身人士设计模式是否可取,反模式,还是任何宗教战争,而是讨论如何以最蟒蛇的方式在Python中最好地实现这种模式.在这种情况下,我将"最pythonic"定义为表示它遵循"最小惊讶原则".
我有多个类可以成为单例(我的用例是记录器,但这并不重要).当我可以简单地继承或装饰时,我不希望在添加gumph的几个类中混乱.
最好的方法:
def singleton(class_):
instances = {}
def getinstance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return getinstance
@singleton
class MyClass(BaseClass):
pass
Run Code Online (Sandbox Code Playgroud)
优点
缺点
m = MyClass(); n = MyClass(); o = type(n)();那时m == n && m != o && n != oclass Singleton(object):
_instance = None
def __new__(class_, *args, **kwargs):
if not isinstance(class_._instance, class_):
class_._instance = object.__new__(class_, *args, **kwargs)
return class_._instance
class MyClass(Singleton, …Run Code Online (Sandbox Code Playgroud) 我有一个朋友喜欢使用元类,并定期提供它们作为解决方案.
我很想你几乎不需要使用元类.为什么?因为我认为如果你正在对一个类做类似的事情,你应该把它做成一个对象.并且需要一个小的重新设计/重构.
能够使用元类导致许多地方的很多人使用类作为某种二流对象,这对我来说似乎是灾难性的.编程是否被元编程取代?遗憾的是,类装饰器的添加使其更加可接受.
所以,我非常想知道Python中元类的有效(具体)用例.或者开悟为什么变异类有时比变异对象更好.
我将开始:
有时,在使用第三方库时,能够以某种方式改变类是有用的.
(这是我能想到的唯一一个案例,并不具体)
何时(为什么)__new__()引入了Python 函数?
创建类的实例需要三个步骤,例如MyClass():
MyClass.__call__()叫做。此方法必须在的元类中定义MyClass。MyClass.__new__()被调用__call__。MyClass自行定义。这将创建实例。MyClass.__init__()被(也称为__call__)。这将初始化实例。实例的创建会受到重载__call__或的影响__new__。通常没有理由重载__call__而不是重载__new__(例如,使用元类的__call__方法而不是__new__?)。
我们有一些旧代码(仍然运行得很强大!),其中__call__的重载位置。给出的原因是__new__当时尚不可用。因此,我尝试了解有关Python和我们的代码的历史的更多信息,但是我不知道何时__new__引入。
__new__出现在用于Python 2.4文档,而不是在那些Python 2.3中,但它不会出现在whathsnew任何Python 2中的版本。我可以找到的第一个提交__new__(将descr-branch合并回主干。)是2001年开始的,但是“ back into trunk”消息表明以前有过。几个月前的PEP 252(使类型看起来更像类)和PEP 253(对内置类型进行子类型化)似乎很重要。
学习更多有关引入的知识__new__将使我们更多地了解Python为何如此。
编辑以澄清:
似乎class.__new__重复了所提供的功能metaclass.__call__。添加仅以更好的方式复制现有功能的方法似乎不符合Pythonic。
__new__是您可以直接使用的少数几个类方法之一(cls例如,第一个参数),从而引入了以前没有的复杂性。如果类是函数的第一个参数,则可以认为该函数应该是元类的常规方法。但是该方法已经存在:__call__()。我觉得我想念什么。
应该有一种-最好只有一种-显而易见的方法。
当试图了解metaclass创建类实例的顺序时,我感到困惑。根据此图(源),
我输入以下代码进行验证。
class Meta(type):
def __call__(self):
print("Meta __call__")
super(Meta, self).__call__()
def __new__(mcs, name, bases, attrs, **kwargs):
print("Meta __new__")
return super().__new__(mcs, name, bases, kwargs)
def __prepare__(msc, name, **kwargs):
print("Meta __prepare__")
return {}
class SubMeta(Meta):
def __call__(self):
print("SubMeta __call__!")
super().__call__()
def __new__(mcs, name, bases, attrs, **kwargs):
print("SubMeta __new__")
return super().__new__(mcs, name, bases, kwargs)
def __prepare__(msc, name, **kwargs):
print("SubMeta __prepare__")
return Meta.__prepare__(name, kwargs)
class B(metaclass = SubMeta):
pass
b = B()
Run Code Online (Sandbox Code Playgroud)
但是,结果似乎不像下面这样。
SubMeta __prepare__
Meta …Run Code Online (Sandbox Code Playgroud)