python 可变变量与不可变变量区分

转:https://blog.csdn.net/god_wen/article/details/78423621

不可变变量

我们可以通过下面的例子来感受上面的话

<span style="color:#000000"><code>52454056
52454032
</code></span>

id()是一个内置函数,可以返回对象的唯一标识 
同样的变量x进过经过加操作后地址改变了。

<span style="color:#000000"><code>x=<span style="color:#006666">1</span>
y=<span style="color:#006666">1</span>
z=<span style="color:#006666">1</span>
<span style="color:#4f4f4f">print</span> id(x)
<span style="color:#4f4f4f">print</span> id(y)
<span style="color:#4f4f4f">print</span> id(z)</code></span>
<span style="color:#000000"><code>56976040
56976040
56976040
</code></span>

可以发现虽然变量名不同但是地址确实一样的。

这种特性是不是很想别的语言中的字符串。我们称有这种特性的变量为不可变变量(值一旦改变就会占据新的内存空间)。python中的不可变变量有如下

不可变(immutable):int、字符串(string)、float、(数值型number)、元组(tuple),None

优点: 
这样可以减少重复的值对内存空间的占用。 
缺点: 
操作之后就开辟内存的特性。执行效率会有一定程度的降低。

可变变量

我再来看看可变变量

<span style="color:#000000"><code>x=[]
<span style="color:#4f4f4f">print</span> id(x)
x.<span style="color:#4f4f4f">append</span><span style="color:#006666">(1</span>)
<span style="color:#4f4f4f">print</span> id(x)</code></span>
<span style="color:#000000"><code>49918024
49918024
</code></span>

可以看见可变量和别的语言是一样的。内存是不会改变的

<span style="color:#000000"><code>x=[]
y=[]
z=[]
<span style="color:#4f4f4f">print</span> id(x)
<span style="color:#4f4f4f">print</span> id(y)
<span style="color:#4f4f4f">print</span> id(z)</code></span>
<span style="color:#000000"><code>62566472
62669960
62671368
</code></span>

可以看见对于可变变量 ,创建一次就开辟一次地址,不会引用同一块内存

可变(mutable)变量:字典型(dictionary)、列表型(list)

默认参数时注意事项

python 中不可变量为按值传递,可变变量按引用传递

<span style="color:#000000"><code><span style="color:#000088">def</span> <span style="color:#009900">f</span><span style="color:#4f4f4f">(l=[])</span>:
    l.append(<span style="color:#006666">1</span>)
    <span style="color:#000088">return</span> l
<span style="color:#000088">print</span> f()
<span style="color:#000088">print</span> f()
<span style="color:#000088">print</span> f()</code></span>
<span style="color:#000000"><code>[1]
[1, 1]
[1, 1, 1]
</code></span>

这是为什么呢?首先我们要知道python 你看见的任何东西都是对象。函数也不例外,默认参数有如下特点

  • 一个函数参数的默认值,仅仅在该函数定义的时候,被赋值一次。
  • 函数默认参数参数在每次调用时指向那个定义时创建的参数

现在我们来验证上上面的结果。 
参数的默认值就存在__defaults__中。

<span style="color:#000000"><code><span style="color:#000088">def</span> <span style="color:#009900">f</span><span style="color:#4f4f4f">(l=[])</span>:

    l.append(<span style="color:#006666">1</span>)
    <span style="color:#000088">return</span> l
f()
<span style="color:#000088">print</span> f.__defaults__
f()
<span style="color:#000088">print</span> f.__defaults__
f()
<span style="color:#000088">print</span> f.__defaults__
</code></span>
<span style="color:#000000"><code>([1],)
([1, 1],)
([1, 1, 1],)
</code></span>

可以看见参数的默认值就在其中,但是是不是同一个呢,现在我们来看看地址

<span style="color:#000000"><code><span style="color:#000088">def</span> <span style="color:#009900">f</span><span style="color:#4f4f4f">(i=<span style="color:#006666">1</span>)</span>:
    <span style="color:#000088">print</span> id(i)
    i+=<span style="color:#006666">1</span>
    <span style="color:#000088">print</span> id(i)
    <span style="color:#000088">return</span> i

f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%+id(f.__defaults__[<span style="color:#006666">0</span>])
f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%+id(f.__defaults__[<span style="color:#006666">0</span>])</code></span>
<span style="color:#000000"><code>56976040
56976016
默认值地址:56976040
56976040
56976016
默认值地址:56976040
56976040
56976016
默认值地址:56976040
</code></span>

可以发现函数定义时默认值就已近存在在__defaults__中了。在调用函数时我们的参数变量就会被赋值为这个__defaults__[0]地址。当.__defaults__[0]是不可变变量时 
我们对参数变量进行修改时我们的参数变量地址会变化。这个和我们的逻辑思维一致

可变变量就不一样了!

<span style="color:#000000"><code><span style="color:#000088">def</span> <span style="color:#009900">f</span><span style="color:#4f4f4f">(l=[])</span>:
    <span style="color:#000088">print</span> id(l)
    l.append(<span style="color:#006666">1</span>)
    <span style="color:#000088">print</span> id(l)
    <span style="color:#000088">return</span> l

f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])</code></span>
<span style="color:#000000"><code>58904648
58904648
默认值地址:58904648
58904648
58904648
默认值地址:58904648
58904648
58904648
默认值地址:58904648
</code></span>

因为可变变量的特性。我们在更改时时不会换地址的,所以我们一直都是在更改__defaults__[0] 。这种特性在默认参数中不是我们想要的。我们用如下的代码完成任务

<span style="color:#000000"><code><span style="color:#000088">def</span> <span style="color:#009900">f</span><span style="color:#4f4f4f">(l=None)</span>:
    <span style="color:#000088">print</span> id(l)
    l=[]
    l.append(<span style="color:#006666">1</span>)
    <span style="color:#000088">print</span> id(l)
    <span style="color:#000088">return</span> l

<span style="color:#000088">print</span> f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
<span style="color:#000088">print</span> f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
<span style="color:#000088">print</span> f()
<span style="color:#000088">print</span> <span style="color:#009900">'默认值地址:%s'</span>%id(f.__defaults__[<span style="color:#006666">0</span>])
</code></span>
<span style="color:#000000"><code>1792584792
47296584
[1]
默认值地址:1792584792
1792584792
47296584
[1]
默认值地址:1792584792
1792584792
47296584
[1]
默认值地址:1792584792
</code></span>

因为None是不可变变量,所以我对他的所有操作都是在新的内存中完成的。这其实也就是None的作用

类中全局变量的注意事项

<span style="color:#000000"><code><span style="color:#000088">class</span> <span style="color:#4f4f4f">b</span>:
    x = []
    <span style="color:#000088">def</span> <span style="color:#009900">set</span><span style="color:#4f4f4f">(self)</span>:
        self.x.append(<span style="color:#006666">1</span>)
    <span style="color:#000088">def</span> <span style="color:#009900">get</span><span style="color:#4f4f4f">(self)</span>:
        <span style="color:#000088">return</span> self.x
<span style="color:#000088">for</span> i <span style="color:#000088">in</span> range(<span style="color:#006666">3</span>):
    a = b()
    <span style="color:#000088">print</span> b.__dict__
    a.set()
    a.get()
</code></span>
<span style="color:#000000"><code>{'x': [], '__module__': '__main__', 'set': <function set at 0x0000000002DE5AC8>, '__doc__': None, 'get': <function get at 0x0000000002DE5B38>}
{'x': [1], '__module__': '__main__', 'set': <function set at 0x0000000002DE5AC8>, '__doc__': None, 'get': <function get at 0x0000000002DE5B38>}
{'x': [1, 1], '__module__': '__main__', 'set': <function set at 0x0000000002DE5AC8>, '__doc__': None, 'get': <function get at 0x0000000002DE5B38>}
</code></span>

可以发现每次创建类b时,其中的x都是不一样的。这也是因为可变变量的原因

而对于不可变变量就不一样了

<span style="color:#000000"><code>
<span style="color:#000088">class</span> <span style="color:#4f4f4f">b</span>:
    x = <span style="color:#006666">1</span>
    <span style="color:#000088">def</span> <span style="color:#009900">set</span><span style="color:#4f4f4f">(self)</span>:
        self.x+=<span style="color:#006666">1</span>
    <span style="color:#000088">def</span> <span style="color:#009900">get</span><span style="color:#4f4f4f">(self)</span>:
        <span style="color:#000088">return</span> self.x
<span style="color:#000088">for</span> i <span style="color:#000088">in</span> range(<span style="color:#006666">3</span>):
    a = b()

    <span style="color:#000088">print</span> b.__dict__
    a.set()
    <span style="color:#000088">print</span> a.get()
</code></span>
<span style="color:#000000"><code>{'x': 1, '__module__': '__main__', 'set': <function set at 0x000000000313AAC8>, '__doc__': None, 'get': <function get at 0x000000000313AB38>}
2
{'x': 1, '__module__': '__main__', 'set': <function set at 0x000000000313AAC8>, '__doc__': None, 'get': <function get at 0x000000000313AB38>}
2
{'x': 1, '__module__': '__main__', 'set': <function set at 0x000000000313AAC8>, '__doc__': None, 'get': <function get at 0x000000000313AB38>}
2
</code></span>

可以发现,原先的”全局变量“现在已经不是全局变量了

猜你喜欢

转载自blog.csdn.net/weixin_42068613/article/details/81394445
今日推荐