类名作为幂等类型转换函数

MvG*_*MvG 3 python constructor casting python-3.x

我正在写一个自定义类型Foo,我想实现以下目标:写作时

foo = Foo(bar)
Run Code Online (Sandbox Code Playgroud)

那么如果bar已经是一个实例Foo,则Foo(foo)返回该对象未修改,所以foobar引用同一个对象.否则,Foo应使用来自bar任何Foo.__init__认为合适的方式的信息创建类型的新对象.

我怎样才能做到这一点?

我认为这Foo.__new__是关键.Foo.__new__如果instanceof检查成功则返回现有对象应该相当容易,super().__new__否则调用.但是文档__new__写这个:

如果__new__()返回cls的实例,则将__init__()调用新实例的方法__init__(self[, ...]),其中self是新实例,其余参数与传递给的相同__new__().

在这种情况下,我将返回所请求类的实例,尽管不是新实例.我可以以某种方式阻止呼叫__init__吗?或者我是否必须在内部添加一个检查__init__来检测是为新创建的实例还是为现有实例调用它?后者听起来像代码重复,应该是可以避免的.

Ser*_*sta 7

恕我直言,你应该直接使用__new____init__.在init中进行的测试,看看你是应该初始化一个新对象还是已经有一个现有对象,这样就很简单,没有代码重复,增加的复杂性是恕我直言

class Foo:
    def __new__(cls, obj):
        if isinstance(obj, cls):
            print("New: same object")
            return obj
        else:
            print("New: create object")
            return super(Foo, cls).__new__(cls)
    def __init__(self, obj):
        if self is obj:
            print("init: same object")
        else:
            print("init: brand new object from ", obj)
            # do the actual initialization
Run Code Online (Sandbox Code Playgroud)

它按预期给出:

>>> foo = Foo("x")
New: create object
init: brand new object from  x
>>> bar = Foo(foo)
New: same object
init: same object
>>> bar is foo
True
Run Code Online (Sandbox Code Playgroud)