ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python风格——动态类型

2021-06-01 12:33:39  阅读:277  来源: 互联网

标签:python list1 list2 对象 风格 引用 动态 id


python风格

想要写出python风格的代码,就得理解python的特点,合理的应用python所带来的东西。
python是一门动态类型的语言,这是由python的设计思想所决定的。在python中,我们编写对象接口而不是类型。我们关心的是一个对象能做什么,而不是关心它是什么。它是什么并不重要,重要的是它能做什么?我们希望代码能自动的适应非常多的类型,任何具有兼容性的接口对象能够正常工作。实际上这就是多态(多态:指为不同数据类型的实体提供统一的接口),这也是使用python的核心思想之一。

动态语言

既然我们只关心只它能做什么,那么它是什么就没有那么的重要了。因此将python设计为一门动态语言就非常合理。
动态语言程序运行时,允许改变程序结构(例如引进新函数、删除旧函数)或变量类型。动态语言中的变量本身是没有类型的,但是变量所绑定的值是有类型的,但是这个类型检查是发生在运行期的。
在python中,是没有类型声明的,直接给变量绑定值即可。例如:
s = "123"
一个有编写过静态类型语言经验的程序员,可能会想着如何在python判断数据类型是什么?但是这样的思路在使用python的时候是不合适的,在代码中检测数据类型,实际上会破坏python的灵活性。虽然python中的type()函数提供了类型判断的功能,但是不建议使用。下面看一个例子,它就体现了python的灵活性。

s = "123"
num = 123

print(type(s))
print(type(num))

s = 123
num = "123"
print(type(s))
print(type(num))

程序执行结果如下:

<class 'str'>
<class 'int'>
<class 'int'>
<class 'str'>

变量,对象和表达式

作为一名有经验的C程序员,在编写python程序的时候,要习惯python中变量不一样的地方。

  1. 变量在第一次赋值的时候会被创建出来;
  2. 变量在使用之前必须被赋值(必须存在这个变量);
  3. 变量引用的是对象;
  4. 变量没有数据类型,有数据类型的是对象。
  5. 变量在表达式中出现的时候,它会被其所引用的对象的值所取代。

总结来说,python里的变量实际上就是一个void *指针(通用类型指针),这个指针指向的是对象。只不过我们在使用的时候不需要解引用。而且这个指针指向的对象还可以改变。(这和C++的引用是完全不同的)
对象知道自己的类型,每个对象都包含一个头部信息,其中的类型标志符标记了这个对象的类型,其中的引用计数器决定何时回收这个对象。

垃圾回收

在python中,每当一个变量名被赋予一个新对象,如果原来的对象没有被其他变量或者对象引用,那么之前的那个对象所占用的内存空间就会被回收。这种自动回收对象空间的技术叫作垃圾回收。得益于垃圾回收机制,python程序员无需手动管理内存,这使得python程序员的工作得到了很大的简化。
在python的实现中,每个对象的头部都有一个引用计数器,它记录了该对象的引用数目,一旦计数器被设为0,那么这个对象的内存空间就会被回收。
在python这里有个问题是集合这样的数据类型本身是一个容器,他可以容纳任何数据类型。所有就会有下面这样的代码出现。

>>> a = [1,2,3]
>>> a.append(a)

这个时候,循环引用就出现了,这样的对象的引用计数器不会为0,必须进行特别处理。
不过这点不用我们担心,python默认是可以回收循环引用的对象。

共享引用

共享引用在python里是指多个变量引用了同一个对象。在看例子之前,我们首先介绍一个函数id()。
id()返回的是对象的“身份证号”,唯一且不变。一个对象的id值在CPython解释器里就代表它在内存中的地址。
下面,我们来看一个例子:

>>> a = 1
>>> b = 1
>>> id(a)
9788992
>>> id(b)
9788992

这个例子中,变量a和变量b所引用的对象的id是一致的,这就是共享引用。注意,a和b本身并没有什么关联。当然了,在python里变量之间是不可能有引用关系的。下面改变b变量所引用的对象,效果如下:

>>> b = '123'
>>> id(a)
9788992
>>> id(b)
140352439347888

这就是python的特殊之处,变量本身不是某个内存地址的标签,变量本身应当是类似void *类型的指针。给变量赋新值,就是改变变量所指向的对象,而不是改变原来对象。事实上,刚才的b指向的对象3是整形,而整形是不可变类型,你根本没有办法改变它。
需要注意的是对可变对象的共享引用,这可能会造成你预期之外的结果。例如:

>>> list1 = [1,2,3]
>>> list2 = list1
>>> id(list1)
140352439347392
>>> id(list2)
140352439347392
>>> list2[0] = 0
>>> list1
[0, 2, 3]
>>> list2
[0, 2, 3]
>>> id(list2)
140352439347392
>>> id(list1)
140352439347392

可以看到,list1和list2共享引用,但是由于列表是可变对象,可以改变其中的值。但是这并没有改变它们是共享引用。所以,list1和list2的结果都发生了改变。这种效果对于习惯了C/C++编程的人而言,一开始是不太习惯的,经历过几次这样的错误就好了。如果你真的想让list1和list2指向的对象不同,那么你可以使用复制对象来解决这个问题。例如:

>>> list1 = [1,2,3]
>>> list2 = list1.copy()
>>> id(list2)
140352438351616
>>> id(list1)
140352439347392

这样做了对象复制之后,list1和list2就会指向不同的对象。复制一个对象还可以将原来的对象传入相应的构造函数中,例如:

>>> list1 = [1,2,3]
>>> list2 = list(list1)
>>> id(list1)
140352438324288
>>> id(list2)
140352438560704

字典和列表也可以使用copy或者构造函数方式来复制原来的对象。复制一个对象方法有很多,这不是重点,重点是python的可变对象的共享引用是较为特殊,尤其是对习惯了C/C++的人而言。

共享引用和相等

首先,python解释器有时候并不会马上回收一个不再使用的对象,python会缓存并复用小的整数和小的字符串,缓存机制并不会影响代码。但是大多数的对象都是在不被引用的时候立即回收的。
基于python的引用模型,python中有两种方法去检测是否相等。例如:

>>> list1 = [1,2,3]
>>> list2 = list1
>>> list1 == list2    #比较值是否相等
True
>>> list1 is list2    #检测是否是同一个对象
True

在这里,由于list1和list2引用的是同一个对象,所以值是相同的。下面的另一个例子则说明了不同之处。

>>> list1 = [1,2,3]
>>> list2 = [1,2,3]
>>> list1 == list2    #比较值是否相等
True
>>> list1 is list2    #检测是否是同一个对象
False

这个例子中,list1和list2引用的对象是不同的(因为python只会缓存并复用小的整数和小的字符串,列表并不会被缓存),但是两个对象的值相同的。最后,我们再来一个说明缓存效果会带来的不同之处。

>>> a = 1
>>> b = 1
>>> a == b
True
>>> a is b
True
  • ==:测试两个被引用的对象是否具有相同的值
  • is:测试两个变量是否引用的是同一个对象

因此,is可以作为测试共享应用的一种方式。
python中sys模块中的getrefcount()方法可以返回对象的引用次数,以数字对象1为例,其返回的引用次数高达199次。

>>> import sys
>>> sys.getrefcount(1)
199

这种方式也是python为了其执行速度而采用的众多优化方式中的一种。

python的这个引用,赋值模型是唯一的,它具有良好的一致性。作为比较对象的C++语言,它的语法一致性奇差。

标签:python,list1,list2,对象,风格,引用,动态,id
来源: https://blog.csdn.net/zy010101/article/details/117119772

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有