我想更好地理解Python 3.x数据模型。但我没有找到Python对象行为的完整而准确的解释。
我正在寻找引用,如果我在下面展示的每个案例都可以链接到Python API参考或PEP或任何其他有价值的东西,那就太棒了。再次感谢您的明智建议......
假设我们有一些复杂的Python结构用于测试目的:
d1 = {
'id': 5432
,'name': 'jlandercy'
,'pets': {
'andy': {
'type': 'cat'
,'age': 3.5
}
,'ray': {
'type': 'dog'
,'age': 6.5
}
}
,'type': str
,'complex': (5432, 6.5, 'cat', str)
,'list': ['milk', 'chocolate', 'butter']
}
1)不可变的原子对象是单身
无论我创建一个新整数的方式如何:
n1 = 5432
n2 = int(5432)
n3 = copy.copy(n1)
n4 = copy.deepcopy(n1)
不会创建此数字的新副本,而是指向与d1['id']
相同的对象。更简洁
d1['id'] is n1
...
它们都具有相同的id
,我无法创建值为5432的新int
实例,因此它是 singleton 。
2)不可变和可变对象可能是单身......
之前的观察也适用于str
,它们是不可变和可迭代。以下所有变量:
s1 = 'jlandercy'
s2 = str('jlandercy')
s3 = copy.copy(s1)
s4 = copy.deepcopy(s1)
指向最初创建的副本d1['name']
。字符串也是单例。
......但不完全......
元组也是 immutable 和 iterable ,但它们的行为不像字符串。众所周知,神奇的空元组是 singleton :
() is ()
但是其他元组不是。
t1 = (5432, 6.5, 'cat', str)
...相反,他们同样哈希
他们没有相同的id
:
id(d1['complex']) != id(t1)
但是这两个结构中的所有项都是原子的,因此它们指向相同的实例。重要的是,两个结构hash
的方式相同:
hash(d1['complex']) == hash(t1)
因此它们可以用作字典键。对于嵌套元组,这甚至是正确的:
t2 = (1, (2, 3))
t3 = (1, (2, 3))
它们具有相同的hash
。
3)通过双重解除引用传递字典作为它的浅层副本
让我们定义以下功能:
def f1(**kwargs):
kwargs['id'] = 1111
kwargs['pets']['andy'] = None
将通过双重解除引用(**
运算符)接收我们的试用词典第一学位成员将被复制,但最深的将通过引用传递。
这个简单程序的输出说明了它:
print(d1)
f1(**d1)
print(d1)
它返回:
{'complex': (5432, 6.5, 'cat', <class 'str'>),
'id': 5432,
'list': ['milk', 'chocolate', 'butter'],
'name': 'jlandercy',
'pets': {'andy': {'age': 3.5, 'type': 'cat'},
'ray': {'age': 6.5, 'type': 'dog'}},
'type': <class 'str'>}
{'complex': (5432, 6.5, 'cat', <class 'str'>),
'id': 5432,
'list': ['milk', 'chocolate', 'butter'],
'name': 'jlandercy',
'pets': {'andy': None, 'ray': {'age': 6.5, 'type': 'dog'}},
'type': <class 'str'>}
字典d1
已由函数f1
修改,但并非完全修改。成员id
'被保留,因为我们处理了一个副本,但成员pets
也是一个字典而浅层副本没有复制它,然后它已被修改。
此行为类似于copy.copy
对象的dict
行为。我们需要copy.deepcopy
来获得对象的递归和完整副本。
我的要求是:
我的观察是否正确解释了?
不可变的原子对象是单身
不可变和可迭代的对象可能是单例,但并不完全相反,它们是平等的
通过双重解除引用传递字典作为它的浅层副本
答案 0 :(得分:1)
不可变的原子对象是单身
不,有些是,有些不是,这是CPython实现的细节。
缓存(-6, 256]
范围内的整数,当对这些整数发出新请求时,将返回已存在的对象。该范围之外的数字受到常量折叠的影响,其中解释器在编译期间重新使用常量作为轻微优化。有关创建新PyLong
个对象的部分中的This is documented。
另外,请参阅以下内容以讨论这些内容:
在编译到字节码期间,字符串文字会像int一样进行实习。但是,管理它的规则并不像int中那样简单:只考虑由特定字符组成的特定大小的字符串。我不知道文档中的任何部分指定了这一点,您可以通过阅读here来查看行为。
浮动,例如,可以考虑&#34;原子&#34; (即使在Python中,这个术语并没有你想到的意思),也没有单身人士:
i = 1.0
j = 1.0
i is j # False
他们当然仍然需要不断折叠。正如您所看到的那样:'is' operator behaves unexpectedly with floats
不可变和可迭代的对象可能是单例,但并不完全相反,它们是同等的
空的immutables集合是signletons;这又是一个实现细节,无法在Python参考中找到,但只有在查看源代码时才会发现。
请参阅此处了解实施情况:Why does '() is ()' return True when '[] is []' and '{} is {}' return False?
通过双重解除引用传递字典作为它的浅层副本。
是。虽然该术语不是双重解除引用,但它正在解包。
这些行为是否记录在某处?
那些被视为实施细节的内容无需以您查找max
函数文档的方式进行记录。如果做出决定,这些是可能容易改变的具体事情。