我了解以下行为是not guaranteed:
>>> x = "Hello, world!"
>>> y = "Hello, world!"
>>> assert x is y
但是,这种行为是否得到保证:
>>> x = "Hello, world!"
>>> y = str(x)
>>> assert x is y
如果是这样,在我自己的(不可变的)类中实现这种行为的正确方法是什么?
编辑:通过"此行为"我的意思是"一个应该重用现有实例的类的构造函数":
>>> x = MyClass("abc", 123)
>>> y = MyClass(x)
>>> assert x is y
答案 0 :(得分:1)
x is y
实际上正在检查id(x) is id(y)
,即这两个引用是否指向同一个对象。 CPython中的str
将返回相同的对象,如果它已经是一个字符串,那么从那个角度来看你描述的行为:
y = str(x)
assert x is y
适用于所有x
isinstance(x, str)
。来自the documentation:
对于字符串,[
str
]返回字符串本身。
我不确定我会认为这是一个实现细节的保证,但会尽量避免编写依赖它的代码。
在SO和其他地方有很多资源在Python中实现不可变的自定义类,所以我不会在这里重复这些信息。
答案 1 :(得分:1)
看起来PyObject_Str
函数负责转换为str
对象。如果是这样,这是它接收str
对象作为参数(v
)时的作用:
if (PyUnicode_CheckExact(v)) {
#ifndef Py_DEBUG
if (PyUnicode_READY(v) < 0)
return NULL;
#endif
Py_INCREF(v);
return v;
}
它只是增加引用计数并返回该对象而不进行更改 - 这就是以下示例中的对象保持不变的原因:
>>> x = 'long string' * 1000
>>> str(x) is x
True
这确实是一个实现细节,因此它可能因不同的Python版本和实现而有所不同。
您也可以找到我的问题Python's int function performance的有趣答案。
答案 2 :(得分:1)
覆盖__new__()
以返回传入的对象:
class C(object):
def __new__(cls, ref):
if isinstance(ref, C):
return ref
else:
return super(C, cls).__new__(cls)
def __init__(self, ref):
if self is not ref:
self.x = ref
c1=C(7)
c2=C(13)
assert c1 is not c2
c3=C(c1)
assert c1 is c3