2016-12-02 77 views
1

我想更好地理解Python 3.x数据模型。但是我找不到Python对象行为的完整和精确的解释。深入理解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一个新的实例,因此它是一个

2)不可改变的,可迭代的对象可能是单身......

上观察也适用于str,这是不可改变的迭代。所有以下变量:

s1 = 'jlandercy' 
s2 = str('jlandercy') 
s3 = copy.copy(s1) 
s4 = copy.deepcopy(s1) 

指向最初创建的复制d1['name']。字符串也是单身人士

......但不完全...

元组也不变迭代,但他们没有表现得像字符串。它知道魔空的元组是

() 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也是一个字典,浅拷贝没有复制它,然后它被修改了。

此行为类似于dict对象的copy.copy行为。我们需要copy.deepcopy有一个递归和完整的对象副本。

我的要求是:

  • 是我的意见正确解释?

    1. 不可改变的原子对象是单身

    2. 不可改变的,可迭代的对象可能是单身,但不完全相反,他们凑同样

    3. 双解引用传递词典作品作为浅拷贝

  • 这些行为是否有充分的文件记录?
  • 对于每种情况状态正确的属性&行为。

回答

1

不可变原子对象是单例

不,有些是,有些则不是,这是CPython的实现方式的细节。

  • 范围内的整数(-6, 256]缓存,当这些新的请求时返回已经存在的对象。在该范围以外的数字会受到常数折叠的影响,解释器在编译期间重新使用常量作为轻微优化。 This is documented在创建新的PyLong对象的部分。

    而且,看到关于这些的讨论如下:

  • 字符串字面量都受到了编译期间实习,以字节码做整型。尽管如此,规则的规则并不像整数那样简单:只考虑由特定字符组成的特定大小的字符串。我不知道文档中的任何部分具体说明了这一点,您可以通过阅读here来查看行为。

  • 花车,例如,它可以被认为是“原子”(即使在Python这个词没有你想的意思)有没有单身:

    i = 1.0 
    j = 1.0 
    i is j # False 
    

    他们依然当然经常折叠。正如你可以看到阅读:'is' operator behaves unexpectedly with floats

不可改变的,可迭代的对象可能是单身,但不完全相反,他们同样哈希

空immutables集合是signletons;这又是一个在Python Reference中找不到的实现细节,但是只有在查看源代码时才会发现。

看到这里看看实现:Why does '() is()' return True when '[] is []' and '{} is {}' return False?

双解引用传递辞典作品作为浅拷贝。

是的。虽然这个术语不是双解引用,但它是解包。

这些行为是否有充分的文件记录?

那些被认为是实现细节的东西不需要按照找到max函数的文档的方式进行记录。如果做出这样的决定,这些具体事情可能很容易改变。

+0

你的答案相当完整,我会稍等一下,如果有其他弹出。不管怎样,谢谢你。 – jlandercy

+0

这使sence @jlandercy,给你尽可能多的时间,因为你认为是最好的:-) –

+0

你可以添加信息哈希在[2],不可变和可迭代(只在stdlib)哈希总是以同样的方式?例如必须有我使用named_tuple或“原子类型”的元组就足够了?谢谢 – jlandercy