Python基础
Python语句中有一些基本规则和特殊字符
- #为注释符号。
- \为继续符号,可以将一行过长的语句用\分解成多行。
- ;分号用来在同一行分隔多条语句。
变量赋值
python语言中,等号(=)是主要的赋值运算符。
注意与C++不同的是,python中不支持++和–这样的自加/自减运算方式。
x=1
#链式赋值也是允许的
y=x=x+1
#增量赋值
x=x+1
x+=1
#多元赋值
x,y,z=1,2,'a string'
在交换两个变量的值时,C++通常需要使用一个中间变量来过渡。在python中,可以直接使用多元赋值的方式进行交换。
x,y=1,2
x,y=y,x
标识符
python3中一共有33个关键字标识符,大部分关键字的含义与其他编程语言中相同,对于每个关键字的详细解释可以参考连接。
关键字是不能用作
除了关键字以外,python还有可以在任何一级代码中使用的内建标识符。
python用下划线作为变量的前缀和后缀指定特殊变量:
- _xxx:不用 from module import *导入
- xxx:系统定义的名字
- __xxx:类中的私有变量名
一般来说,下划线对于解释器有特殊的意义,所以在命名普通变量时,需要避免使用下划线,对于类中的私有变量,则可以使用__xxx。
python代码编写风格
对于python代码,除了注释、文档、缩进,使用如下的布局可以建立一种统一易读的结构(https://mangoroom.cn/amp/typical-python-file-structure.html):
- 起始行(Unix)
- 模块文档:简要介绍功能以及全局变量的含义
- 模块导入:导入当前模块代码所需要的其他模块
- 变量定义:这里定义的变量为全局变量,所有函数都可以直接使用
- 类定义语句:定义类
- 函数定义语句:def
- 主程序:if name == ‘main’ :
- __name__指示模块应该如何被加载:当在模块中import另一模块时,此时并不需要执行另一模块的主程序,通过__name__就可以判断出此时模块是被导入还是被直接执行。
对于测试,python标准库中提供了unittest测试框架进行单元测试。
内存管理
与C/C++等不同的是,python在声明变量时,不需要显式的声明名称和类型,变量在第一次被赋值时将会自动声明。(简单来说就是直接赋值即可)
在当我们为变量分配内存时,是从系统资源中申请,在当变量时候结束后需要归还相应的资源。在C++中,可以通过new/delete等方式进行资源的申请与回收。在python中,解释器承担了这些内存管理的任务,所以在python中,无需考虑这些底层问题。
要保持追踪追踪内存中的对象,python使用了引用计数这一技术(与C++中的shared_ptr相仿)。当对象被创建时,引用计数为1,当引用计数为0时,回收对象。
引用计数会通过将同一对象赋值给其他变量,或作为参数传递给函数时增加。
x=3.14
y=x
第一句创建了float对象并将其引用赋值给x,那么此时x是第一个引用。
第二句y并没有创建新的对象,而是创建了一个指向同一对象的别名y,引用计数+1。
通过运行下面的代码,可以验证,两次print出的id是相同的,即y并没有申请新的内存,而是直接对于x所引用的对象创建了别名
x=3.14
y=x
print(id(x))
print(id(y))
当对象被销毁时,引用计数减少,例如当引用离开作用域时(函数结束),所有局部变量销毁,对象的引用计数也跟随者减少。
当变量被赋值给另外一个对象时,原对象的引用计数也会减一。
foo='xyz'
bar=foo
foo=123
其他造成引用计数减少的方式包括:
- 使用del语句删除一个变量
- del obj[, obj]会删除对象的一个引用
- 对象被从一个窗口对象中删除
- myList.remove(x)
对象的引用计数为0后,会被执行垃圾回收(GC)。垃圾收集器负责释放内存,是一块独立的代码,用于寻找引用计数为0的对象,它也负责寻找那些虽然引用计数大于0的但也需要销毁的对象。
循环引用(类似于C++中):当你至少有两个对象互相引用时,这两个对象的引用计数将永远不会为0。Python的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器。当一个对象的引用计数变为0,解释器会暂停,释放掉这个对象和仅有这个对象可访问(可到达)的对象。垃圾收集器同样也会留心被分配的总量很大的对象。
第一个python程序:创建文档/读取文档
# 提示用户输入一个不存在的文件名,然后有用户输入改文件的每一行,最后将所有文本写入文本文件
import os
# 为os.linesep创建别名,因为os.linesep解释器将会做两次查找,浪费资源。os.linesep的含义是给出当前编译平台的终止符
ls=os.linesep
# 输入文件名称
while True:
fname=input('input a filename: ')
if os.path.exists(fname):
print("The "+fname+" is already existed")
else:
break
# 输入文本内容
all=[]
print('enter lines, quit with .')
while True:
entry=input('>')
if entry=='.':
break
else:
all.append(entry)
fobj=open(fname,'w')
# 列表解析,将列表all中的每一项元素,与ls(结束符)重新组合为新的字符串,将此字符串作为参数写入fobj
fobj.writelines('%s%s'%(x,ls)for x in all)
fobj.close()
print('DONE')
一些将来可能会用到的模块
- Debugger: pdbv
- Logger: logging
- Profilers: profile, hotshot, cprofile
Python对象
在前面的学习中,反复提到对象一词,对象作为python的核心,本节将重点讨论。
对象
所有的python对象都拥有三个特性:
- 身份:每个对象都有一个唯一身份标识,任何对象的身份都可以使用内建函数id()来得到。这个值可以被认为是该对象的内存地址。
- 类型:类型决定了该对象可以保存什么类型的值,进行什么样的啊哦做,遵循什么规则,可以通过type()来查看对象的类型。
- 值:数据项
标准类型
在第一章中有提到过,标准类型包括:整形、布尔型、长整型、浮点型、复数型、字符串、列表、元组、字典
内建类型
做python开发时可能会用到的一些类型。
- 类型:类型对象不能只是一个简单字符串,这些信息不能也不应该与数据保存在一起。
- type(42) 将会得到结果 <class ‘int’>
- type(type(42) )将会得到结果<class ‘type’>
- None:与None类型最接近的就是C语言中的void,None类型的值与其他语言中的NULL相似。None的布尔值总是False(任何空对象或值为0的的任何数字都是False)。
- 文件
- 集合/固定集合
- 函数/方法
- 模块
- 类
内部类型
- 代码:代码对象是编译过的python源代码片段,是可执行对象。通过调用内建函数compile()可以得到代码对象,代码对象可以被exec命令或eval()函数来执行,后续章节会详细讨论。
- 帧:帧对象表示python的执行栈帧。帧对象包含python解释器在运行时所需要知道的所有信息。它的属性包括指向上一帧的链接、正在被执行的代码、本地及全局名字空间字典以及当前指令等。每次函数调用产生一个新的帧,每一个帧对象都会相应的创建一个C栈帧。用到帧对象的一个地方就是跟踪记录对象。
- 跟踪记录:当代码发生异常,解释器会退出脚本运行,显示诊断信息。当异常发生时,栈跟踪信息对象会被创建,如果一个异常有自己的处理程序,处理程序就会访问这个跟踪记录对象。
- 切片对象:当使用切片语法时产生,包括步进切片、多维切片、省略切片等。
- 省略对象
- XRange对象:调用xrange()函数时生成,xrange()类似range(),用于节省内存。
标准类型运算符
- 值比较:python中所有内建类型均支持比较运算,比较运算返回True/False。比较运算的运算规则根据类型而定,例如数字之间按照大小和符号,字符串之间按照字符序列比较。不同类型之间无法比较,例如1<‘str’,但浮点数和整数之间可以。
- python中多个比较运算可以在同一行进行:3<4<7
- 身份比较:通过is和not,例如当i=1, j=1时,两者实际指向同一对象,那么此时i is j =true
- 值得注意的是,在第二版书中提到python仅缓存简单整数。经过我自己试验发现,在python shell中结果与书上相同。但在pycharm中的python脚本中,却得到不同结果,运行脚本时浮点数也得到了缓存。
- 布尔类型比较:and、or、not,与其他语言中类似。
标准类型内建函数
- type():接收一个对象作为参数,并返回对象的类型。
- cmp():接收两个对象作为参数,如果obj1>obj2则返回正整数,也可以用于自定义的类型(后续章节讨论)。
- str()、repr()、’ ‘运算符:三种将对象转化为字符串的方法,其中repr()和’ '运算符完全相同,而str()可读性更高。
- isinstance():python不支持函数重载,因此必须保证调用的就是需要的函数或对象。type()函数可以帮助确定这一点,其次python中提供isinstance()函数,这个函数接收一个或多个对象和类型的元组作为参数,可以在一次函数调用中判断多个对象是否符合一个或多个类型。
标准类型的分类
- 存储模型:列表、元组、字典。字符串在python中并不是一个容器,因为python中并没有char类型。
- 更新模型:
- 可变:列表、字典
- 不可变:数字、字符串、元组。这里的不可变是指在更新数据之后,对象是否发生改变。例如i=1; i=5在第二次对i进行赋值的过程,i所引用的对象发生了改变。
- 访问模型:根据访问存储的数据的方式对数据类型进行分类
- 直接存取:数字
- 顺序:字符串、列表、元组(可以通过下标顺序访问)
- 映射:字典
Python中不支持的类型
char、byte、指针,学习python时可以暂时忘记这几个概念。
关于int、short、long,python中将整数与长整数融合,所以在使用时并不需要考虑范围。
python中的float类型实际相当于C中的double类型,因为python认为同时支持两种浮点类型的开销过大,开销与好处不符。
下一章节将讨论python中的数值对象及其使用。