IT系统集成商

系统集成 | 虚拟化应用 | 群晖网络存储 | 视频会议 | 数据防泄密 | 技术运维

手机: 130-1534-6247   电话: 0351-2396570

Python笔记1-变量与对象

关注亿维讯达
关注亿维讯达

一、Python 中,一切皆对象。每个对象由:标识(identity)、类型(type)、value(值)组成。
1. 标识用于唯一标识对象。使用内置函数 id(obj)可返回对象 obj 的标识。
2. 类型用于表示对象存储的“数据”的类型。可以使用 type(obj)获得对象的所属类型。
3. 值表示对象所存储的数据的信息。使用 print(obj)可以直接打印出值。
4. Python 是动态类型语言,变量不需要显式声明类型。根据变量引用的对象,Python 解释器自动确定数据类型。
5. Python 是强类型语言,每个对象都有数据类型,只支持该类型支持的操作。
 
二、赋值
 
在 Python 中,变量也称为对象的引用。变量引用“对象”。
变量位于栈内存。对象位于堆内存。
 
python 赋值
变量盒子

Python 赋值语句实际上与“变量盒子”模型略有不同。在 Python 中,值可能最终放在内存中的任何位置,而变量用于引用它们。对变量赋值就像把一个黄色小粘贴便签放在值上,并说“这是 x”。
python 赋值
赋值就象贴标签
 
上图是一个更准确的 Python 赋值的效果。箭头用于显示变量引用的值。旧值不会被新值擦除,变量只需重新绑定新值。效果就像将粘贴便签从一个对象移动到另一个对象一样(重新绑定)。

你也不必担心计算机内存中充满“被丢弃”的值。如果一个值不再被任何变量引用,它就不再有用。 Python将自动从内存中清除这些值,以便空间可以用于存放新值。这个自动内存管理的过程确实被称为“垃圾收集”。

变量在使用前必须先进行初始化,也就是将变量绑定在一个对象上,格式如:变量名 = 表达式。执行过程中,解释器先运行右边的表达式,在堆内存中创建一个对象,然后将对象的内存地址赋给左边的变量。

<section style="margin: 0px; padding: 0px; color: rgb(51, 51, 51); font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, " helvetica="" neue",="" "pingfang="" sc",="" "hiragino="" sans="" gb",="" "microsoft="" yahei="" ui",="" yahei",="" arial,="" sans-serif;="" font-size:="" 17px;="" text-align:="" justify;="" text-indent:="" 2em;"=""> 为了简化内存管理,Python通过引用计数机制实现自动垃圾回收功能,Python中的每个对象都有一个引用计数,用来计数该对象在不同场所分别被引用了多少次。每当引用一次Python对象,相应的引用计数就增1,每当消毁一次Python对象,则相应的引用就减1,只有当引用计数为零时,才真正从内存中删除Python对象。

 

不要将is用于数和字符串等不可变的基本值。鉴于Python在内部处理这些对象时可能会采用“small integer cache”的方式,将一些小整数、字符串等不可变对象只保留一份拷贝,这样做的结果是不可预测的。
 
三、 可变对象与不可变对象
 
Python在heap中分配的对象分成2类:
  1. 不可变对象(immutable object):Number(int、float、bool、complex)、String、Tuple. 采用等效于“传引用”的方式。
  2. 可变对象(mutable object):List、dictionary.采用等效于“传值”的方式。
 
四、关于参数传递
 
在编程语言设计中,有两种常见的范例将参数传递给函数:
    传递值:参数的副本传递给函数。
    传递引用:对参数的引用将传递给函数。
 
Python中的参数是按值传递还是按引用传递?答案是,两者都不是。
 
回想一下,在Python中,每条数据都是一个对象。引用指向一个对象,而不是一个特定的内存位置。
在Python中,类似的赋值语句如下:
 
x = 5
x = 10
这些赋值语句具有以下含义:
 
第一条语句导致x指向一个值为的对象5。
下x一条语句重新分配为值为的另一个对象的新引用10。换句话说,第二个赋值重新绑定x到具有value的另一个对象10。
在Python中,当您将参数传递给函数时,会发生类似的重新绑定。考虑以下示例:
 
def f(fx):
    fx = 10
 
x = 5
f(x)
---------------------
>>>x
>>>5
在主程序中,第x = 5的语句创建一个名为x的引用,该引用x绑定到一个值为的对象5。然后x作为参数调用f()。当f()第一次启动时,一个叫做fx新的引用被创建,它最初指向对象x(也就是5)
 
python参数传递
 
函数调用图
 
但是,在执行fx = 10的语句时,将fx重新绑定 到值为10的新对象。x和fx这两个引用相互分离。没有影响主程序中的x,并且在f()终止x时仍会指向该对象5,就像在函数调用之前一样:
python参数传递
 
Python函数调用
 
可以使用id()确认。显示了所涉及对象的数字标识符:
 
>>> def f(fx):
 2 ...     print('fx =', fx, '/ id(fx) = ', id(fx))
 3 ...     fx = 10
 4 ...     print('fx =', fx, '/ id(fx) = ', id(fx))
 5 ...
 6 
 7 >>> x = 5
 8 >>> print('x =', x, '/ id(x) = ', id(x))
 9 x = 5 / id(x) =  1357924048
10 
11 >>> f(x)
12 fx = 5 / id(fx) =  1357924048
13 fx = 10 / id(fx) =  1357924128
14 
15 >>> print('x =', x, '/ id(x) = ', id(x))
16 x = 5 / id(x) =  1357924048
当f()第一次启动,fx与x都指向同一个对象,它id()是1357924048。f()执行语句fx = 10后,fx指向不同的对象,它id()是1357924128。调用环境中与原始对象的连接丢失。
 
Python中的参数传递在某种程度上是按值传递和按引用传递之间的混合。传递给函数的是对对象的引用,但该引用是按值传递的。
 
注意: Python的参数传递机制称为pass-by-assignment。这是因为参数名称绑定到Python中函数输入上的对象,并且赋值也是将名称绑定到对象的过程。您可能还会看到术语“按对象传递”,“按对象传递引用”或“按共享传递”。
 
这里的关键要点是,Python函数无法通过将相应的参数重新分配给其他东西来更改参数的值。下面的示例演示了这一点:
>>> def f(x):
...     x = 'foo'
...
>>> for i in (40,dict(foo=1, bar=2),{1, 2, 3},'bar',['foo', 'bar', 'baz']):
...     f(i)
...     print(i)
...
40
{'foo': 1, 'bar': 2}
{1, 2, 3}
bar
['foo', 'bar', 'baz']
在这里,类型的对象int,dict,set,str,,list传递给f()作为参数。但是正如您所看到的,一旦回到调用环境中,它们都保持不变。一旦f()执行任务x = 'foo',将被重新绑定,原始对象的连接丢失。
 
这是否意味着Python函数根本无法修改其参数?其实不,不是这样!注意这里发生的情况:
 
>>> def f(x):
...     x[0] = '---'
...

>>> my_list = ['foo', 'bar', 'baz', 'qux']

>>> f(my_list)
>>> my_list
['---', 'bar', 'baz', 'qux']
在这种情况下,f()参数是list。当f()被调用时,一个引用my_list被传递。您已经看到f()无法重新分配my_list。但是,f()可以在内部使用引用进行修改my_list。在这里,f()已经修改了第一个元素。您可以看到,函数一旦返回,my_list实际上在调用环境中已被更改。相同的概念适用于字典:
 
>>> def f(x):
...     x['bar'] = 22
...

>>> my_dict = {'foo': 1, 'bar': 2, 'baz': 3}

>>> f(my_dict)
>>> my_dict
{'foo': 1, 'bar': 22, 'baz': 3}
在这里,f()修改了my_dict。该更改反映在f()返回后的调用环境中。
 
参数传递摘要
 
Python中传递的参数可以总结如下。传递一个不可变的对象,像int,str,tuple,或frozenset,传递给Python函数的行为类似于按值传递。该函数无法在调用环境中修改对象。传递一个可变的对象,比如list、dict或set,可以起到类似于引用传递的作用,但不完全是这样。该函数不能完全重新分配对象,但它可以在对象中适当地更改项,这些更改将反映在调用环境中。
关注亿维讯达
关注亿维讯达