Python:将对象实例化为引用

时间:2018-01-05 18:53:19

标签: python

我所要求的可能在Python中是不可能的,可能源于我习惯于指针,但这就是它如何:在python中可以实现以下目标吗?

class A(object):
    #body of class

a = A() #create a new object
b = A(a) #"b" is now an alias for "a"

我天真地尝试这样做是

class A(object):
    def __init__(self, x):
        if isinstance(x, A):
             self = x

但是,当然,这是无意义的,因为自我只是一个局部变量。

编辑:要清楚,这不是简单的变量赋值(即b=a创建别名但我不在乎)。当我试图构建一个包含大量相同类型对象的循环时,出现了这个问题:

class A(object):
    #blah

l = []
for cond in conditions:
    tmp = A(*cond)
    l.append(tmp)

如果cond[0]是A类型的另一个对象,则tmp只是对该对象的引用。 现在,有一个解决方法,但这不是我要求的。我想知道我的原始问题是否有解决方案。

3 个答案:

答案 0 :(得分:2)

如果你想这样做,必须在对象__new__方法中进行。您可以在其中影响新对象的创建,而不是在创建后修改它们的__init__。一种方法是

class A:
    def __new__(cls, copy=None):
        if copy: # This assumes that instances of A cannot be falsy
            if isinstance(copy, A):
                return copy
            else:
                raise ValueError("Argument not of type A")
        else:
            return super().__new__(cls)

a = A()
b = A(a)
b is a # True

答案 1 :(得分:2)

您可以使用__new__

来实现这一目标
class A(object):
    def __new__(cls, param=None):
        if isinstance(param, A):
            return param
        return super().__new__(cls)

    def __init__(self, param=None):  # should match __new__ signature
        if isinstance(param, A):
            return
        self.param = param
        # normal initialization

据说你可能想重新考虑你的架构。

答案 2 :(得分:0)

我认为最好的方法实际上是在这里使用元类,特别是如果你计划使用继承,尽管,元类确实增加了一些复杂性。如果只是,我会呼吁这是创建单例类的常用方法,这与你原则上做的非常相似。但这是一个草图:

In [43]: class MyMeta(type):
    ...:     def __call__(cls, *args, **kwargs):
    ...:         if isinstance(args[0], cls):
    ...:             return args[0]
    ...:         else:
    ...:             return super(MyMeta, cls).__call__(*args, **kwargs)
    ...:

In [44]: class A(metaclass=MyMeta):
    ...:     def __init__(self, arg1, arg2):
    ...:         print("initialized")
    ...:

In [45]: a1 = A(1, 1)
initialized

In [46]: a2 = A(2, 2)
initialized

In [47]: a3 = A(a1, 3)

In [48]: [hex(id(x)) for x in (a1, a2, a3)]
Out[48]: ['0x103ccd160', '0x103ccd198', '0x103ccd160']

In [49]: a1 is a2, a1 is a3
Out[49]: (False, True)

注意,来自docs

  

__new__()主要用于允许不可变类型的子类   (例如intstrtuple)来自定义实例创建。它是   也经常在自定义元类中重写以便自定义   课堂创作。

另请注意,使用此方法时,不会再次调用__init__可能是您想要的。

In [53]: class A(object):
    ...:     def __new__(cls, *args, **kwargs):
    ...:         if isinstance(args[0], A):
    ...:             return args[0]
    ...:         return super().__new__(cls)
    ...:
    ...:     def __init__(self, arg1, arg2):  # should match __new__ signature
    ...:         print("initialized")
    ...:

In [54]: a1 = A(1, 1)
initialized

In [55]: a2 = A(2, 2)
initialized

In [56]: a3 = A(a1, 3)
initialized

In [57]: a1 is a2, a1 is a3
Out[57]: (False, True)