引用和拷贝

python中没有赋值,只有引用。
(1)没有限制条件的分片表达式(L[:])能够复制序列,但此法只能浅层复制(浅复制出来的对象内存地址和原来不一样)。
(2)字典 copy 方法,D.copy() 能够复制字典,但此法只能浅层复制
(3)有些内置函数,例如 list,能够生成拷贝 list(L)
(4)copy 标准库模块能够生成完整拷贝:deepcopy 本质上是递归 copy(之前遇到过keystone.seesion来传证书,然后发现参数里有session,同时还有其他参数里也包含了session,这样不能deepcopy)
对象分为可变与不可变的,
可变:list set dict
可变对象更改的时候,内存地址不变,只是区域长度会变长或变短;但不可变对象如string更改的时候,内存地址会发生改变,及id(d)会变化即身份标示
对象的三要素:id(身份标示),type(数据类型)、value(值)
is比较的是两个对象的id值是否相等,也就是比较两个对象是否为同一个实例对象,是否指向同一个内存地址。
==比较的是两个对象的内容是否相等,默认会调用对象的eq()方法。

>>> b = 10**3
>>> a == b
True
>>> a is b
False
>>>
数字类型不一样,id也不一样
>>> c = 'pythontab.com'
>>> d = 'pythontab.com'
>>> c is d
False
>>> c == d
True
>>> c = 'pythontabcom'
>>> d = 'pythontabcom'
>>> c is c
True
>>> c == d
True
字符串类型不一样,导致id不一样

4.为什么修改全局的dict变量不用global关键字
为什么修改字典d的值不用global关键字先声明呢?

s = 'foo'
d = {'a':1}
def f():
    s = 'bar'
    d['b'] = 2
f()
print s  # foo
print d  # {'a': 1, 'b': 2}

这是因为,【1】在s = 'bar'这句中,它是“有歧义的“,因为它既可以是表示引用全局变量s,也可以是创建一个新的局部变量,所以在python中,默认它的行为是创建局部变量,除非显式声明global,global定义的本地变量会变成其对应全局变量的一个别名,即是同一个变量。【2】在d['b']=2这句中,它是“明确的”,因为如果把d当作是局部变量的话,它会报KeyError,所以它只能是引用全局的d,故不需要多此一举显式声明global。

上面这两句赋值语句其实是不同的行为,一个是rebinding(不可变对象), 一个是mutation(可变对象).
但是如果是下面这样:

d = {'a':1}
def f():
    d = {}
    d['b'] = 2
f()
print d  # {'a': 1}

在d = {}这句,它是”有歧义的“了,所以它是创建了局部变量d,而不是引用全局变量d,所以d['b']=2也是操作的局部变量。
推而远之,这一切现象的本质就是”它是否是明确的“。
仔细想想,就会发现不止dict不需要global,所有”明确的“东西都不需要global。因为int类型str类型之类的不可变对象,每一次操作就重建新的对象,他们只有一种修改方法,即x = y, 恰好这种修改方法同时也是创建变量的方法,所以产生了歧义,不知道是要修改还是创建。而dict/list/对象等可变对象,操作不会重建对象,可以通过dict['x']=y或list.append()之类的来修改,跟创建变量不冲突,不产生歧义,所以都不用显式global。
5.list的=和append/extend的区别

list_a = []
def a():
    list_a = [1]      ## 语句1
a()
print list_a    # []

print "======================"

list_b = []
def b():
    list_b.append(1)    ## 语句2
b()
print list_b    # [1]

因为 = 创建了局部变量,而 .append() 或者 .extend() 重用了全局变量。
可参考这个[https://blog.csdn.net/dream_allday/article/details/78767813]
一般可变对象的id变了,值也就不一样了
6.5、陷阱:使用可变的默认参数
我多次见到过如下的代码:

def foo(a, b, c=[]):
# append to c
# do some more stuff
永远不要使用可变的默认参数,可以使用如下的代码代替:

def foo(a, b, c=None):
    if c is None:
        c = []
    # append to c
    # do some more stuff
‍‍与其解释这个问题是什么,不如展示下使用可变默认参数的影响:‍‍

In[2]: def foo(a, b, c=[]):
...        c.append(a)
...        c.append(b)
...        print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]

同一个变量c在函数调用的每一次都被反复引用。这可能有一些意想不到的后果。

你可能感兴趣的:(引用和拷贝)