Python3基本用法 2020.2.20
Python3简介
Python是一个高层次的结合了解释性、编译性、互动型和面向对象的脚本语言。
Python的设计具有很强的可读
%8.5f格式说明符表示输出为宽度为8、小数点后保留5位小数的浮点数。性,相比其他语言经常使用的一些标点符号,它具有比其它语言更有特色的语法结构。
- Python是一种解释型语言:没有编译这个环节
- Python是交互式语言:可以在
>>>
后执行代码 - Python是面向对象的语言
- Python是初学者语言:支持广泛的应用程序开发
Python3发展历史
Python 是由 Guido van Rossum 在八十年代末和九十年代初,在荷兰国家数学和计算机科学研究所设计出来的。
Python 本身也是由诸多其他语言发展而来的,这包括 ABC、Modula-3、C、C++、Algol-68、SmallTalk、Unix shell 和其他的脚本语言等等。
像 Perl 语言一样,Python 源代码同样遵循 GPL(GNU General Public License)协议。
现在 Python 是由一个核心开发团队在维护,Guido van Rossum 仍然占据着至关重要的作用,指导其进展。
Python 2.0 于 2000 年 10 月 16 日发布,增加了实现完整的垃圾回收,并且支持 Unicode。
Python 3.0 于 2008 年 12 月 3 日发布,此版不完全兼容之前的 Python 源代码。不过,很多新特性后来也被移植到旧的Python 2.6/2.7版本。
Python 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。
Python 2.7 被确定为最后一个 Python 2.x 版本,它除了支持 Python 2.x 语法外,还支持部分 Python 3.1 语法
Python3特点
- 易于学习:Python有较少的关键字,结构简单,和一个明却定义的语法,学习起来更简单。
- 易于阅读:Python代码定义的更清晰。
- 易于维护:Python的成功在于它的源代码是相当容易维护的。
- 一个广泛的标准库:Python的最大的优势之一是丰富的库,跨平台的,在UNIX,Windows和Macintosh兼容很好。
- 互动模式:互动模式的支持,可以在终端输入执行代码并或得结果的语言,互动的测试和调试代码片段。
- 可移植:基于其开放源代码的特性,Python已经被移殖到很多平台。
- 可扩展:如果你需要一段运行很快的关键代码,或者想要编写一些不愿开放的算法,你可以使用C或者C++完成那部分程序,然后从你的Python程序中调用。
- 数据库:Python提供所有主要的商业数据库的接口。
- GUI编程:Python支持GUI可以创建和移殖到许多系统调用。
- 可嵌入:你可以将Python嵌入到C/C++程序,让你的程序的用户获得“脚本化”的能力。
Python3基础语法
标识符
- 第一个字符必须为英文字母或者下划线组成。
- 标识符的其他部分由字母,数字和下划线组成。
- 标识符对大小写敏感。
- Python可以使用中文作为变量名,非ASCII标识符也允许。
保留字
保留字即关键字,不能用作标识符名称,Python的标准库提供了一个keyword模块,可以输出当前版本的关键字:
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
注释
Python中单行注释以#
开头,例如:
#注释
print("hello python!")#第二个注释
输出:hello python!
多行注释
多行注释可以用多个#
号,还有'''
和"""
,例如:
#第一个注释
#第二个注释
'''
第三个注释
第四个注释
'''
"""
第五个注释
第六个注释
"""
print("hello python!")
输出:hello python!
行与缩进
python最具特色的就是使用缩进来表示代码块,不需要使用大括号{}
。
缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数,例如:
if True:
print("True")
else:
print("False")
输出:True
以下代码最后一行语句缩进数的空格数不一致,会导致运行错误:
if True:
print("Answer")
print("True")
else:
print("Answer")
print("False")#缩进不一致,会导致运行错误
多行语句
Python通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠/
来实现多行语句,例如:
total = item_one + \
item_two + \
item_three
在[]
,{}
,或者()
中的多行语句,不需要使用反斜杠,例如:
total = ['item_one', 'item_two','item_three','item_four', 'item_five']
数字(Number)类型
Python中数字有四种类型:整形、布尔型、浮点数和复数。
- int,表示长整形
- bool,布尔表达式
- float,浮点数
- complex,复数
字符串(String)
- Python中单引号和双引号使用完全相同。
- 使用
'''
或"""
可以指定一个多行字符串。 - 转义符号
\
可以用来转义,使用r可以让反斜杠不发生转义。例如r"this is line \n",并不是换行。 - 按字面意义级连字符串,如"this"“is”"string"会被自动转换成this is string。
- 字符串可以用
+
号连接在一起,用*
运算符重复。 - Python中的字符串有两种索引方式,从左往右以-1开始。
- Python中的字符串不能改变。
- Python没有单独的字符类型,一个字符串就是长度为1的字符串。
- 字符串的截取的语法格式如:
变量[头下标:尾下标:步长]
案例:
#!/usr/bin/python3
str='qifen'
print(str)#输出字符串
print(str[0:-1])#输出第一个到倒数第二个的所有字符
print(str[0])#输出字符串第一个字符
print(str[2:4])#输出字符串第三个到第四个字符
print(str[2:])#输出第三个后的所有字符
print(str * 2)#输出字符串两次
print(str + '你好')#连接字符串
输出:
qifen
qife
q
fe
fen
qifenqifen
qifen你好
空行
- 函数之间或类的方法之间用空行分隔,表示一段代码的开始。类和函数入口之间也用一行空行进行分隔,以突出函数入口的开始。
- 空行与代码缩进不同,空行并不是Python语法的一部分。书写时不插入空行,Python解释器运行也不会报错。但是空行的作用在于分隔两段不同的代码,便于日后代码的维护或者重构。
- 空行也是程序代码的一部分。
等待用户输入
执行input函数在按回车键后就会等待用户输入,例如:
#!/usr/bin/python3
input("按下enter键后退出。")
同一行显示多条语句
Python可以在同一行中使用多条语句,语句之间用;
分割,例如:
#!/usr/bin/python3
import sys; x='qifen'; sys.stdout.write(x + '\n')
使用脚本执行以上代码,输出结果为:qifen
使用交互式命令行执行,输出结果为:
>>> import sys; x='qifen'; sys.stdout.write(x + '\n')
5
此处的5表示字符数。
多个语句构成代码组
缩进相同的一组语句构成一个代码块,我们称之为代码组。
像if、while、def和class这样的复合语句,首行以关键字开始,以冒号:
结束,该行之后的一行或多行代码构成代码组。我们将首行及后面的代码组成为一个字句(clause),例如:
if expression :
suite
elif expression :
suite
else :
suite
Print输出
print默认输出是换行的,如果要实现不换行需要在变量末尾加上end=""
,例如:
#!/usr/bin/python3
x="3"
y="b"
print(x)
print(y)
print("------")
print(x,end="")
print(y,end="")
print()
输出:
3
b
------
3b
import与from…import
在python用import
或者from...import
来导入相应的模块。
将整个模块(somemodule)导入,格式为:import somemodule
从某个模块中导入某个函数,格式为:from somemodule import somefunction
从某个模块中导入多个函数,格式为:from somemodule import firstfunc,secondfunc,thirdfunc
将某个模块中的全部函数导入,格式为:from somemodule import *
例如:
import sys #导入sys模块
print('命令行参数为:')
for i in sys.argv:
print(i)
print('\n python路径为:',sys.path)
导入sys模块的argv,path成员
from sys import argv,path #导入特定成员
print('path:',path)
命令行参数
很多程序可以执行一些操作来查看一些基本信息,Python可以使用-h参数查看各参数的帮助信息
Python3基本数据类型
Python中的变量不需要声明。每个变量在使用前必须赋值以后该变量才会被创建。
在Python中,变量就是变量,它没有类型,我们所说的“类型”是变量1所指的内存中对象的值。
等号运算符左边是一个变量名,等号右边是存储在变量中的值,例如:
#!/usr/bin/python3
counter=100#整形变量
miles=1000。0#浮点型变量
name='qifen'#字符串
print(counter)
print(miles)
print(name)
输出:
100
1000.0
qifen
多个变量赋值
Python允许你同时为多个变量赋值。例如:
a = b = c = 1
以上实例,创建一个整型对象,值为1,从后向前赋值,三个变量被赋予相同的数值。
可以为多个对象指定多个变量。例如:
a, b, c = 1, 2, "qifen"
以上实例,两个整形对象1和2的分配给变量a和b,字符串对象“qifen”分配给变量c。
标准数据类型
Python3中有六个标准的数据类型:
- Number(数字)
- String(字符串)
- List(列表)
- Tuple(元组)
- Set(集合)
- Dictionary(字典)
Python3的六个标准数据类型中: - 不可变数据(3个):Number、String、Tuple。
- 可变类型(3个):List、Dictionary、Set。
Number(数字)
Python3支持int、float、bool、complex(复数)。
在Python3里,只有一种整型类型int,表示为长整型,没有Python2中的Long。
像大多数语言一样,数值类型的赋值和计算都是很直观的。
内置的type()函数可以用来查询变量所指的对象类型,例如:
>>> a, b, c, d = 20, 5.5, True, 4+3j
>>> print(type(a),type(b),type(c),type(d))
<class 'int'> <class 'float'> <class 'bool'> <class 'complex'>
此外还可以用isinstance来判断,例如:
>>>a = 11
>>> isinstance(a, int)
True
>>>
isinstance和type的区别在于:
- type()不会认为子类是一种父类类型。
- isinstance()会认为子类是一种父类类型。
>>> class A:
... pass
...
>>> class B(A):
... pass
...
>>> isinstance(A(),A)
True
>>> type(A())==A
True
>>> type(B())==A
False
注意:在Python2中是没有布尔型的,它的数字0表示False,用1表示True。到Python3中,把True和False定义为关键字了,但它们的值还是1和0,他们可以和数字相加。
当你指定一个值时,Number对象就会被创建:
var1 = 1
var2 = 10
可以使用del删除一些对象引用,例如:
del var
del var_a, var_b
数值运算
案例:
>>>5 + 4 #加法
9
>>>4.3 - 2 #减法
2.3
>>>3 * 7 #乘法
21
>>>2 / 4 #除法,得到一个整数
0
>>>17 % 3 #取余
2
>>>2 ** 5 #乘方
32
注意:
- Python可以同时为多个变量赋值,如a, b=1, 2。
- 一个变量可以通过赋值指向不同类型的对象。
- 数值的除法包含两个运算符:
/
返回一个浮点数,//
返回一个整数。 - 在混合计算时,Python会把整形转换为浮点数。
String(字符串)
Python中的字符串用单引号'
和双引号"
阔起来,同时使用反斜杠\
转义特殊字符。
索引值以0开始值,-1为从尾部的开始位置,字符串截取的语法格式如下:
变量[头标签:尾标签]
加号+
是字符串的连接符,星号*
表示复制当前字符串,与之结合的数字为复制的次数。
Python使用反斜杠\
转义特殊字符,如果你不想让反斜杠发生转义,可以在字符串前面添加一个r,表示原始字符串,例如:
>>> print('qife\nn')
qife
n
>>> print(r'qife\nn')
qife\nn
另外,反斜杠\
可以作为续行符,表示下一行是上一行的延续。也可以使用"""…"""或者’’’…’’'跨越多行。
注意,Python没有单独的字符类型,一个字符就是长度为1的字符串,案例:
>>>word = 'python'
>>>print(word[0], word[5])
p n
>>>print(word[-1], word[-6])
n p
与C字符串不同的是,Python字符串不能被改变,向一个索引位置赋值,比如word[0]='m’会报错。
注意:
- 反斜杠可以用来转义,使用r可以让反斜杠不发生转义。
- 字符串可以用+运算符连接在一起,用*运算符重复。
- Python中的字符串有两种索引方式,从左往右以0开始,从右往左以-1开始。
- Python中的字符串不能改变。
List(列表)
List(列表)是Python中使用最频繁的数据类型。
列表可以完成大多数集合类的数据结构实现。列表中元素类型可以不相同,它支持数字、字符串甚至可以包含列表(所谓嵌套)。
列表是写在方括号[]
之间、用逗号分隔的元素列表。
和字符串一样,列表同样可以被索引和截取,列表被截取后返回一个包含所需元素的新列表,列表截取的语法格式如下:
变量[头下标:尾下标]
索引以0为开始值,-1为从末尾的开始位置,加号+
是列表连接运算符,星号*
是重复操作,例如:
#!/usr/bin/python3
list = ['abc', 123, 4.56, 'qifen', 78.9]
tinylist = [123, 'qifen']
print(list)#输出完整列表
print(list[0])#输出列表第一个元素
print(list[1:3])#输出第二个元素到第三个元素
print(list[2:])#输出从第三个元素的所有元素
print(tinylist * 2)#输出两次列表
print(list + tinylist)#连接列表
输出:
['abc', 123, 4.56, 'qifen', 78.9]
abc
[123, 4.56]
[4.56, 'qifen', 78.9]
[123, 'qifen', 123, 'qifen']
['abc', 123, 4.56, 'qifen', 78.9, 123, 'qifen']
与Python字符串不同的是,列表中的元素是可以改变的:
>>>a = [1, 2, 3, 4, 5, 6,]
>>>a[0] = 9
>>>a[2:5] = [13, 14, 15]
>>>a
[9, 2, 13, 14, 15]
>>>a[2:5] = [] #将对应的元素值设置为[]
>>>a
[9, 2, 6]
注意:
- List写在括号之间,元素用逗号隔开。
- 和字符串一样,list可以被索引和切片。
- List可以使用+操作符进行拼接。
- List中的元素是可以被改变的
Python列表截取可以接收第三个参数,参数作用是截取的步长,例如:
>>>list=['a','b','c','d','e','f']
>>>list[1:4:2]
['b', 'd']
如果第三个参数为复数表示逆向读取,例如:
#!/usr/bin/python3
def reverseWords(input):
#通过空格分隔符,把各个单词分隔为列表
inputWords = input.split(" ")
#翻转字符串
#假设列表list = [1,2,3,4]
#inputWords[-1::-1]有三个参数
#第一个参数-1表示最后一个参数
#第二个参数为空表示移动到列表的末尾
#第三个参数为步长-1表示逆向
inputWords = inputWords[-1::-1]
#重新组合字符串
output = ' '.join(inputWords)
return output
if __name__ == "__main__":
input = 'I like qifen'
rw = reverseWords(input)
print(rw)
输出:qifen like I
Tuple(元组)
元组(Tuple)与列表类似,不同之处在于元组不能修改。元组写在小括号里()
里,元素之间用逗号隔开。
元组中的元素类型也可以不相同,例如:
#!/usr/bin/python3
tuple = ('abc', 456, 7.89, 'qifen', 34.5)
tinytuple = (123, 'qifen')
print(tuple)
print(tuple[0])
print(tuple[1:3])
print(tuple[2:])
print(tinytuple * 2)
print(tuple + tinytuple)
输出:
('abc', 456, 7.89, 'qifen', 34.5)
abc
(456, 7.89)
(7.89, 'qifen', 34.5)
(123, 'qifen', 123, 'qifen')
('abc', 456, 7.89, 'qifen', 34.5, 123, 'qifen')
元组与字符串类似,可以被索引且下标索引从0开始,-1为从为末尾开始的位置。也可以进行截取。
其实可以把字符串看作一种特殊的元组:
>>>tup = (1, 2, 3, 4, 5, 6)
>>>print(tup[0])
1
>>>print(tup[1:5])
(2, 3, 4, 5)
>>>tup[0] = 11#修改元组元素的操作是非法的
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
虽然tuple的元素不可改变,但它可以包含可变的对象,比如list列表。
构造包含0个或者1个元素的元组比较特殊,所以有一些额外的语法规则:
tup1 = ()#空元组
tup2 = (20,)#一个元素,需要在元素后添加逗号
string、list和tuple都属于sequence(序列)。
注意:
- 与字符串一样,元组的元素不能修改。
- 元组也可以被索引和切片,方法一样。
- 注意构造包含0或者1个元素的元组的特殊语法规则。
- 元组也可以使用+操作符进行拼接。
Set(集合)
集合(set)是由一个或者数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。
基本功能是进行成员关系测试和删除重复元素。
可以使用大括号{}
或者set()
函数创建集合,注意:创建一个空集合必须用set(),而不是用{},因为{}是用来创建一个空字典。
创建格式:
parame = {value0, value2}
或者
set(value)
例如:
#!/usr/bin/python3
student = {'Tom', 'Jim', 'Mary', 'Jack', 'Rose'}
print(student)#输出集合,重复的元素被自动去除
#成员测试
if 'Rose' in student :
print('Rose 在集合中')
else :
print('Rose 不在集合中')
#set可以进行集合运算
a = set('abcdef')
b = set('abc')
print(a)
print(a - b)#a和b的差集
print(a | b)#a和b的并集
print(a & b)#a和b的交集
print(a ^ b)#a和b中不同时存在的元素
输出:
{'Rose', 'Jim', 'Mary', 'Tom', 'Jack'}
Rose 在集合中
{'a', 'f', 'd', 'b', 'e', 'c'}
{'d', 'e', 'f'}
{'b', 'e', 'c', 'a', 'f', 'd'}
{'b', 'c', 'a'}
{'f', 'd', 'e'}
Dictionary(字典)
字典(dictionary)是Python中另一个非常有用的内置数据类型。
列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。
字典是一种映射类型,字典用{}
标识,它是一个无序的键(key):值(value)
的集合。
键(key)必须使用不可变类型。
在一个字典中,键(key)必须唯一,例如:
#!/usr/bin/python3
dict = {}
dict['one'] = "qifen"
dict[2] = "duck"
tinydict = {'name':'qifen', 'code':1, 'site':'duck'}
print(dict['one'])#输出键为'one'的值
print(dict[2])#输出键为2的值
print(tinydict)#输出完整的字典
print(tinydict.keys())#输出所有键
print(tinydict.value())#输出所有值
输出:
qifen
duck
{'name': 'qifen', 'code': 1, 'site': 'duck'}
dict_keys(['name', 'code', 'site'])
dict_values(['qifen', 1, 'duck'])
构造函数dict()可以直接从键值对序列中构建字典,例如:
>>>dict([('qifen', 1), ('duck', 2), ('gogs', 3)])
{'qifen':3, 'duck':2, 'gogs',3}
>>>{x:x**2 for x in (2, 4, 6)}
{2:4, 4:16, 6:36}
>>>dict(qifen=1, duck=2, gogs=3)
{'qifen':1, 'duck':2, 'gogs':3}
另外,字典类型也有一些内置的函数,例如clear()、values()等。
注意:
- 字典是一种映射类型,它的元素是键值对。
- 字典的关键字必须为不可变类型,且不能重复。
- 创建空字典使用
{}
。
Python数据类型转换
函数 | 描述 |
---|---|
int(x [,y]) | 第一个参数时是转换为整型,第二个参数是转换进制数,可只用一个参数来转换数值类型 |
float(x) | 将x转换为一个浮点数 |
complex(x,y) | 创建一个复数 |
str(x) | 将对象x转换为字符串 |
repr(x) | 将对象x转换为表达式字符串 |
eval(str) | 用来计算在字符串中的有效Python表达式,并返回一个对象 |
tuple(s) | 将序列s转换为一个元组 |
list(s) | 将序列s转换为一个列表 |
set(s) | 转换为可变集合 |
dict(d) | 创建一个字典,d必须是一个(key,value)元组序列 |
frozenset(s) | 转换为不可变集合 |
chr(x) | 将一个整数转换为一个字符 |
ord(x) | 将一个字符转换为它的整数值 |
hex(x) | 将一个整数转换为一个十六进制字符串 |
oct(x) | 将一个整数转换为一个八进制字符串 |
Python3解释器
Linux/Unix的系统上,,一般默认的python版本为2.x,我们可以将python3.x安装在/usr/local/python3目录中。安装完成后,我们可以将路径/usr/local/python3/bin
添加到Linux/Unix操作系统的环境变量中,这样您就可以通过shell终端输入下面的命令来启动Python3。
$ PATH=$PATH:/usr/local/python3/bin/python3 #设置环境变量
$ python3 --version #查看Python版本
Python 3.6.9
在Window系统下你可以通过以下命令来设置Python的环境变量,假设你的Python安装在C:\Python3下:
set path=%path%;C:\Python3
交互式编程
我们可以在命令提示符中输入"Python"命令来启动Python解释器,例如:
>>>print("hello world")
输出:hello world
当输入一个多行结构时,续行是必须的,我们可以看下如下if语句:
>>>flag = True
>>>if flag :
... print("flag 条件为 True!")
...
flag 条件为 True!
脚本式编程
创建hello.py,在里面写入:
print("hello world!")
命令执行该脚本python3 hello.py
输出:hello world!
在Linux/Unix系统中,你可以在脚本顶部添加以下命令让Python脚本像shell脚本一样可直接执行:
#! /usr/bin/env python3
然后修改脚本权限,使其具有可执行权限,命令如下:
$ chmod +x hello.py
执行以下命令:
./hello.py
输出:hello world!
Python3注释
确保对模块、函数、方法和行内注释使用正确的风,Python中的注释有单行注释和多行注释,单行注释用#
开头,例如:
#这是一个注释
print("hello world")
三个单引号注释'''
#!/usr/bin/python3
'''
这是多行注释,用三个单引号
这是多行注释,用三个单引号
这是多行注释,用三个单引号
'''
print("hello world!")
三个双引号注释"""
#!/usr/bin/python3
"""
这是多行注释,用三个单引号
这是多行注释,用三个单引号
这是多行注释,用三个单引号
"""
print("hello world!")
Python3运算符
Python语言支持以下类型的运算符:
- 算术运算符
- 比较(关系)运算符
- 赋值运算符
- 逻辑运算符
- 位运算符
- 成员运算符
- 身份运算符
- 运算符优先级
Python算术运算符
以下假设变量a为10,变量b为21:
运算符 | 描述 | 实例 |
---|---|---|
+ | 加-两个对象相加 | a + b输出31 |
- | 减-得到负数或是一个数减去另一个数 | a - b输出-11 |
* | 乘-两个数相乘或是返回一个被重复若干次的字符串 | a * b输出210 |
/ | 除-x除以y | b / a输出2.1 |
% | 取模-返回除法的余数 | b % a输出结果1 |
** | 幂-返回x的y次幂 | a ** b为10的21次方 |
// | 取整除-向下取接近除数的整数 | 9//2输出4,-9//2输出-5 |
Python比较运算符
以下假设变量a为10,变量b为20
运算符 | 描述 | 实例 |
---|---|---|
== | 等于-比较对象时候相等 | (a == b)返回False |
!= | 不等于-比较两个对象时候不相等 | (a != b)返回True |
> | 大于-返回x是否大于y | (a > b)返回False |
< | 小于-返回x是否小于y,所有比较运算符返回1表示真,0表示假 | (a < b)返回True |
>= | 大于等于-返回x是否大于等于y | (a >= b)返回False |
<= | 小于等于-返回x是否小于等于y | (a <= b)返回True |
Python赋值运算符
以下假设变量a为10,变量b为20:
运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为c |
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
%= | 取模赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c *= a 等效于 c = c * a |
//= | 取整除赋值运算符 | c = c // a |
:= | 海象运算符,可在表达式内部为变量赋值,Python3.8版本新增运算符 | 赋值表达式可以避免len()两次:if(n := len(a)) > 10 |
Python位运算符
按位运算符是把数字看作二进制来计算的,下表中变量a为60,b为13二进制格式如下:
a = 0011 1100
b = 0000 1101
a & b = 0000 1100 #&(按位与)两边都有1位才是1
a | b = 0011 1101 #|(按位或)两边都有0位才是0
a ^ b = 0011 0001 #^(按位异或)两边加上等于1位才为1
~a = 1100 0011 #~(按位取反)位等于0改为1
a << 2 = 1111 0000 #<<(左移运算)左移动位,右补0
a >> 2 = 0000 1111 #>>(右移运算)右移动位,左补0
运算符 | 描述 | 实例 |
---|---|---|
& | 按位与运算符:参与运算的两个值,如果两个相应位都是1,则该位的结果为1,否则为0 | (a & b)输出结果12,二进制解释:0000 1100 |
| | 按位或运算符:只要对应的两个二进制位有一个为1时,结果位就为1 | (a | b)输出结果61,二进制解释:0011 1101 |
^ | 按位异或运算符:当两对应的二进位相异时,结果为1 | (a ^ b)输出结果49,二进制解释:0011 0001 |
~ | 按位取反运算符:对数据的每个二进制取反,即把1变为0,把0变为1,~x 类似于-x-1 | (~a)输出-61,二进制解释:1100 0011,在一个有符号二进制数的补码形式 |
<< | 左移运算符:运算数的各二进制全部左移若干位,由"<<"右边的数指定移动位数,高位丢失,低位补0 | a << 2 输出结果240,二进制解释:1111 0000 |
>> | 右移运算符:把">>左边的运算符的各二进制位全部右移若干位,">>"右边的数指定移动的位数 | a >> 2 输出结果15,二进制解释:0000 1111 |
Python逻辑运算符
Python语言支持逻辑运算符,以下假设变量a为10,b为20:
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔“与”-如果x为False,x and y返回False,否则它返回y的计算值 | (a and b)返回20 |
or | x or y | 布尔“或”-如果x是True,它返回x的值 | (a or b)返回10 |
not | not x | 布尔“非”-如果x为True,返回True,如果x为True,它返回True | not(a and b)返回False |
Python成员运算符
除了以上的一些运算符之外,Python还支持成员变量运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回True,否则返回False | x在y序列中,如果x在y序列中返回True |
not in | 如果在指定的序列中没有找到值返回True,否则返回False | x不在y序列中,如果x不在y序列中返回True |
Python身份运算符
身份运算符用于比较两个对象的存储单元
运算符 | 描述 | 实例 |
---|---|---|
is | is是判断两个标识符是不是引用自一个对象 | x is y ,类似id(x) == id(y) ,如果引用的是同一个对象则返回True,否则返回False |
is not | is not是判断两个标识符是不是引用自不同对象 | x is not y ,类似id(a) != id(b),如果引用的不是同一个对象则返回True,否则返回False |
注:id()函数用于获取对象内存地址。
is和==区别
is用于判断两个变量引用对象是否为同一个,==用于判断引用变量的值是否相等。
>>>a = [1, 2, 3]
>>>b = a
>>>b is a
True
>>>b == a
True
>>>b = a[:]
>>>b is a
False
>>>b == a
True
Python运算优先级
以下表格优先级从高到低列出了所有运算符:
运算符 | 描述 |
---|---|
** | 指数(优先级最高) |
~ + - | 按位翻转,一元加减号 |
* / % // | 乘、除、求余数和取整除 |
+ - | 加法、减法 |
>> << | 右移、左移运算符 |
& | 位’AND’ |
^ | | 位运算符 |
>= > < <= | 比较运算符 |
== != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
is is not | 身份运算符 |
in not in | 成员运算符 |
not and or | 逻辑运算符 |
运算默认从右到左边
Python3数字(Number)
Python数字数据类型用于存储数值。
数据类型是不允许改编的,这就意味着如果改变数字类型的值,将重新分配内存空间。
以下实例在变量赋值时Number对象被创建:
var1 = 1
var2 = 10
你也可以使用del语句删除一些数字对象的引用。
del语句的语法是:
del var1[,var2[,var3[...,varN]]]
可以使用del语句删除单个或多个对象的引用,例如:
del var
del var_a, var_b, var_c
Python支持三种不同的数据类型:
- 整形(int)-通常被称为是整形或整数,是正数或者负数,不带小数点。Python3整型时没有限制大小的,可以作Long类型使用,所以Python3没有Python2的Long类型。
- 浮点数(float)-浮点数由整数部分与小数部分组成,浮点型也可以使用科学计数法表示(2.5e2 = 2.5 x 102 = 250)。
- 复数(complex)-复数由实体部分和虚数部分构成,可以用a + bj,或者complex(a, b)表示,复数的实体a和虚部b都是浮点数。
我们可以使用十六进制和八进制来代表整数:
>>>number = 0xA0F #十六进制
>>>number
2575
>>number = 0o37 #八进制
>>>number
31
- Python支持复数,复数由实数和虚数部分构成,可以用a + bj,或者complex(a, b)表示,复数的实部a和虚部b都浮点数。
Python数字类型转换
有时候,我们需要对数据内置的类型进行转换,数据类型的转换,你只需要将数据类型作为函数名即可。
- int(x)将x转换为一个整数。
- float(x)将x转换到一个浮点数。
- complex(x)将x转换到一个复数,实数部分为x,虚数部分为0。
- complex(x, y)将x和y转换到一个复数,实数部分为x,虚数部分为y。x和y是数字表达式。
以下实例将浮点数变量a转换为整数:
>>>a = 1.0
>>>int(a)
1
Python数学运算
Python解释器可以作为一个简单的计算器,可以在解释器里输入一个表达式,它将输出表达式的值。
表达式的语法很直白:+
、-
、*
、/
,和其它语言里一样。例如:
>>>2 + 2
4
>>>50 - 5 * 6
20
>>>(50 + 5 * 6)/4
5.0
>>>8 / 5
1.6
**注意:**在不同的机器上浮点运算结果可能会不一样。
在整数除法中,除法/
总是返回一个浮点数,如果只想得到整数的结果,丢弃可能的风俗部分,可以使用运算符//
:
>>>17 / 3 #整数除法返回浮点型
5.666666666666667
>>>17 // 3 #整数除法返回向下取整后的结果
5
>>>17 % 3 #%操作符返回除法的余数
2
>>>5 * 3 + 2
17
注意://
得到的并不一定是整数类型的数,它与分母分子的数据类型有关系。
>>>7 // 2
3
>>>7.0 // 2
3.0
>>>7 // 2.0
3.0
等号=
用于给变量赋值。赋值之后,除下一个提示符,解释器不会显示任何结果。
>>>width = 20
>>>height = 5 * 9
>>>width * height
900
Python可以使用**
操作来进行幂运算:
>>>5 ** 2 #5的平方
25
>>>2 ** 7 #2的7次方
128
变量在使用前必须先赋予变量一个值,否则出现错误:
>>>n #尝试访问一个未定义的变量
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'n' is not defined
不同类型的数混合运算时会将整数转换为浮点数:
>>>3 * 3.75 / 1.5
7.5
>>>7.0 / 2
3.5
在交互模式中,最后被输出的表达式结果被赋值给变量_
。例如:
>>>tax = 12.5 / 100
>>>price = 100.50
>>>price * tax
12.5625
>>>price + _
113.0625
>>>round(_, 2)
113.06
此处,_变量应被用户视为只读变量。
数学函数
函数 | 返回值(描述) |
---|---|
abs(x) | 返回数字的绝对值,如abs(-10)返回10 |
ceil(x) | 返回数字的上入整数,如math.ceil(4.1)返回5 |
cmp(x, y) | 如果x < y返回-1,如果x == y返回0,如果x > y返回1。Python3已经废弃,使用(x > y)-(x < y)替换 |
exp(x) | 返回e的x次幂,如math.exp(1)返回2.718281828459045 |
fabs(x) | 返回数字的绝对值,如math.fbs(-10)返回10.0 |
floor(x) | 返回数字的下舍整数,如math.floor(4.9)返回4 |
log(x) | 如math.log(math.e)返回1.0,math.log(100,10)返回2.0 |
max(x, y, z, …) | 返回给定参数的最大值,参数可以是序列 |
min(x, y, z, …) | 返回给定参数的最小值,参数可以为序列 |
modf(x) | 返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示 |
pow(x, y) | x ** y运算后的值 |
round(x [,n]) | 返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数。其实准确的说是保留值将保留到离上一位更近的一端 |
sqrt(x) | 返回数字x的平方根 |
随机数函数
随机数可以用于数学,游戏,安全等领域中,还经常被嵌入到算法中,可以提高函数算法效率,并提高程序的安全性。
Python包含以下常用随机数函数:
|函数|描述|
|choice(seq)|从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数|
|randrange([start,] stop [,step])|从指定范围内,按指定基数递增的集合中获取一个随机数,基数默认值1|
|random()|随机生成一个实数,它在[0, 1]范围内|
|seed([x])改变随机数生成器的种子seed,可以不必设置seed,Python会自动选择seed|
|shuffle(list)|将序列所有元素随机排序|
|uniform(x, y)|随机生成一个实数,它在[x, y]范围之内|
三角函数
Python包括以下三角函数:
函数 | 描述 |
---|---|
acos(x) | 返回x的反余弦弧度值 |
asin(x) | 返回x的反正弦弧度值 |
atan(x) | 返回x的反正切弧度值 |
atan2(y, x) | 返回给定的x及y坐标值的反正切值 |
cos(x) | 返回x的幅度的余弦值 |
hypot(x, y) | 返回鸥几里德范数sqrt(x * x + y * y) |
sin(x) | 返回x弧度的正弦值 |
tan(x) | 返回x弧度的正切值 |
degrees(x) | 将弧度转换为角度,如degrees(math.pi / 2),返回90。0 |
radians(x) | 将角度转换为弧度 |
数学常量
常量 | 描述 |
---|---|
pi | 数学常量pi(圆周率,一般以π来表示) |
e | 数学常量e,e即自然数(自然常数) |
Python3字符串
字符串是Python中最常用的数据类型,我们可以使用引号('
或"
)来创建字符串。
创建字符串分简单,只要为变量分配一个值即可。例如:
var1 = 'hello world!'
var2 = "qifen"
Python访问字符串中的值
Python不支持单字符类型,单字符在Python中也是作为一个字符使用。
Python访问子字符串,可以使用方括号来截取字符串,例如:
#!/usr/bin/python3
var1 = 'hello world!'
var2 = 'qifen'
print("var1[0]", var1[0])
print("var2[1:4]", var2[1:4])
输出:
var1[0] h
var2[1:4] ife
Python字符串更新
你可以截取字符串的一部分并与其他字段拼接,例如:
#!/usr/bin/python3
var1 = 'hello world!'
print("已更新字符串:", var1[:6]+'qifen')
输出:已更新字符串: hello qifen
Python转义字符
在需要在字符中使用特殊字符时,python用反斜杠\
转义字符。如下表:
转义字符 | 描述 |
---|---|
\(在行尾时) | 续行符 |
\\ | 反斜杠符号 |
\’ | 单引号 |
\" | 双引号 |
\a | 响铃 |
\b | 退格 |
\000 | 空 |
\n | 换行 |
\v | 纵向制表符 |
\t | 横向制表符 |
\r | 回车 |
\f | 换页 |
\oyy | 换页 |
\xyy | 八进制数,yy代表的字符,例如:\o12代表换行,o是字母 |
other | 其它的字符以普通格式输出 |
字符串运算符
下表实例变量a值为字符串"Hello",b变量值为"Python":
操作符 | 描述 | 实例 |
---|---|---|
+ | 字符串连接 | a + b输出结果:HelloPython |
* | 重复输出字符串 | a * 2输出结果:HelloHello |
[] | 通过索引获取字符串中字符 | a[1]输出e |
[:] | 截取字符串中的一部分,遵循着左闭右开原则,str[1, 2]是不包含第3个字符的 | a[1:4]输出ell |
in | 成员运算符-如果字符串中包含给定的字符返回True | ‘H’ in a输出True |
not in | 成员运算符-如果字符串中不包含给定的字符返回True | ‘M’ not in a输出结果True |
r / R | 原始字符串-所有的字符串都是直接按照字面的意思输出(转义无效) | r’\n’ 和 R’\n’,都输出\n |
% | 格式字符串 | todo |
Python字符串格式化
Python支持格式化字符串的输出,尽管这样可能会用到非常复杂的表达式,但最基本的用法是将一个值插入到一个有字符串格式符%s的字符串值中。
在Python中,字符串格式化使用与C中printf函数一样的语法。
#!/usr/bin/python3
print("我叫 %s 今年 %d 岁!"%('小明', 10))
输出:我叫 小明 今年 10 岁!
Python字符串格式化符号:
符号 | 描述 |
---|---|
%c | 格式化字符及其ASCII码 |
%s | 格式化字符串 |
%d | 格式化整数 |
%u | 格式化无符号整型 |
%o | 格式化无符号八进制数 |
%x | 格式化无符号十六进制 |
%X | 格式化无符号十六进制(大写) |
%f | 格式化浮点数,可 |
指定小数点后的精度 | |
%e | 用科学计数法格式化浮点数 |
%g | %f和%e的简写 |
%G | %f和%E的简写 |
%p | 用十六进制数格式化变量的地址 |
格式化操作符辅助指令:
符号 | 功能 |
---|---|
* | 定义宽度或者小数点精度 |
- | 用做左对齐 |
在正数前面显示空格 | |
# | 在八进制数前面显示(‘0’),在十六进制前面显示’0x’或者’0X’(取决于用的是’x’还是’X’) |
0 | 显示的数字前面填充’0’而不是默认的空格 |
% | ‘%%‘输出一个单一的’%’ |
(var) | 映射变量(字典参数) |
m.n. | m是显示的最小总宽度,n是小数点后的位数(如果可用的话) |
Python2.6开始,新增了一种格式化字符串的函数str.format(),它增强了字符串格式化的功能
Python三引号
#!/usr/bin/python3
para_str = """多行字符串
多行字符串可以使用\t制表符
也可以使用\n换行符
"""
print(para_str)
输出:
多行字符串
多行字符串可以使用 制表符
也可以使用
换行符
f-string
f-string是python3.6之后版本添加的,称之为字面量格式化字符串,是新的格式化字符串的语法,例如:
>>>name = 'qifen'
>>>'Hello %s' %name
Hello qifen
f-string格式化字符串以f开头,后面跟着字符串,字符串中的表达式用大括号{}包起来,它会将变量或表达式计算后的值替换进去,例如:
>>>name = 'qifen'
>>>f'Hello {name}' #替换变量
>>>f'{1 + 2}' #使用表达式
'3'
>>>w = {'name':'qifen', 'url':'www.qifen.site'}
>>>f'{w["name"]}:{w["url"]}'
'qifen:www.qifen.site'
在Python3.8的版本中可以用=
符号来拼接运算表达式与结果:
>>>x = 1
>>>print(f'{x+1}') #Python3.6
2
>>>x = 1
>>>print(f'{x+1=}') #Python3.8
'x+1=2'
Unicode字符串
在Python2中,普通字符串是以8位ASCII码进行存储的,而Unicode字符串则存储16位unicode字符串,这样能够表示更多的字符集,使用的语法是在字符串前面加上前缀u
。
在Python3中,所有的字符串都是Unicode字符串。
Python的字符串内建函数
Python的字符串常用内建函数如下:
函数 | 描述 |
---|---|
capitalize() | 将字符串的第一个字符转换为大写 |
center(width, fillchar) | 返回一个指定的宽width居中的字符串,fillchar为填充的字符,默认为空格。 |
count(str, beg=0, end=len(string)) | 返回str在string里面出现的次数,如果beg或者end指定则返回指定范围内str出现的次数。 |
bytes.decode(encoding=“utf-8”, errors = “strict”) | Python3中没有decode方法,但是我们可是使用bytes对象的decode()方法来解码给定的bytes对象,这个bytes对象可以由str.encode()来编码返回。 |
encode(encoding=‘UTF-8’, errors=‘strict’) | 以encoding指定的编码格式编码字符串,如果出错默认报一个ValueError的异常,除非errors指定的是’ignore’或者’replace’。 |
endsWith(suffix, beg=0, end=len(string)) | 检查字符串是否以obj结束,如果beg或者end指定则检查指定的范围内是否以obj结束,如果是,返回True,否则返回False。 |
expandtabs(tabsize=8) | 把字符串string中的tab符号转为空格,tab符号默认的空格数为8。 |
find(str, beg=0, end=len(string)) | 检测str是否包含在字符串中,如果指定范围内beg和end,则检查是否包含在指定范围内,如果包含返回开始的索引值,否则返回-1。 |
index(str, beg=0, end=len(string)) | 跟find方法一样,只不过如果str不在字符串中会报一个异常。 |
isalnum() | 如果字符串至少有一个字符并且所有字符都是字母数字则返回True,否则返回False。 |
isalpha() | 如果字符串至少有一个字符并且所有字符都是字母则返回True,否则返回False。 |
isdigit() | 如果字符串中只包含数字则返回True否则返回False。 |
islower() | 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回True,否返回False。 |
isnumeric() | 如果字符串中只包含数值字符,则返回True,否则返回False。 |
istitle() | 如果字符串是标题化的(见title())则返回True,否则返回False。 |
isspace() | 如果字符串中只包含空白,则返回True,否则返回False。 |
isupper() | 如果字符串中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回True,否则返回False。 |
join(seq) | 以指定字符串作为风格符,将seq中的所有元素(的字符串表示)合并为一个新的字符串。 |
len(string) | 返回字符串长度。 |
ljust(width [,fillchar]) | 返回一个原字符串左对齐,并使用fillchar填充至长度width的新字符串,fillchar默认为空格。 |
lower() | 转换字符串中所有大写字符为小写。 |
lstrip() | 截掉字符串左边的空格或指定字符串。 |
maketrans() | 创建字符映射的转换表,对于接受两个参数的最简单的调用方式,第一个参数是字符串,表示需要转换的字符,第二个参数也是字符串表示转换的目标。 |
min(str) | 返回字符串str中最小的字母。 |
max(str) | 返回字符串str中最大的字母。 |
replace(old, new [,max]) | 把将字符串中的str1替换成str2,如果max指定,则替换不超过max次。 |
rfind(str,beg=0, end=len(string)) | 类似于find()函数,不过是从右边开始查找。 |
rindex(str, beg=0, end=len(string)) | 类似于index(),只不过从右边开始。 |
rjust(width [,fillchar]) | 返回一个原字符右对齐,并使用fillchar(默认空格)填充至长度width的新字符串。 |
rstrip() | 删除字符串字符串末尾的空格。 |
split(str="", num=string, count(str)) | num=string.count(str)以str为分隔符截取字符串,如果num有指定值,则仅截取num+1个子字符串 |
splitlines([keepends]) | 按照行(’\r’,’\r\n’,’\n’)分隔,返回一个包含各行作为元素的列表,如果参数keepends为False,不包含换行符,如果为True,则保留换行符。 |
startWith(substr, beg=0, end=len(string)) | 检查字符串是否以指定子字符串substr开头,是则返回True,否则返回False,如果beg和end指定值,则在指定范围内检查。 |
strip([chars]) | 在字符串上执行lstrip()和rstrip() |
swapcase() | 将字符串中大写转换小写,小写转换为大写 |
title() | 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写(见istitle())。 |
translate(table,deletechars="") | 根据str给出的表(包含256个字符)转换string的字符,要过滤掉的字符放到deletechars参数中。 |
upper() | 转换字符串中的小写字母为大写 |
zfill(width) | 返回长度为width的字符串,原字符串右对齐,前面填充0。 |
isdecimal() | 检查字符串是否只包含十进制,如果是返回True,否则返回False。 |
Python3列表
序列是Python中最基本的数据结构。序列中的每个元素都分配一个数字-他的位置,或索引,第一个索引是0,第二个索引是1,以此类推。
Python中有6个序列的内置类型,但最常见的是列表和元组。
序列都可以进行的操作包括索引、切片、加、乘、检查成员。
此外Python已经内置确定序列的长度以及确定最大和最小的元素的方法。
列表是最常见的Python数据类型,它可以作为一个方括号内的逗号分隔值出现。
列表的数据项不需要具有相同的类型
创建一个列表,只要把逗号分隔的不同的数据项使用方括号阔起来即可,例如:
list1 = ['Google', 'qifen', 1997, 2000]
list2 = [1, 2, 3, 4, 5]
list3 = ["a", "b", "c", "d"]
与字符串的索引一样,列表索引从0开始,列表可以进行截取、组合等。
访问列表中的值
使用下标索引来访问列表中的值,同样也可以使用方括号的形式截取字符,例如:
#!/usr/bin/python3
list1 = ['Google', 'qifen', 1997, 2000]
list2 = [1, 2, 3, 4, 5, 6, 7]
print("list1[0]", list1[0])
print("list2[1:5]", list2[1:5])
输出:
list1[0] Google
list2[1:5] [2, 3, 4, 5]
更新列表
你可以对列表的数据项进行修改或更新,你也可以使用append()方法来添加列表项,例如:
#!/usr/bin/python3
list = ['Google', 'qifen', 1997, 2000]
print("第三个元素为:", list[2])
list[2] = 2001
print("更新后的第三个元素为:", list[2])
输出:
第三个元素为: 1997
更新后的第三个元素为: 2001
删除列表元素
可以使用del语句来删除列表的元素,例如:
#!/usr/bin/python3
list = ['Google', 'qifen', 1997, 2000]
print("原始列表:", list)
del list[2]
print("删除第三个元素:", list)
输出:
原始列表: ['Google', 'qifen', 1997, 2000]
删除第三个元素: ['Google', 'qifen', 2000]
Python列表脚本操作符
列表 + 和 * 的操作符与字符串相似,* 号用于重复列表。
Python表达式 | 结果 | 描述 |
---|---|---|
len([1, 2, 3]) | 3 | 长度 |
[1, 2 ,3]+[4, 5, 6] | [1, 2, 3, 4, 5, 6] | 组合 |
[‘Hi’] * 4 | [‘Hi’,‘Hi’,‘Hi’,‘Hi’] | 重复 |
3 in [1, 2, 3] | True | 元素是否存在于列表中 |
for x in [1, 2, 3]:print(x, end=" ") | 1 2 3 | 迭代 |
Python列表截取与拼接d
Python的列表截取与字符串操作类型,例如:
L = ['google', 'qifen', 'duck']
操作:
Python表达式 | 结果 | 描述 |
---|---|---|
L[2] | ‘duck’ | 读取第三个元素 |
L[-2] | ‘qifen’ | 从右侧开始读取倒数第二个元素 |
L[1:] | [‘qifen’, ‘duck’] | 输出从第二个元素开始后的所有元素 |
列表还支持拼接操作:
>>>squares = [1, 4, 9, 16, 25]
>>>squares += [36, 49, 64, 81, 100]
>>>squares
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
嵌套列表
使用嵌套列表即在列表里创建其它列表,例如:
>>>a = ['a', 'b', 'c']
>>>n = [1, 2, 3]
>>>x = [a, n]
>>>x
[['a', 'b', 'c']]
>>>x[0][1]
'b'
Python列表函数&方法
Python包含以下函数:
函数 | 描述 |
---|---|
len(list) | 列表元素个数 |
max(list) | 返回列表的最大元素 |
min(list) | 返回列表元素最小值 |
list(seq) | 将元组转换为列表 |
Python包含以下方法:
方法 | 描述 |
---|---|
list.append(obj) | 在列表末尾添加新的对象 |
list.count(obj) | 统计某个元素在列表中出现的次数 |
list.extend(seq) | 在列表末尾一次性追加另一个序列中的多个值(用新的列表扩展原来的列表) |
list.index(obj) | 从列表中找出某个值第一个匹配项的索引位置 |
list.insert(index, obj) | 将对象插入列表 |
list.pop([index = -1]) | 移除列表中的一个元素(默认最后一个元素),并且返回该元素的值 |
list.remove(obj) | 移除列表中某个值的第一个匹配项 |
list.reverse() | 反向列表中的元素 |
list.sort(key = None, reverse = False) | 对原列表进行排序 |
list.clear() | 清空列表 |
list.copy() | 复制列表 |
Python3元组
Python的元组与列表类似,不同之处在于元组的元素不能修改。
元组使用小括号,列表使用方括号。
元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可,例如:
>>>tup1 = ('Google', 'qifen', 1997, 2000)
>>>tup2 = (1, 2, 3, 4, 5)
>>>tup3 = "a", "b", "c", "d" #不需要括号也可以
>>>type(tup3)
<class 'tuple'>
创建空元组:tup1 = ()
元组中只包含一个元素时,需要在元素后面添加逗号,否则括号会被当作运算符使用:
>>>tup1 = (50)
>>>type(tup1) #不加逗号类型为整数
<class 'int'>
>>>tup1 = (50,)
>>>type(tup1) #加上逗号类型为元组
<class 'tuple'>
元组与字符串类似,下标从0开始,可以进行截取,组合等。
访问元组
元组可以使用下标索引来访问元组中的值,如下实例:
#!/usr/bin/python3
tup1 = ('Google', 'qifen', 1997, 2000)
tup2 = (1, 2, 3, 4, 5, 6, 7)
print("tup1[0]:", tup1[0])
print("tup2[1:5]:", tup2[1:5])
输出:
tup1[0]: Google
tup2[1:5]: (2, 3, 4, 5)
修改元组
元组中的元素值是不允许修改的,但我们可以对元组进行连接组合,例如:
#!/usr/bin/python3
tup1 = (12, 34.56)
tup2 = ('abc','xyz')
#以下修改元素操作是非法的
#tup[0] = 100
#创建一个新的元素
tup3 = tup1 + tup2
print(tup3)
输出:(12, 34.56, ‘abc’, ‘xyz’)
删除元组
元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组,例如:
#!/usr/bin/python3
tup = ('Google', 'qifen', 1997, 2000)
print(tup)
del tup
print("删除后的元组 tup:")
print(tup)
以上实例元组被删除后,输出变量会有异常信息,如下:
删除后的元组 tup :
Traceback (most recent call last):
File "test.py", line 8, in <module>
print (tup)
NameError: name 'tup' is not defined
元组运算符
与字符串一样,元组之间可以使用+号和*号进行运算。这就意味着他们可以组合和复制,运算后会生成一个新的元组。
Python表达式 | 结果 | 描述 |
---|---|---|
len((1, 2, 3)) | 3 | 计算元素个数 |
(1, 2, 3)+(4, 5, 6) | (1, 2, 3, 4, 5, 6) | 连接 |
(‘Hi’,) * 4 | (‘Hi’, ‘Hi’, ‘Hi’, ‘Hi’) | 复制 |
3 in (1, 2, 3):print(x,) | True | 元素是否存在 |
for x in (1, 2, 3):print(x,) | 1 2 3 | 迭代 |
元组索引,截取
因为元组也是一个序列,所以我们可以访问元组中的指定位置的元素,也可以截取索引中的一段元素,例如:
L = ('Google', 'qifen', 'duck')
Python表达式 | 结果 | 描述 |
---|---|---|
L[2] | ‘duck’ | 读取第三个元素 |
L[-2] | ‘qifen’ | 反向读取,读取倒数第二个元素 |
L[1:] | (‘qifen’,‘duck’) | 截取元素,从第二个开始后的所有元素 |
元组内置函数
Python元组包含了以下内置函数
方法 | 描述 |
---|---|
len(tuple) | 计算元组元素个数 |
max(tuple) | 返回元组中元素最大值 |
min(tuple) | 返回元组中元素最小值 |
tuple(iterable) | 将可迭代序列转换为元组 |
关于元组是不可变的
所谓元组的不可变指的是元组指向的内存中的容量不可变。
>>>tup = ('r', 'u', 'n', 'o', 'b')
>>>tup[0] = 'g' #不支持修改元素
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>>id(tup) #查看内存地址
140513815003208
>>>tup = (1, 2, 3)
>>>id(tup)
140513783736080 #内存地址不一样了
从以上实例可以看出,重新赋值的元组tup,绑定到新的对象了,不是修改了原来的对象。
Python3字典
字典是另一种可变容器模型,且可存储任意类型对象。
字典的每个键值(key=>value)对用冒号:
分割,每个对之间用逗号,
分割,整个字典包括在花括号{}
中,例如:
d = {key1:value1, key2:value2}
键必须是唯一的,但值则不必。
值可以取任何数据类型,但键必须是不可变的,如字符串,数值或者元组。
一个简单的字典实例:
dict = {'Alice':'2341', 'Beth':'9102', 'Cecil':'3258'}
也可如此创建字典:
dict1 = {'abc':456}
dict2 = {'abc':123, 98.6:37}
访问字典里的值
以上实例输出结果:
#!/usr/bin/python3
dict = {'Name':'qifen', 'Age':7, 'Class':'First'}
print("dict['Name']:", dict['Name'])
print("dict['Age']:", dict['Age'])
输出:
dict['Name']: qifen
dict['Age']: 7
如果用字典里没有的键访问数据,会输出错误如下:
#!/usr/bin/python3
dict = {'Name':'qifen', 'Age':7, 'Class':'First'}
print("dict['Alice']:", dict['Alice'])
输出:
Traceback (most recent call last):
File "test.py", line 5, in <module>
print ("dict['Alice']: ", dict['Alice'])
KeyError: 'Alice'
修改字典
向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对,例如:
#!/usr/bin/python3
dict = {'Name':'qifen', 'Age':7, 'class':'First'}
dict['age'] = 8 #chool更新Age
dict['Shool'] = "七分" #添加信息
print("dict['Age']:", dict['Age'])
print("dict['School']:", dict['School'])
输出:
dict['Age']: 7
dict['School']: 七分
删除字典元素
能删除单一的元素也能清空字典,清空只需一项操作。
显示删除一个字典用del命令,例如:
#!/usr/bin/python3
dict = {'Name':'qifen', 'age':7, 'Class':'First'}
del dict['Name'] #删除键'Name'
dict.clear() #清空字典
del dict #删除字典
print("dict['Age']:", dict['Age'])
print("dict['School']:", dict['School'])
执行del操作后字典不再存在,所以这会引发一个异常:
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 6, in <module>
print("dict['Age']:", dict['Age'])
TypeError: 'type' object is not subscriptable
字典的特性
字典值可以是任何的python对象,既可以是标准的对象,也可以是用户定义的,但键不行。
两个重要的点需要记住:
- 不允许同一个键出现两次,创建时如果同一个键被赋值两次,后一个值会被记住,例如:
#!/usr/bin/python3
dict = {'Name':'qifen', 'Age':7, 'Name':'duck'}
print("dict['Name']:", dict['Name'])
输出:(“dict[‘Name’]:”, ‘duck’)
2. 键必须不可变,所以可以用数学,字符串或者元组充当,而用列表就不行,例如:
#!/usr/bin/python3
dict = {['Name']:'qifen', 'Age':7}
print("dict['Name']:", dict['Name'])
输出:
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 2, in <module>
dict = {['Name']:'qifen', 'Age':7}
TypeError: unhashable type: 'list'
字典内置函数&方法
Python字典包含了以下内置函数:
|函数|描述|
|len(dict)|计算字典元素个数,即键的总数。|
|str(dict)|输出字典,以可打印的字符串表示。|
|type(variable)|返回输入的变量类型,如果变量是字典就返回字典类型。|
Python字典包含了以下内置方法:
方法 | 描述 |
---|---|
radiansdict.clear() | 删除字典所有元素 |
radiansdict.copy() | 返回一个字典的浅复制 |
radiansdict.fromkeys() | 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
radiansdict.get(key, default = None) | 返回指定键的值,如果值不在字典中返回default值 |
key in dict | 如果键在字典dict里返回True,否则返回False |
radiansdict.items() | 以列表返回可遍历的(键, 值)元组数组 |
radiansdict.keys | 返回一个迭代器,可以使用list()来转换为列表 |
radiansdict.setdefault(key,default=None) | 和get()类似,但如果键不存在于字典中,将会添加键并将值设为default |
radiansdict.update(dict2) | 把字典dict2的键/值对更新到dict里 |
radiansdict.values() | 返回一个迭代器,可以使用list()来转换为列表 |
pop(key[,default]) | 删除字典给定键key所对应的值,返回值为被删除的值,key值必须给出,否则返回default值。 |
popitem() | 随机返回并删除字典中的最后一对键和值 |
集合
集合(set)是一个无序的不重复元素序列。
可以使用大括号{}
或者set()
函数创建集合,注意:创建集合必须要用set()
而不是{}
,因为{}
是用来创建一个空字典。
创建格式:
parame = {value1, values2, ...}
或者
set(vaue)
例如:
>>>basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'}
>>>print(basket) #set集合去重了
{'banana', 'pear', 'apple', 'orange'}
>>>'orange' in basket #快速判断元素是否在集合内
True
>>>'crabgrass' in basket
False
>>>a = set('abracadabra')
>>>b = set('alacazam')
>>>a
{'a', 'r', 'b', 'c', 'd'}
>>>a - b #集合a中包含而集合b中不包含的元素
{'r', 'd', 'd'}
>>>a | b #集合a和b中都包含的元素
{'a', 'c', 'r', 'd', 'b', 'm', 'z', 'l'}
>>>a & b #集合a和b中都有的元素
{'a', 'c'}
>>>a ^ b #不同时包含于a和b的元素
{'r', 'd', 'b', 'm', 'z', 'l'}
类似列表推导式,同样集合支持集合推导式(Set comprehension):
>>>a = {x for x in 'abracadabra' if x not in 'abc'}
>>>a
{'r', 'd'}
集合添加元素
将元素x添加到集合s中,如果元素已存在,则不进行任何操作,语法:s.add(x)
>>>thisset = set(("Google", "qifen", "duck"))
>>>thisset.add("gogs")
>>>print(thisset)
{'gogs', 'duck', 'qifen', 'Google'}
还有一个方法,也可以添加元素,且参数可以是列表,元组,字典等,语法:s.update(x),x可以有多个,用逗号分开。
>>>thisset = set(("google", "qifen", "duck"))
>>>thisset.update({1, 3})
>>>print(thisset)
{1, 3, 'google', 'qifen', 'duck'}
集合移除元素
将元素x从集合s中移除,如果元素不存在,则会发生错误,语法:s.remove(x)
>>>thisset = set(("google", "qifen", "duck"))
>>>thisset.remove("duck")
>>>print(thisset)
{'google', 'duck'}
>>>thisset.remove('gogs') #移除不存在的元素会发生错误
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'gogs'
此外还有一个方法也是移除集合中的元素,且如果元素不存在,不会发生错误。语法:s.discard(x)
>>>thisset = set(("google", "qifen", "duck"))
>>>thisset.discard("gogs") #不存在不会发生错误
>>>print(thisset)
{'google', 'duck', 'qifen'}
我们也可以设置随机删除集合中的一个元素,语法格式如下:s.pop()
thisset = set(("google", "qifen", "duck", "gogs"))
x = thisset.pop()
print(x)
print(thisset)
输出:
qifen
{'google', 'gogs', 'duck'}
set集合的pop方法会对集合进行无序的排列,然后将这个无序排列集合的左面第一个元素进行删除。
计算集合元素个数
计算集合s元素个数,语法:len(s)
>>>thisset = set(("google", "qifen", "duck"))
>>>len(thisset)
3
清空集合
清空集合s,语法:s.clear()
>>>thisset = set(("google", "qifen", "duck"))
>>>thisset.clear()
>>>print(thisset)
set()
判断元素是否在集合中存在
判断元素x是否在集合s中,存在返回True,不存在返回False,语法:x in s
>>>thisset = set(("google", "qifen", "duck"))
>>>"qifen" in thisset
True
>>>"gogs" in thisset
False
集合内置方法列表
方法 | 描述 |
---|---|
add() | 为集合添加元素 |
clear() | 移除集合中所有元素 |
copy() | 拷贝一个集合 |
difference() | 返回多个集合的差集 |
difference_update() | 移除集合中的元素,该元素在指定集合也存在 |
discard() | 删除集合中指定的元素 |
intersection() | 返回集合的交集 |
intersection_update() | 返回集合的交集 |
isdisjoint() | 判断两个集合是否包含相同的元素,如果没有返回True,否则返回False |
issubset() | 判断指定集合是否为该方法参数集合的子集 |
issuperset() | 判断该方法的参数集合是否为指定集合的子集 |
pop() | 随机移除元素 |
remove() | 移除指定元素 |
symmetric_difference() | 返回两个集合中不重复的元素集合 |
symmetric_difference_update() | 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中 |
union() | 返回两个集合的并集 |
update() | 给集合添加元素 |
Python3补充
这是一个斐波纳契数列
#!/usr/bin/python3
#Fibonacci series: 斐波纳契数列
#两个元素的总和确定了下一个数
a, b = 0, 1 #a = 0, b = 1
while b < 10:
print(b)
a, b = b, a + b
其中a, b = b, a + b
的计算方式为先计算右边表达式,然后同时赋值给左边,相当于a = b, b = a + b。
输出:
1
1
2
3
5
8
输出变量值:
>>>i = 256 * 256
>>>print('i的值为:', i)
end关键字
end关键字可以用来将结果输出到同一行,或者在输出的末尾添加不同的字符,例如:
#!/usr/bin/python3
#Fibonacci series: 斐波纳契数列
#两个元素的总和确定下一个数
a, b = 0, 1
while b < 1000:
print(b, end=',')
a, b = b, a + b
输出:
1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
Python3条件控制
Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。
if语句
Python中if语句的一般形式如下所示:
if condition_1:
statement_block_1
elif condition_2:
statement_block_2
else:
statement_block_3
Python中用elif
代替了else if,所以if语句的关键字为if-elif-else
。
注意:
- 每个条件后面要使用冒号
:
,表示接下来是满足条件后要执行的语句块。 - 使用缩进来划分语句块,相同的缩进数的语句在一起组合成一个语句块。
- 在Python中没有switch-case语句。
案例1:
#!/usr/bin/python3
var1 = 100
if var1:
print("1 - if 表达式条件为True")
print(var1)
var2 = 0
if var2:
print("2 - if表达式条件为True")
print(var2) #不执行
print("Bye")
输出:
1 - if 表达式条件为True
100
Bye
案例2:
#!/usr/bin/python3
age = int(input("请输入你家狗的年龄:"))
if age <= 0:
print("年龄不能是负数")
elif age == 1:
print("你还是一条小狗")
elif age == 2:
print("你已经是成熟的狗子")
elif age > 2:
print("你已经是大狗了")
输出:
请输入你家狗的年龄1
你还是一条小狗
以下为if中常用的操作运算符:
操作符 | 描述 |
---|---|
< | 小于 |
<= | 小于或等于 |
> | 大于 |
>= | 大于或等于 |
== | 等于,比较两个值是否相等 |
!= | 不等于 |
if嵌套
在嵌套if语句中,可以把if…elif…else结构放在另一个if…elif…else结构中。
if 表达式1:
语句:
if 表达式2:
语句
elif 表达式3:
语句
else :
语句
elif 表达式4:
语句
else:
语句
案例:
#!/usr/bin/python3
num = int(input("输入一个数字:"))
if num % 2 == 0:
if num % 3 == 0:
print("你输入的数字可以整除2和3")
else:
print("你输入的数字可以整除2,不可以整除3")
else:
if num % 3 == 0:
print("你输入的数字可以整除3,不能整除2")
else:
print("你输入的数字不能整除2和3")
输出:
输入一个数字:6
你输入的数字可以整除2和3
Python3循环语句
Python中的循环语句有for和while。
while循环
Python中while语句的一般形式:
while 判断条件:
执行语句
while循环同样需要冒号和缩进,另外,在Python中没有do…while循环。
案例:
#!/usr/bin/env python3
#计算1-100的和
n = 100
sum = 0
counter = 1
while counter <= n :
sum = sum + counter
counter += 1
print("1 - %d 的和为:%d" % (n, sum))
输出:1 - 100 的和为:5050
无限循环
我们可以通过设置条件表达式永远不为false来实现无限循环,例如:
#!/usr/bin/python3
var = 1
while var == 1: #表达式永远为True
num = int(input("输入一个数字:"))
print("你输入的数字是:", num)
print("Bye")
以上会循环无限次,需要按下ctrl+c停止程序,输出:
输入一个数字:1
你输入的数字是: 1
输入一个数字:1
while循环使用else语句
在while…else条件语句为False时执行else的语句块,语法格式:
while 条件:
语句
else:
语句2
循环输出数字,并判断大小:
#!/usr/bin/python3
count = 0
while count < 5:
print(count, "小于5")
count = count + 1
else:
print(count, "大于等于5")
输出:
0 小于5
1 小于5
2 小于5
3 小于5
4 小于5
5 大于等于5
简单语句块
类似if语句的语法,如果你的while循环体中只有一条语句,你可以将该语句与while写在同一行,如下所示:
#!/usr/bin/python3
flag = 1
while (flag): print('while简写')
注意:以上会无限循环,可以使用ctrl+c停止程序,以上输出:
while简写
while简写
while简写
for语句
Python for循环可以遍历任何序列的项目,如一个列表或者一个字符串,for循环的一般格式如下:
for <variable> in <sequence>:
<statements>
else:
<statements>
案例:
>>>lan = ['c', 'java', 'python']
>>>for x in lan:
... print(x)
...
c
java
python
以下for实例中使用了break语句,break语句用于跳出当前循环体,例如:
#!/usr/bin/python3
sites = ['baidu', 'qifen', 'taobao']
for site in sites:
if site == 'qifen':
print('www.qifen.site')
break
print('循环数据:' + site)
else:
print('没有循环数据!')
print('完成循环')
输出:
循环数据:baidu
www.qifen.site
完成循环
range()函数
如果你需要遍历数字序列,你可以使用内置range()
函数,它会生成数列,例如:
>>>for i in range(3):
... print(i)
...
0
1
2
也可以指定区间的值,例如:
>>>for i in range(5, 8)
... print(i)
...
5
6
7
也可以使range以指定数字开始并指定不同的增量(甚至可以是负数,也就是"步长"),例如:
>>>for i in range(0, 10, 3):
... print(i)
...
0
3
6
9
负数:
>>>for i in range(-10, -100, -30):
... print(i)
...
-10
-40
-70
可以结合range()和len()函数以遍历一个序列的索引,例如:
>>>a = ['qifen', 'duck', 'gogs', 'cloud']
>>>for i in range(len(a)):
... print(i, a[i])
...
0 qifen
1 duck
2 gogs
3 cloud
还可以使用range()函数来创建一个列表,例如:
>>>list(range(5))
[0, 1, 2, 3, 4]
break和continue语句及循环中的else子句
break语句可以跳出for和while循环体,如果你从for或者while循环中终止,任何对应的循环else块将不执行。
continue语句被用来告诉Python跳过当前循环中剩余语句,然后继续下一轮循环。
案例(while中使用break):
#!/usr/bin/python3
n = 5
while n > 0:
n -= 1
if n == 2:
break
print(n)
print('循环结束')
输出:
4
3
循环结束
while中使用continue:
#!/usr/bin/python3
n = 5
while n > 0:
n -= 1
if n == 2:
continue
print(n)
print('循环结束')
输出:
4
3
1
0
循环结束
if使用break和continue案例:
#!/usr/bin/python3
for letter in 'qifen':
if letter == 'b':
break
print('当前字母为:', letter)
var = 10
while var > 0:
print('当前变量值为:', var)
var = var - 1
if var == 5:
break
输出:
当前字母为: q
当前字母为: i
当前字母为: e
当前字母为: n
当前变量值为: 7
当前变量值为: 6
循环语句中有else子句,循环中执行break后else不被执行,案例:
#!/usr/bin/python3
for i in range(7):
if i == 3:
break
print(i)
else:
print(i,'不在序列中')
输出:
1
2
3
pass语句
Python pass是空语句,是为了保持程序结构的完整性,pass不做任何事情,一般用做占位语句,例如:
>>>while True:
... pass #等待键盘中断ctrl+c
在字母为o时执行pass语句块,例如:
#!/usr/bin/python3
for letter in 'qifen':
if letter == 'f':
pass
print('执行pass块')
print('当前字母:', letter)
输出:
当前字母: q
当前字母: i
执行pass块
当前字母: f
当前字母: e
当前字母: n
Python3迭代器与生成器
迭代器
- 迭代器是Python最强大的功能之一,是访问集合元素的一种方式。
- 迭代器是一个可以记住遍历的位置的对象。
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
- 迭代器有两个基本的方法
iter()
和next()
。
字符串、列表或元组对象都可用于创建迭代器,例如:
>>>list = [1, 2, 3, 4]
>>>it = iter(list) #创建一个迭代器对象
>>>print(next(it)) #输出迭代器的下一个元素
1
>>>print(next(it))
2
迭代器对象可以使用常规for语句进行遍历,例如:
#!/usr/bin/python3
list = [1, 2, 3, 4]
it = iter(list) #创建迭代器对象
for x in it:
print(x, end=' ')
输出:1 2 3 4
也可以使用next()函数:
#!/usr/bin/python3
import sys #引入sys模块
list = [1, 2, 3, 4]
it = iter(list) #创建迭代器对象
while True:
try:
print(next(it))
except StopIteration:
sys.exit()
输出:
1
2
3
4
创建一个迭代器
把一个类作为一个迭代器使用需要在类中实现两个方法__iter__()和__next__()。
Python的构造函数为__init__(),它会在对象初始化的是否执行。
__iter__()方法返回一个迭代器对象,这个迭代器对象实现了__next__()方法通过StopIteration异常标识迭代的完成。
__next__()方法(Python2里是next())会返回下一个迭代器对象。
创建一个返回数字的迭代器,初始值为1,逐步递增1,案例:
#!/usr/bin/python3
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
x = self.a
self.a += 1
return x
myclass = MyNumbers()
myiter = iter(myclass)
print(next(myiter))
print(next(myiter))
print(next(myiter))
输出:
1
2
3
StopIteration
StopIteration异常用于标识迭代的完成,防止出现无限循环的情况,在__next__()方法中我们可以设置在完成指定循环次数后触发StopIteration异常年来结束迭代,例如(迭代5行):
#!/usr/bin/python3
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 5:
x = self.a
self.a += 1
return x
else:
raise StopIteration
myclass = MyNumbers()
myiter = iter(myclass)
for x in myiter:
print(x)
输出:
1
2
3
4
5
生成器
在Python中,使用了yield的函数被称为生成器(generator)。
跟普通函数不同的是,生成器是一个返回迭代的函数,只能用于迭代操作。
在调用生成器运行的过程中,每次遇到yield时函数会暂停并保存当前所有的运行信息,返回yield的值,并在下一次执行next()方法时从当前位置继续运行。
调用一个生成器函数,返回的是一个迭代器对象。
案例(使用yield实现斐波纳契数列):
#!/usr/bin/python3
import sys
def fibonacci(n): #生成器函数-斐波纳契
a, b, counter = 0, 1, 0
while True:
if(counter > n):
return
yield a
a, b = b, a + b
counter += 1
f = fibonacci(10) #f是一个迭代器,由生成器返回生成
while True:
try:
print(next(f), end=' ')
except StopIteration:
sys.exit()
输出:0 1 1 2 3 5 8 13 21 34 55
Python3函数
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段,函数能提高应用的模块性,和代码的重复利用率。
定义一个函数
你可以定义一个函数,规则是:
- 函数代码块以
def
关键词开头,后接函数标识符名称和圆括号()
。 - 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
return [表达式]
结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回None。
定义函数语法格式:
def 函数名(参数列表):
函数体
默认情况下,参数值和参数名称是按按函数声明中定义的顺序匹配起来的。案例:
>>>def hello():
... print('hello world')
...
>>>hello()
hello world
函数中带上参数变量:
#!/usr/bin/python3
#计算面积函数
def area(width, height):
return width * height
def print_welcome(name):
print('welcome', name)
print_welcome('qifen')
w = 4
h = 5
print('width =', w, 'height =', h, 'area =', area(w, h))
输出:
welcome qifen
width = 4 height = 5 area = 20
函数调用
定义一个函数:给了函数一个名称,指定了函数里包含的参数,和代码块结构。
这个函数的基本结构完成以后,你可以通过另一个函数调用执行,也可以直接从Python命令提示符执行。
以下案例调用了printme()函数:
#!/usr/bin/python3
#定义函数
def printme(str):
#打印任何传入的字符串
print(str)
return
printme('调用自定义函数')
printme('再次调用')
输出:
调用自定义函数
再次调用
参数传递
在Python中,类型属于对象,变量是没有类型的,例如:
a = [1, 2, 3]
a = 'qifen'
以上代码中,[1, 2, 3]是List类型,"qifen"是String类型,而变量a是没有类型。她仅仅是一个对象的引用(一个指针),可以是指向List类型对象,也可以是指向String类型对象。
可更改(mutable)与不可更改(immutable)对象
在Python中,string、tuple、numbers是不可更改的对象,而List、dict等则是可以修改的对象。
- **不可变类型:**变量赋值a = 5后,再赋值a = 10,这里实际是新生成一个int值对象10,再让a指向它,而5被丢弃,不是改变了a的值,相当于新生成了a。
- **可变类型:**变量赋值la = [1, 2, 3]后再赋值la[2] = 5则是将list la的第三个元素值更改,本身la没有动,只是内部的一部分值被修改了。
Python函数的参数传递:
- **不可变类型:**类似c++的值传递,如整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。
- **可变类型:**类似c++的引用传递,如列表、字典。如fun(la),则是将la真正的传过去,修改后fun外部的la也会受影响。
Python中一切都是对象,严格意义我们不能说传递还是引用传递,我们应该说传不可变对象和传可变对象。
Python传不可变对象实例
使用函数来输出helloworld
#!/usr/bin/python3
def ChangeInt(a):
a = 10
b = 2
ChangeInt(b)
print(b)
实例中有int对象2,指向它的变量是b,在传递给ChangeInt函数时,按传值的方式复制了变量b,a和b都指向了同一个int对象,在a = 10时,则新生成一个int值对象10,并让a指向它。
传可变对象实例
可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了,例如:
#!/usr/bin/python3
#可写函数说明
def changeme(mylist):
#修改传入的列表
mylist.append([1, 2, 3, 4])
print('函数内取值:', mylist)
return
#调用changeme函数
mylist = [10, 20, 30]
changeme(mylist)
print('函数外取值:', mylist)
传入函数的和在末尾添加新内容的对象用的是同一个引用,所以输出:
函数内取值: [10, 20, 30, [1, 2, 3, 4]]
函数外取值: [10, 20, 30, [1, 2, 3, 4]]
参数
以下是调用函数时可使用的正式参数类型:
- 必须参数
- 关键字参数
- 默认参数
- 不定长参数
必须参数
必须参数须以正确的顺序传入函数。调用时的数量必须和声明时候的一样,调用printme()函数,你必须传入一个参数,不然会出现语法错误:
#!/usr/bin/python3
#可写函数说明
def printme(str):
print(str)
return
#调用printme()函数,不加参数会报错
printme() #没加参数报错
输出:
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 7, in <module>
printme() #没加参数报错
TypeError: printme() missing 1 required positional argument: 'str'
关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为Python解释器能够用参数名匹配数值。
以下实例在函数printme()调用时使用参数名:
#!/usr/bin/python3
#可写函数说明
def printme(str):
print(str)
return
#调用printme()函数
printme(str = 'qifen')
输出:qifen
以下实例中演示了函数参数的使用不需要使用指定顺序:
#!/usr/bin/python3
def printme(name, age):
print('name:', name)
print('age:', age)
return
printme(age = 50, name = 'qifen')
输出:
name: qifen
age: 50
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传递age参数,则使用默认值:
#!/usr/bin/python3
def printinfo(name, age=35):
print('name:', name)
print('age:', age)
return
printinfo(age = 50, name = 'qifen')
print('---')
printinfo(name = 'qifen')
输出:
name: qifen
age: 50
---
name: qifen
age: 35
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数,这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名,基本语法如下:
#!/usr/bin/python3
def functionname([formal_args,] *var_args_tuple):
function_suite
return [expression]
加了星号*
的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
#!/usr/bin/python3
def printinfo(arg1, *vartuple):
print(arg1)
print(vartuple)
printinfo(70, 60, 50)
输出:
70
(60, 50)
如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量,例如:
#!/usr/bin/python3
def printinfo(arg1, *vartuple):
print(arg1)
for var in vartuple:
print(var)
return
#调用printinfo函数
printinfo(10)
printinfo(70, 60, 50)
输出:
10
70
60
50
还有一种就是参数带两个星号**
基本语法如下:
def functionname([formal_args,] **var_args_dict):
function_suite
return [expression]
加了两个星号**
的参数会以字典的形式导入。
#!/usr/bin/python3
def printinfo(arg1, **vardict):
print(arg1)
print(vardict)
printinfo(1, a = 2, b = 3)
输出:
1
{'a': 2, 'b': 3}
声明函数时,参数中星号*
可以单独出现,例如:
def f(a, b, *, c):
return a + b + c
如果单独出现星号*
后的参数必须用关键字传入。
>>>def f(a, b, c, *, c)
... return a + b + c
...
>>>f(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'f' is not defined
>>>f(1, 2, c = 3) #正常
6
匿名函数
python使用lambda来创建匿名函数,所谓匿名函数,意即不再使用def语句这样标准的形式定义一个函数。
- lambda只是一个表达式,函数体比def简单很多。
- lambda的主体是一个表达式,而不是一个代码块。
- lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。
语法
lambda函数的语法只包含一个语句,例如:
lambda [arg1[,arg2,...argn]]:expression
实例:
#!/usr/bin/python3
sum = lambda arg1, arg2: arg1 + arg2
#调用sum函数
print('相加的值为:', sum(10, 20))
print('相加的值为:', sum(20, 20))
输出:
相加的值为: 30
相加的值为: 40
return语句
return[表达式]语句用于退出函数,选择性地向调用方法返回一个表达式。不带参数值的return语句返回None,例如:
#!/usr/bin/python3
def sum(arg1, arg2):
#返回两个参数和
total = arg1 + arg2
print('函数内:', total)
return total
total = sum(10, 20)
print('函数外:', total)
输出:
函数内: 30
函数外: 30
强制位置参数
Python3.8新增了一个函数形参语法/
用来指明函数形参必须使用指定位置参数,不能使用关键字参数的形式。
在以下的例子中,形参a和b必须使用指定位置参数,c或d可以是位置形参或关键字形参,而e或f要求为关键字形参:
#!/usr/bin/python3.8
def f(a, b, /, c, d, *, e, f):
print(a, b, c, d, e, f)
以下使用方法是正确的:
f(10, 20, 30, d = 40, e = 50, f = 60)
以下使用方法会发生错误:
f(10, b = 20, c = 30, d = 40, e = 50, f = 60)
f(10, 20, 30, 40, 50, f = 60)
Python3数据结构
列表
Python中列表是可变的,这是它区别于字符串和元组的最重要的特点,列表可以修改,而字符串和元组不能,以下是Python中列表的方法:
方法 | 描述 |
---|---|
list.append(x) | 把一个元素添加到列表的结尾,相当于a[len(a):] = [x]。 |
list.extend(L) | 通过添加指定列表的所有元素来扩充列表,相当于a[len(a):] = L 。 |
list.insert(i, x) | 在指定位置插入一个元素。第一个参数是准备插入到其前面的那个元素的索引。 |
list.remove(x) | 删除列表中值为x的第一个元素。如果没有这样的元素,会返回一个错误。 |
list.pop([i]) | 从列表的指定位置移除元素,并将其返回。如果没有指定索引,a.pop()返回最后一个元素。元素随即从列表中被移除。 |
list.clear() | 移除列表中的所有项,等于del a[:]。 |
list.index(x) | 返回列表中第一个值为x的元素的索引。如果没有匹配的元素就会返回一个错误。 |
list.count(x) | 返回x在列表中出现的次数。 |
list.sort() | 对列表中的元素进行排序。 |
list.reverse() | 排倒列表中的元素。 |
list.copy() | 返回列表的浅复制,等于a[:]。 |
将列表当作堆栈使用
列表方法使得列表可以很方便的作为一个堆栈来使用,堆栈作为特定的数据结构,最先进入的元素最后一个被释放(先进后出),用append()方法可以把一个元素添加到堆栈顶。用不指定索引的pop()方法可以把一个元素从堆栈顶部释放出来,例如:
>>>stack = [3, 4, 5]
>>>stack.append(6)
>>>stack.append(7)
>>>stack
[3, 4, 5, 6, 7]
>>>stack.pop()
7
>>>stack
[3, 4, 5, 6]
>>>stack.pop()
6
将列表当作队列使用
也可以把列表当作队列用,只是在队列里第一加入的元素,第一个取出来;但是拿列表用作这样的目的效率不高。在列表的最后添加或者弹出元素速度快,然而在列表里插入或者从头部弹出速度却不快(因为其它元素都得一个一个地移动)。
>>>from collections import deque
>>>queue = deque(['qifen', 'duck', 'gogs'])
>>>queue.append('cloud')
>>>queue.append('md')
>>>queue.popleft()
'qifen'
>>>queue.popleft()
'duck'
>>>queue
deque(['gogs', 'cloud', 'md'])
列表推导式
列表推倒式提供了从序列创建列表的简单途径。通常应用程序将一些操作应用于某个序列的某个元素,用其获得的结果作为生成新列表的元素,或者根据确定的判定条件创建子序列。
每个列表推导式都在for之后跟一个表达式,然后有0个到多个for或if子句。返回结果是一个根据表达式从其后的for和if上下文环境中生成出来的列表。如果希望表达式推导出一个元组,就必须使用括号。
这里我们将列表中每个数值乘3,获得一个新的列表:
>>>vec = [2, 4, 6]
>>>[3 * x for x in vec]
[6, 12, 18]
案例:
>>>vec = [2, 4, 6]
>>>[[x, x ** 2] for x in vec]
[[2, 4], [4, 16], [6, 36]]
案例:
>>>freshfruit = [' apple', ' pear ', 'oran ge']
>>>[weapon.strip() for weapon in freshfruit]
['apple', 'pear', 'oran ge']
可以使用if子句作为过滤器:
>>>vec = [2, 4, 6]
>>>[3 * x for x in vec if x > 3]
[12, 18]
>>>[3 * x for x in vec if x < 2]
[]
案例:
>>>vec1 = [2, 4, 6]
>>>vec2 = [4, 3, -9]
>>>[x * y for x in vec1 for y in vec2]
[8, 6, -18, 16, 12, -36, 24, 18, -54]
>>>[x + y for x in vec1 for y in vec2]
[6, 5, -7, 8, 7, -5, 10, 9, -3]
>>>[vec1[i]*vec2[i] for i in range(len(vec1))]
[8, 12, -54]
列表推导式可以使用复杂表达式或嵌套函数:
>>>[str(round(355/113, i)) for i in range(1, 6)]
['3.1', '3.14', '3.142', '3.1416', '3.14159']
嵌套列表解析
Python的列表还可以嵌套。
以下实例展示3X4矩阵列表:
>>>a = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>>a
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
将3X4矩阵列表转换为4X3列表:
>>>a = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
>>>[[row[i] for row in a] for i in range(4)]
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
另一种方法实现:
#!/usr/bin/python3
list = []
a = [[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]]
for i in range(4):
list_row = []
for row in a:
list_row.append(row[i])
list.append(list_row)
print(list)
输出:[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
del语句
使用del语句可以从一个列表中依索引而不是来删除一个元素。这与使用pop()返回一个值不同。可以用del语句从列表中删除一个切割,或清空整个列表(还可以通过赋值的方式给该数组赋一个空列表),例如:
>>>a = [-1, 1, 66.25, 333, 333, 1234.5]
>>>del a[0]
>>>a
[1, 66.25, 333, 333, 1234.5]
>>>del a[2:4]
>>>a
[1, 66.25, 1234.5]
>>>a
[]
也可以使用del删除实体变量:
>>>del a
元组和序列
元组由若干逗号分隔的值组成,例如:
>>>t = 12345, 54321, 'hello!'
>>>t[0]
12345
>>>t
(12345, 54321, 'hello!')
>>>u = t, (1, 2, 3, 4, 5)
>>>u
((12345, 54321, 'hello!'), (1, 2, 3, 4, 5))
元组在输出时总是有括号的,以便于正确表达嵌套结构。在输入时可能有或没有括号,不过括号通常时必须的(如果元组是更大的表达式的一部分)。
集合
集合是一个无序不重复元素的集。基本功能包括关系测试和消除重复元素,可以使用大括号{}
创建集合,注意:如果要创建一个空集合,你必须用set()而不是用{},后者创建一个空的字典,案例:
>>>basket = {'apple', 'orange', 'apple', 'pear', 'orange', 'banana'} #自动删除重复元素
>>>print(basket)
{'orange', 'banana', 'pear', 'apple'}
>>>'orange' in basket #检测成员
True
>>>'crabgrass' in basket
False
>>>a = set('abcdef')
>>>b = set('abc')
>>>a
{'a', 'b', 'c', 'd', 'e', 'f'}
>>>a - b #a中唯一的字母
{'d', 'e', 'f'}
>>>b - a #b中唯一的字母,没有返回set()
set()
>>>a | b #在a和b中的字母
{'a', 'b', 'c', 'd', 'e', 'f'}
>>>a & b #在a和b中都有字母
{'d', 'e', 'f'}
>>>a ^ b #在a或b中的字母,但不同时在a和b中
{'d', 'e', 'f'}
集合也支持推导式:
>>>a = {x for x in 'abcdef' if x not in 'abc'}
>>>a
{'d', 'f', 'e'}
字典
序列是以连续的整数为索引,与此不同的是,字典以关键字为索引,关键字可以是任何不可变类型,通常用字符串或数值
理解字典的最佳方式是把它看做无序的键值对集合。在同一个字典之内,关键字必须是互不相同,大括号创建一个空的字典{}
,例如:
>>>tel = {'jack': 4098, 'sape': 4139}
>>>tel['guido'] = 4127
>>>tel
{'sape': 4139, 'guido': 4127, 'jack': 4098}
>>>tel['jack']
4098
>>>del tel['sape']
>>>tel['irv'] = 4127
>>>tel
{'guido':4127, 'irv': 4127, 'jack':4098}
>>>list(tel.keys()) #输出所有键,返回列表
['irv', 'guido', 'jack']
>>>sorted(tel.keys()) #输出所有键并排序
['guido', 'irv', 'jack']
>>>'guido' in tel
True
>>>'jack' not in tel
False
构造函数dict()直接从键值对元组列表中构建字典。如果有固定的模式,列表推导式指定的键值对:
>>>dict([('sape', 4139), ('guido', 4127), ('jack', 4098)])
{'sape': 4139, 'guido': 4127, 'jack': 4098}
此外,字典推导可以用来创建任意键和值的表达式字典:
>>>{x : x ** 2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
如果关键字只是简单的字符串,使用关键字参数指定键值对有时候更方便:
>>>dict(sape = 4139, guido = 4127, jack = 4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}
遍历技巧
在字典遍历时,关键字和对应的值可以使用items()方法同时解读出来:
>>>a = {'name': 'duck', 'site': 'qifen'}
>>>for k, v in a.items():
... print(k, v)
...
name duck
site qifen
在序列中遍历时,索引位置和对应值可以使用enumerate()函数同时得到:
>>>for i, v in enumerate(['qifen', 'duck', 'gogs']):
... print(i, v)
...
0 qifen
1 duck
2 gogs
同时遍历两个或更多的序列,可以使用zip()组合:
>>>que = ['name', 'sex', 'fav']
>>>ans = ['lan', 'boy', 'blue']
>>>for q, a in zip(que, ans):
... print('{0}:{1}'.format(q, a))
...
name:lan
sex:boy
fav:blue
要反向遍历一个序列,首先指定这个序列,然后调用reversed()函数:
>>>for i in reversed(range(1, 10, 3)):
... print(i)
7
4
1
要按顺序遍历一个序列,使用sorted()函数返回一个已排序的序列,并不修改原值:
>>>basket = ['apple', 'orange', 'apple', 'pear', 'banana']
>>>for f in sorted(set(basket)):
... print(f)
...
apple
banana
orange
pear
Python3模块
模块是一个包含所有你定义的函数和变量的文件, 其后缀名是py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用python标准库的方法,案例:
#!/usr/bin/python3
import sys
print('python路径为:', sys.path)
输出:
python路径为: ['/home/qifen/Projects/vscodecprojects/test', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
- import sys引入python标准库中的sys.py模块,这是引入某一模块的方法。
- sys.argv是一个包含命令行参数的列表。
- sys.path包含了一个Python解释器自动查找所需模块的路径的列表。
import语句
想使用Python源文件,只需要在另一个源文件里执行import语句,语法:
import module1[, module2, ... moduleN]
当解释器遇到import语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块support,需要把命令放在脚本的顶端:
#!/usr/bin/python3
#support.py文件
def print_func(par):
print('hello:', par)
return
test.py引入support模块:
#!/usr/bin/python3
#test.py文件
import support #导入上面的support模块
support.print_func('qifen')
输出:
hello qifen
一个模块只会被导入一次,不管你指定多少次import。这样可以防止模块被一遍一遍地执行。
当我们使用import语句的时候,Python解释器会搜索一系列目录名,Python解释器就依次从这些目录中去寻找引入的模块。这看起来很像环境变量,也可以通过定义环境变量的方式来确定搜索路径。
搜索路径是在Python编译或安装的时候确定的,安装新的库也会修改,搜索路径被存储在sys模块中的path变量,做个简单的实验,如下:
>>>import sys
>>>sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
sys.path输出的是一个列表,其中第一项是空串,代表当前目录(如果是脚本打印的话,可以看到真实目录),亦即是我们执行python解释器的目录(对于脚本的话就是运行的脚本所在目录)。因此在当前目录下存在要引入模块同名的文件,就会把要引入的模块屏蔽掉。
了解了搜索路径概念,就可以在脚本中修改sys.path来引入一些不在搜索路径中的模块。现在,在解释器的当前目录或者sys.path中的一个目录里面创建一个fibo.py的文件,代码如下:
def fib(n): #定义到n的斐波纳契数列
a, b = 0, 1
while b < n:
print(b, end = ' ')
a, b = b, a + b
print()
def fib2(n): #返回到n的斐波纳契数列
result = []
a, b = 0, 1
while b < n:
result.append(b)
a, b = b, a + b
return result
然后进入Python解释器,使用下面的命令导入这个模块:
>>>import fibo
这样做并没有把直接定义在fibo中的函数写入到当前符号表里,只是把模块fibo的名字写到了那里,可以使用模块名称来访问函数:
>>>fibo.fib(1000)
1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
如果你打算经常使用一个函数,你可以把它赋值给一个本地的名称:
>>>fib = fibo.fib
>>>fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
from … import 语句
Python的from语句让你从模块中导入一个指定的部分到当前命令空间中,语法如下:
from modname import name1[, name2[, ... nameN]]
例如,要导入fibo的fib函数,使用如下语句:
>>>from fibo import fib, fib2
>>>fib(500)
这个声明不会把整个fibo模块导入到当前的命名空间中,它只会将fibo里的fib和fib2函数引入进来。
from … import *语句
把一个模块的所有内容全部都要导入到当前的命名空间也是可行的,只需要如下声明:
from modname import *
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
深入模块
模块除了方法定义,还可以包括可执行的代码。这些代码一般用来初始化这个模块。这些代码只有在第一次被导入时才会被执行。
每个模块有各自独立的符号表,在模块内部为所有函数当作全局符号表来使用。
所以模块的作者可以放心大胆在模块内部使用这些变量,而不用担心把其它用户的全局变量搞混。
你可以通过modname.itemname这样的表示法来访问模块内的函数。
模块是可以导入其它模块的。在一个模块(或脚本,或者其他地方)的最前面使用import来导入一个模块,被导入模块的名称将放入当前操作的模块的符号表中。
可以使用import直接把模块内(函数,变量)名称导入到当前操作模块。比如:
>>>from fibo import fib, fib2
>>>fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
这种导入的方法不会把被导入的模块的名称放在当前的字符列表中(所以在这个例子中,fibo这个名称是没有定义的)
还有一种方法,可以一次性的把模块中的所有(函数,变量)名称都导入到当前模块的字符表:
>>>from fibo import *
>>>fib(500)
1 1 2 3 5 8 13 21 34 55 89 144 233 377
这将把所有的名字都导入进来,但是那些由单一下划线(_)开头的名字不在此例。大多数情况,Python程序员不使用这种方法,因为引入的其它来源的命名,很可能覆盖了已有的定义。
__name__属性
一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__属性来使该程序块仅在该模块自身运行时执行。
#!/usr/bin/python3
if __name__ == '__main__':
print('程序自身在运行')
else:
print('我来自另一个模块')
输出:程序自身在运行
**说明:**每个模块都有一个__name__属性,当其值是__name__时,表明该模块自身在运行,否则是被引入。
dir()函数
内置的函数dir()可以找到模块内定义的所有名称。以一个字符串列表的形式返回:
>>>import fibo, sys
>>>dir(fibo)
['__name__', 'fib', 'fib2']
>>>dir(sys)
['__displayhook__', '__doc__', '__excepthook__', ... 省略一堆 ... ]
如果没有给定参数,那么dir()函数会罗列出当前定义的所有名称:
>>>a = [1, 2, 3, 4, 5]
>>>import fibo
>>>fib = fibo.fib
>>>dir() #得到一个当前模块中定义的属性列表
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
>>>a = 5 #建立一个新的变量‘a’
>>>dir()
['__builtins__', '__doc__', '__name__', 'a', 'sys']
>>>del a #删除变量a
>>>dir()
['__builtins__', '__doc__', '__name__', 'sys']
标准模块
Python本身带着一些标准的模块库,有些模块直接被构建在解析器里,这些虽然不是一些语言内置的功能,但是他却能很高效的使用,甚至是系统级调用也没问题。
这些组件会根据不同的操作系统进行不同形式的配置,比如winreg这个模块就只会提供给Windows系统。
应该注意到这有一个特别的模块sys,它内置在每个Python解析器中。变量sys.ps1和sys.ps2定义了主提示符和副提示符所对应的字符串:
>>>import sys
>>>sys.ps1
'>>>'
>>>sys.ps2
'...'
>>>sys.ps1 = 'C>'
C>print('qifen')
qifen
C>
包
包是一种管理Python模块命名空间的形式,采用“点模块名称”。
比如一个模块的名称是A.B,那么他表示一个包A中的子模块B。
就好像使用模块的时候,你不用担心不同模块之间的全局变量相互影响一样,采用点模块名称这种形式也不用担心不同库之间的模块重命名的情况。
这样不同的作者都可以提供NumPy模块,或者是Python图形库。
不妨假设你想设计一套统一处理声音和数据的模块(或者称之为一个‘包’)
现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如:.wav,:file:.aiff,:file:.au,),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。
并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。
这里给出了一种可能的包结构(在分层的文件系统中):
sound/ 顶层包
__init__.py 初始化 sound 包
formats/ 文件格式转换子包
__init__.py
wavread.py
wavwrite.py
aiffread.py
aiffwrite.py
auread.py
auwrite.py
...
effects/ 声音效果子包
__init__.py
echo.py
surround.py
reverse.py
...
filters/ filters 子包
__init__.py
equalizer.py
vocoder.py
karaoke.py
...
在导入一个包的时候,Python会根据sys.path中的目录来寻找这个包中包含的子目录。
目录只有包含一个叫作__init__.py的文件才会被认作是一个包,主要是为了避免一些滥俗的名字(比如叫做string)不小心的影响搜索路径中的有效模块。
最简单的情况,放一个空的:file:__init__.py就可以了。当然这个这个文件中也可以包含一些初始化代码或者为__all__变量赋值。
用户可以每次只导入一个包里面的特定模块,比如:
import sound.effects.echo
这将会导入子模块:sound.effects.echo。他必须使用全名去访问:
sound.effects.echo.echo.echofilter(input, output, delay = 0.7, atten = 4)
还有一种导入子模块的方法是:
from sound.effects import echo
这样同样会导入模块echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
echo.echofilter(input, output, delay = 0.7, atten = 4)
还有一种变化就是直接导入一个函数或者变量:
from sound.effects.echo import echofilter
同样的,这种方法会导入子模块:echo,并且可以直接使用他的echofilter()函数:
echofilter(input, output, delay = 0.7, atten = 4)
注意当使用from package import item
这种形式时候,对应的item既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。
import语法会首先把item当作一个包定义名的的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个:exc:ImportError
异常。
反之,如果使用形如import item.subitem.subsubitem
这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者包,但是不可以是类,函数或者变量的名字。
从一个包中导入*
设想一下,如果我们使用from sound.effects import * 会发生什么?
Python会进入文件系统,找到这个包里面所有的子模块,一个一个的把它们都导入进来。
这个方法在Windows平台上工作的不是很好,因为Windows是一个大小写不区分的系统。在这类平台上导入一个叫ECHO.py的文件可能会被识别成echo或者Echo。
为了解决这个问题,只能烦劳包作者提供一个精确的包索引了,导入语句遵循如下规则:如果包定义文件__init__.py存在一个叫做__all__的列表变量,那么在使用from package import *的时候就把这个列表中的所有名字作为包内容导入。
作为包的作者,不能忘了在更新包后__init__.py也要更新,例如:
__all__ = ['echo', 'surround', 'reverse']
这表示当你使用from sound.effects import *这种用法时,你只会导入包里面这三个子模块。
如果__all__没有定义,那么使用from sound.effects import *这种语法时,就不会导入包sound.effects里面的任何子模块,他只是把包sound.effects和它里面定义的所有内容导入进来(可能运行__init__.py里定义的初始化代码)。
这会把__init__.py里面定义的所有名字导入进来。并且他不会破坏我们在这句话之前导入的所有明确指定的模块,例如:
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
在这个例子中,在执行from … import前,包sound.effects中的echo和surround模块都被导入到当前的命名空间中了。(当然如果定义__all__那就更没问题了)
通常我们不主张使用*
这种方法来导入模块,因为这种方法经常会导致代码的可读性降低,不过这样倒的确是可以省去不少时间,而且一些模块都设计成了只能通过特定的方法导入。
使用from package import specific_submodule
这种方法永远不会有错。事实上,这也是推荐的方法,除非是你要导入的子模块有可能和其他包的子模块重名。
如果在结构中包是一个子包(比如这个例子中对于包sound来说),而你又想导入同级别的包,你就得使用导入绝对包的路径来导入。比如模块sound.filters.vocoder要使用包sound.effects中的模块echo,你就要写成from sound.effects import echo。
from . import echo
from .. import formats
from ..filters import equalizer
无论是隐式的还是显式的相对导入都是从当前模块开始的。主模块的名字永远是"__main__",一个Python应用程序的主模块,应当总是使用绝对路径引用。
包还提供一个额外的属性__path__。这是一个目录列表,里面每一个包含的目录都有为这个包服务的__init__.py,你得在其他__init__.py被执行前定义,可以修改这个变量,用来影响包含在包里面的模块和子包,这个功能不常用,一般用来扩展包里面的模块。
Python3输入和输出
输出格式美化
Python两种输出值的方式:表达式语句和print()函数。
第三种方式是使用文件对象的write()方法,标准输出文件可以用sys.stdout引用
如果你希望输出的形式更加多样,可以使用str.format()函数来格式化输出值。
如果你希望将输出的值转换成字符串,可以使用repr()或str()函数来实现。
- str()函数返回一个用户易读的表达形式。
- repr()产生一个解释器易读的表达形式。
例如:
>>> s = 'hello, qifen'
>>> str(s)
'hello, qifen'
>>> repr(s)
"'hello, qifen'"
>>> str(1 / 7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'x 的值为:' + repr(x) + ', y 的值为:' + repr(y)
>>> print(s)
x 的值为:32.5, y 的值为:40000
>>> # repr()函数可以转义字符串中的特殊字符
... hello = 'hello, qifen\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, qifen\n'
>>> # repr()的参数可以是Python的任何对象
... repr((x, y, ('google', 'qifen')))
"(32.5, 40000, ('google', 'qifen'))
这里有两种方式输出一个平方与立方的表:
>>> for x in range(1, 11):
... print(repr(x).rjust(2), repr(x * x).rjust(3), end = ' ')
... print(repr(x * x * x).rjust(4))
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
>>> for x in range(1, 11):
... print('{0:2d} {1:3d} {2:4d}'.format(x, x * x, x * x * x))
...
1 1 1
2 4 8
3 9 27
4 16 64
5 25 125
6 36 216
7 49 343
8 64 512
9 81 729
10 100 1000
注意:在第一个例子中,每列间的空格由print()添加,这个例子展示了字符串对象的rjust方法,它可以让字符串靠右,并在左边填充空格。还有类似的方法如ljuest()和center()。这些方法并不会写任何东西,他们仅仅返回新的字符串。
另一个方法zfill(),它会在数字的左边填充0,如下所示:
>>>'12'.zfill(5)
'00012'
>>>'-003.14'
>>>'3.14159265359'.zfill(5)
'3.14159265359'
str.format()的基本使用如下:
>>>print('{}网址: "{}"'.format('qifen', 'www.qifen.site'))
qifen网址: "www.qifen.site"
括号及其里面的字符(称做格式化字段)将会被format()中的参数替换。
在括号中数字用于指向传入对象在format()中的位置,如下所示:
>>>print('{0} 和 {1}'.format('qifen', 'duck'))
qifen 和 duck
>>>print('{1} 和 {0}'.format('qifen', 'duxk'))
duck 和 qifen
如果在format()中使用了关键字参数,那么它们的值会指向使用该名字的参数。
>>>print('{name}网址:{site}'.format(name = 'qifen', site = 'www.qifen.site'))
qifen网址:www.qifen.site
位置及关键字参数可以任意的结合:
>>>print('站点列表 {0}, {1}, 和 {other}。'.format('google', 'qifen', other = 'ali'))
站点列表 google, qifen, 和 ali。
!a
(使用ascii),!s
(使用str())和!r
(使用repr()),可以用于格式化某个值之前对其进行转化:
>>>import math
>>>print('常量PI的值近似为:{}。'.format(math.pi))
常量PI的值近似为:3.141592653589793。
>>>print('常量PI的值近似为:{!r}。'.format(math.pi))
常量PI的值近似为:3.141592653589793。
可选项:
和格式标识符可以跟着字段名。这就允许对值进行更好的格式化。下面案例将pi保留到小数点后三位:
>>>import math
>>>print('常量PI的值近似为{0:.3f}。'.format(math.pi))
常量PI的值近似为3.142。
在:
后传入一个整数,可以保证该域至少有这么多的宽度。用于美化表格时很有用
>>>table = {'google': 1, 'qifen': 2, 'duck': 3}
>>>for name, number in table.items():
... print('{0:10} ==> {1:10d}'.format(name, number))
...
google ==> 1
qifen ==> 2
duck ==> 3
如果你有一个很长的格式化字符串,而你不想将他们分开,那么在格式化时通过变量名而非位置会是很好的事情。最简单的就是传入一个字典,然后使用方括号[]
来访问键值:
>>>table = {'google': 1, 'qifen': 2, 'duck': 3}
>>>print('qifen: {0[qifen]:d}; google: {0[google]:d}; duck: {0[duck]:d}'.format(table))
qifen: 2; google: 1; duck:3
也可以通过在table变量前使用**
来实现相同的功能:
>>>table = {'google': 1, 'qifen': 2, 'duck': 3}
>>>print('qifen: {qifen:d}; google: {google:d}; duck: {duck:d}'.format(**table))
qifen: 2; google: 1; duck:3
旧式字符串格式化
%
操作符也可以实现字符串格式化。它将左边的参数作为类似sprintf()
式的格式化字符串,而将右边的带入,然而返回格式化后的字符串,例如:
>>>import math
>>>print('常量PI的值近似为:%5.3%f。' % math.pi)
常量PI的值近似为:3.142。
因为str.format()是比较新的函数,大多数的Python代码仍然使用%操作符,但是因为这种旧式的格式化最终会从该语言中移除,应该更多的使用str.format()。
读取键盘输入
Python提供了input()内置函数从标准输入读入一行文本,默认的标准输入是键盘。input可以接收一个python表达式作为输入,并将运算结果返回。
#!/usr/bin/python3
str = input('请输入:')
print('你输入的是:', str)
运行输出:
请输入:qifen
你输入的是: qifen
读和写文件
open()将会返回一个file对象,基本语法如下:
open(filename, mode)
- filename:包含了你要访问的文件名称的字符串值
- mode:决定了打开文件的模式:只读,写入,追加等。所有可取值见如下的完全列表。这个参数是非强制的,默认文件访问模式为只读®。
不同模式打开文件的完全列表:
模式 | 描述 |
---|---|
r | 以只读方式打开文件,文件的指针将会放在文件的开头。这是默认的模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。 |
w | 打开一个文件只用于写入。如果该文件已经存在则打开文件,并从开头开始编辑,即原有内容会被删除,如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从头开始编辑,即原有内容会被删除,如果该文集爱你不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已经存在则打开这个文件,并从头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
a | 打开一个文件用于追加。如果该文件存在,文件指针将会放在文件的末尾,也就是说,新的内容将会被写入到已有的内容后面。如果文件不存在,创建文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件存在,文件指针将会放在文件的结尾,也就是说,新的内容将会被写入到已有内容之后。如果文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写,如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加,如果该文件存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
以下表格更直观:
模式 | r | r+ | w | w+ | a | a+ |
---|---|---|---|---|---|---|
读 | + | + | + | + | ||
写 | + | + | + | + | + | |
创建 | + | + | + | + | ||
覆盖 | + | + | ||||
指针在开始 | + | + | + | + | ||
指针在结尾 | + | + |
以下案例集那个字符串写入到文件test.txt中:
#!/usr/bin/python3
#在当前目录打开一个文件
f = open('./test.txt', 'w')
f.write('python是一个不错的语言。\n是的,的确不错!')
#关闭打开的文件
f.close()
- 第一个参数为要打开的文件名
- 第二个参数描述文件如何使用的字符,mode可以是’r’如果文件只读,'w’只用于写(如果存在同名文件则将被删除);和’a’用于追加文件内容,所写的任何数据都会被自动增加到末尾;'r+'同时用于读写。mode参数是可选的;'r’将是默认值。
此时在当前目录打开文件test.txt,显示如下:
python是一个不错的语言。
是的,的确不错!
文件对象的方法
本节中剩下的例子假设已经创建了一个称为f的文件对象。
f.read()
为了读取一个文件的内容,调用f.read(size),这将读取一定数目的数据,然后作为字符串或字节对象返回。
size是一个可选的数字类型的参数。当size被忽略了或者为负,那么该文件的所有内容都将被读取并返回。
以下实例假定test.txt已经存在(上面实例已经创建):
#!/usr/bin/python3
#打开一个文件
f = open('./test.txt', 'r')
str = f.read()
print(str)
#关闭打开的文件
f.close()
以上程序输出结果为:
python是一个不错的语言。
是的,的确不错!
f.readline()
f.readline()会从文件中读取单独的一行。换行符为’\n’。f.readline()如果返回一个空字符串,说明已经读取到最后一行。
#!/usr/bin/python3
#打开一个文件
f = open('./test.txt', 'r')
str = f.readline()
print(str)
f.close()
输出:python是一个不错的语言。
f.readlines()
f.readlines()将返回该文件中包含的所有行。如果设置可选参数sizehint,则读取指定长度的字节,并且将这些字节按行进行分割,案例:
#!/usr/bin/python3
#打开一个文件
f = open('./test.txt', 'r')
str = f.readlines()
print(str)
#关闭打开的文件
f.close()
执行以上程序,输出结果为:
['python是一个不错的语言。\n', '是的,的确不错!']
另一种方式是迭代一个文件对象然后读取每行:
#!/usr/bin/python3
#打开一个文件
f = open('./test.txt', 'r')
for line in f:
print(line, end = '')
#关闭打开的文件
f.close()
输出:
python是一个不错的语言。
是的,的确不错!
这个方法很简单,但是并没有提供一个很好的处理机制不同,最好不要混用。
f.write()
f.write(string)将string写入到文件中,然后返回写入的字符数。
#!/usr/bin/python3
#打开一个文件
f = open('./test.txt', 'w')
num = f.write('python是一个非常好的语言。\n是的,的确不错')
print(num)
#关闭打开的文件
f.close()
输出:24
如果要写入一些不是字符串的东西,那么将需要先进行转换:
#!/usr/bin/python3
#打开文件
f = open('./test.txt', 'w')
value = ('www.qifen.site', 14)
s = str(value)
f.write(s)
#关闭打开的文件
f.close()
打开test.txt文件,内容为:(‘www.qifen.site’, 14)
t.tell()
t.tell()返回文件对象当前所处的位置,它是从文件开头算起的字节数。
f.seek()
如果要改变文件当前的位置,可以使用f.seek(offset, from_what)函数。from_what的值,如果是0表示开头,如果是1表示当前位置,2表示文件结尾,例如:
- seek(x, 0): 从起始位置即文件首行首字符开始移动x个字符。
- seek(x, 1): 表示从当前位置往后移动x个字符。
- seek(-x, 2)表示从文件的结尾往前移动x字符
from_what值为默认为0,即文件开头。下面给出一个完整的例子:
>>>f.write(b'0123456789abcdef')
16
>>>f.seek(5) #移动到文件的第六个字节
5
>>>f.read(1)
b'5'
>>>f.seek(-3, 2) #移动到文件的倒数第三个字节
13
>>>f.read(1)
b'd'
f.close()
在文本文件中(那些打开文件的模式下没有b的),只会相对于文件起始位置进行定位。当你处理完一个文件后,调用f.close()来关闭文件并释放系统的资源,如果尝试再调用该文件,则会抛出异常。
>>>f.close()
>>>f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ValueError: I/O operation on closed file
当处理一个文件对象时,使用with关键字时非常好的方式。在结束后,它会帮你正确的关闭文件。而且写起来也比try-finally语句块要简短:
>>>with open('./test.txt', 'r') as f:
... read_data = f.read()
...
>>>f.closed
True
文件对象还有其它方法,如isatty()和trucate(),但这些通常比较少用。
pickle模块
python的pickle模块实现了基本的数据序列和反序列化,通过pickle模块的序列化操作我们能将程序中运行的对象信息保存到文件中去,永久存储。通过pickle模块的反序列化操作,我们能够从文件中创建上一次程序保存的对象,基本接口:
pickle.dump(obj, file[, protocol])
有了pickle这个对象,就能够对file以读取的形式打开:
x = pickle.load(file)
注解:从file中读取一个字符串,并将它重构为原来的python对象。
file:类文件对象,有read()和readline()接口。
案例1:
#!/usr/bin/python3
import pickle
#使用pickle模块将数据对象保存到文件
data1 = {'a': [1, 2.0, 3, 4+6j], 'b': ('string', u'Unicode string'), 'c': None}
selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)
output = open('data.pk1', 'wb')
pickle.dump(data1, output)
pickle.dump(selfref_list, output, -1)
output.close()
案例2:
#!/usr/bin/python3
import pprint, pickle
pkl_file = open('data.pkl', 'rb')
data1 = pickle.load(pkl_file)
pprint.pprint(data1)
data2 = pickle.load(pkl_file)
pprint.pprint(data2)
pkl_file.close()
此案例中展示了序列化与反序列化
Python3 File
open()方法
Python open()方法用于打开一个文件,并返回文件对象,在对文件进行处理过程都需要这个函数,如果该文件无法被打开,会抛出OSError。
注意:使用open()方法一定要保证关闭文件对象,即调用close()方法。
open()函数常用形式是接收两个参数:文件名(file)和模式(mode):
open(file, mode = 'r')
完整的语法格式为:
open(file, mode = 'r', buffering = -1, encoding = None, errors = None, newline = None, closefd = Ture, opener = None)
参数说明:
- file:必须,文件路径(相对或者绝对路径)
- mode:可选,文件打开模式
- buffering:设置缓冲
- encoding:一般用utf-8
- errors:报错级别
- newline:区分换行符
- closefd:传入的file参数类型
- opener:
mode参数有:
模式 | 描述 |
---|---|
t | 文本模式(默认) |
x | 写模式,新建一个文件,如果该文件已经存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
U | 通用换行模式(Python3不支持)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认的模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在已存在则打开文件,并从头开始编辑,即原有内容会被删除,如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写,如果该文件已存在则打开文件,并从头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件存在,文件指针将会放在文件结尾。也就是说,新的内容将会被写入到已有内容之后,如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,则指针会放在文件结尾。也就是说,新的内容会被写入到已有内容之后。如果文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件存在,文件指针会在内容结尾,文件打开时会是追加模式。如果文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加,如果该文件存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
默认为文本模式,如果要以二进制模式打开,加上b
。
file对象
file对象使用open函数来创建,下表列出了file对象常用的函数:
函数 | 描述 |
---|---|
file.close() | 关闭文件,关闭后文件不能再进行读写操作。 |
file.flush() | 刷新文件内部缓冲,直接把内部缓冲区的数据立刻写入文件,而不是被动的等待输出缓冲区写入。 |
file.fileno() | 返回一个整型的文件描述符(file descriptor FD整形),可以用在如os模块的read方法等一些底层操作上。 |
file.isatty() | 如果文件连接到一个终端设备返回True,否则返回False。 |
file.next() | 返回文件的下一行(Python3中的File对象不支持next()方法)。 |
file.read([size]) | 从文件读取指定的字节数,如果未给定或为负数则读取所有。 |
file.readline([size]) | 读取整行,包括’\n’字符。 |
file.readlines([sizeint]) | 读取读取所有行并返回列表,若给定sizeint>0,返回总和大约为sizeint字节的行,实际读取值可能比sizeint较大,因为需要填充缓冲区。 |
file.seek(offset[, whence]) | 移动文件读取指针到指定位置。 |
file.tell() | 返回文件当前位置。 |
file.truncate([size]) | 从文件的首行首字符开始截断,截断文件为size个字符,无size表示从当前位置截断;截断之后后面的所有字符被删除,其中Windows系统下的换行代表2个字符大小。 |
file.write(str) | 将字符串写入文件,返回的是写入的字符长度。 |
file.writelines(sequence) | 向文件写入一个序列字符串列表,如果需要换行则要自己加入每行的换行符号。 |
Python3 OS文件/目录方法
os模块提供了非常丰富的方法用来处理文件和目录。常用的方法如下表所示:
方法 | 描述 |
---|---|
os.access(path, mode) | 校验权限模式 |
os.chdir(path) | 改变当前工作目录 |
os.chfiags(path, flags) | 设置路径的标记为数字标记 |
os.chmod(path, mode) | 更改权限 |
os.chroot(path) | 改变当前进程的根目录 |
os.close(fd) | 关闭文件描述符fd |
os.closerange(fd_low, fd_high) | 关闭所有文件描述符,从fd_low(包含)到fd_high(不包含),错误会忽略 |
os.dup(fd) | 复制文件描述符fd |
os.dup2(fd, fd2) | 将一个文件描述符fd复制到另一个fd2 |
os.fchdir(fd) | 通过文件描述符改变当前工作目录。 |
fchmod(fd, mode) | 改变一个文件的访问权限,该文件由参数fd指定,参数mode是Unix下的文件访问权限。 |
os.fchown(fd, uid, gid) | 修改一个文件的所有权,这个函数修改一个文件的用户ID和用户组ID,该文件由文件描述符fd指定。 |
os.fdatasync(fd) | 强制写入磁盘,该文件由文件描述符fd指定,但是不强制更新文件的状态信息。 |
os.fdopen(fd[, mode[, bufsize]]) | 通过文件描述符fd创建一个文件对象,并返回这个文件对象 |
os.fpathconf(fd, name) | 返回一个打开的文件的系统配置信息。name为检索的系统配置的值,它也许是一个定义系统值的字符串,这些名字存在很多标准中指定(POSIX.1, Unix 95, Unix 98, 和其它)。 |
os.fstat(fd) | 返回文件描述符fd的状态,像stat() |
os.fstatvfs(fd) | 返回包含文件描述符fd的文件系统的信息,Python3.3相等于statvfs() |
os.fsync(fd) | 强制将文件描述符为fd的文件写入磁盘 |
os.ftruncate(fd, length) | 裁减文件描述符fd对应的文件,所以它最大不能超过文件大小 |
os.getcwd() | 返回当前工作目录 |
os.isatty(fd) | 如果文件描述符fd是打开的,同时tty(-like)设备相连,则返回True,否则False。 |
os.lchflags(path, flags) | 设置路径的标记为数字标记,类似chflags(),但是没有软连接 |
os.lchmod(path, mode) | 修改连接文件权限 |
lchown(path, uid, gid) | 更改文件所有者,类似chown,但是不追踪链接 |
os.link(src, dst) | 创建硬链接,名为dst,指向参数src |
os.listdir(path) | 返回path指定的文件夹包含的文件获文件夹的名字的列表 |
os.lseek(fd, pos, how) | 设置文件描述符 fd当前位置为pos, how方式修改: SEEK_SET 或者 0 设置从文件开始的计算的pos; SEEK_CUR或者 1 则从当前位置计算; os.SEEK_END或者2则从文件尾部开始. 在unix,Windows中有效 |
os.lstat(path) | 像stat(),但是没有软连接 |
os.major(device) | 从原始的设备号中提取设备major号码(使用stat中的st_dev或者st_rdev field) |
os.makedev(major, minor) | 以major和minor设备号组成一个原始设备号 |
os.makedirs(path[, mode]) | 递归文件夹创建函数。像mkdir(),但创建的所有intermediate-level文件夹需要包含子文件夹 |
os.minor(device) | 从原始的设备号中提取设备minor号码(使用stat中的st_dev或者str_rdev field) |
os.mkdir(path[, mode]) | 以数字mode的mode创建一个名为path的文件夹,默认的mode是0777(八进制) |
os.mkfifo(path[, mode]) | 创建命名管道,mode为数字,默认为0666(八进制) |
os.mknod(filename[, mode=0600, device]) | 创建一个名为filename文件系统节点(文件,设备特别文件或者命名pipe) |
os.open(file, flags[, mode]) | 打开一个文件,并且设置需要的打开选项,mode参数是可选的 |
os.openpty() | 打开一个新的伪终端对,返回pty和tty的文件描述符 |
os.pathconf(path, name) | 返回相关文件的系统配置信息 |
os.pipe() | 创建一个管道,返回一对文件描述符(r, w)分别为读和写 |
os.popen(command[, mode[, bufsize]]) | 从一个command打开一个管道 |
os.read(fd, n) | 从文件描述符fd中读取最多n个字节,返回包含读取字节的字符串,文件描述符fd对应文件已达到结尾,返回一个空字符串 |
os.readlink(path) | 返回软链接所指向的文件 |
os.remove(path) | 删除路径为path的文件,如果path是一个文件夹,将抛出OSError;查看下面的rmdir()删除一个directory |
os.removedirs(path) | 递归删除目录 |
os.rename(src, dst) | 重命名文件或目录,从src到dst |
os.renames(old, new) | 递归对目录进行改名,也可以对文件进行改名 |
os.rmdir(path) | 删除path指定的空目录,如果目录为非空,则抛出一个OSError异常 |
os.stat(path) | 获取path指定的路径的信息,功能等同于C API中stat()系统调用 |
os.stat_float_times([newvalue]) | 决定stat_result是否以float对象显示时间戳 |
os.statvfs(path) | 获取指定路径的文件系统统计信息 |
os.symlink(src, dst) | 创建一个软链接 |
os.tcgetpgrp(fd) | 返回与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组 |
os.tcsetpgrp(fd, pg) | 设置与终端fd(一个由os.open()返回的打开的文件描述符)关联的进程组为pg |
os.tempnam([dir[, prefix]]) | Python3中已删除。返回唯一的路径名用于创建临时文件 |
os.tmpfile() | Python3中已经删除。返回一个打开的模式为(w+b)的文件对象,这文件对象没有文件夹入口,没有文件描述符号,将会自动删除 |
os.tmpnam() | Python3中已删除。为创建一个临时文件返回一个唯一的路径 |
os.ttyname(fd) | 返回一个字符串,它表示与文件描述符fd关联的终端设备。如果fd没有与终端设备关联,则引发一个异常。 |
os.unlink(path) | 删除文件路径 |
os.utime(path, times) | 返回指定的path文件的访问和修改的时间 |
os.walk(top[, topdown = True[, onerror = None[, followlinks = False]]]) | 输出在文件夹中的文件名通过在树中游走,向上或者向下 |
os.write(fd, str) | 写入字符串到文件描述符fd中,返回实际写入的字符串长度 |
os.path模块 | 获取文件的属性信息 |
Python3错误和异常
Python有两种错误很容易辨认:语法错误和异常。
语法错误
Python的语法错误或者称之为解析错,是初学者经常碰到的,如下实例:
>>>where True print('hello world')
File "<stdin>", line 1
where True print('hello world')
^
SyntaxError: invalid syntax
这个例子中,函数print()被检查到有错误,是它前面缺少一个冒号:
,语法分析器指出了出错的一行,并且在最先找到的错误的位置标记了一个小小的箭头。
异常
即便Python程序的语法是正确的,在运行它的时候,也有可能会发生错误。运行期检测到的错误被称为异常。大多数的异常都不会被程序处理,都以错误信息的形式展现在这里:
>>> 10 * (1 / 0) #0不能作为除数,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + apam * 3 #spam未定义,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'apam' is not defined
>>> '2' + 2 #int不能与str相加,触发异常
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: must be str, not int
异常以不同的类型出现,这些类型都作为信息的一部分打印出来:例子中的类型有ZeroDivisionError,NameError和TypeError。错误信息的前面部分显示了异常发生的上下文,并以调用栈的形式显示具体信息。
异常处理
try/except
异常捕捉可以使用try/except
语句
以下案例中,用户输入一个合法的整数,但是允许用户中断这个程序(ctrl+c终止)。用户中断的信息会发生一个KeyboardInterrupt异常。
while True:
try:
x = int(input('请输入一个数字:'))
break
except ValueError:
print('你输入的不是数字,请你再次输入!')
try语句按照如下方式工作:
- 首先,执行try子句(在关键字try和关键字except之间的语句)。
- 如果没有异常发生,忽略except子句,try子句执行后结束。
- 如果在执行try子句的过程中发生了异常,那么try子句余下的部分将被忽略。如果异常的类型和except之后的名称相符,那么对应的except子句将执行。
- 如果一个异常没有与任何的except匹配,那么这个异常将会传递给上层的try中。
一个try语句可能包含多个except子句,分别来处理不同的特定异常。最多只有一个分支会执行,处理程序将只对应的try子句中的异常进行处理,而不是其它的try的处理程序中的异常。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:
except (RuntimeError, TypeError, NameError):
pass
最后一个expect子句可以忽略异常的名称,它即将被当作通配符使用
#!/usr/bin/python3
import sys
try:
f = open('./test.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print('OS error: {0}'.format(err))
except ValueError:
print('你输入的不是整数!')
except:
print('未知错误:', sys.exc_info()[0])
raise
try/except…else
try/except...else
语句还有一个可选的else
子句,如果使用这个子句,那么必须放在所有的except子句之后。else子句将在try子句没有发生任何异常的时候执行。
以下实例在try语句中判断文件时候可以打开,如果打开文件时正常的没有发生异常则执行else部分语句,读取文件内容:
#!/usr/bin/python3
import sys
for arg in sys.argv[1:]:
try:
f = open(arg, 'r')
except IOError:
print('不能打开文件', arg)
else:
print(argv, 'has', len(f.readline(), 'lines'))
f.close()
使用else子句比把所有的语句都放在try子句里面要好,这样可以避免一些意想不到,而expect又无法捕获的异常。
异常处理并不仅仅处理那些直接发生在try子句中的异常,而且还能处理子句中调用的函数(甚至间接调用的函数)里抛出的异常。例如:
>>>def this_fails();
... x = 1 / 0
...
>>>try:
... this_fails()
...except ZeroDivisionError as err:
... print('Handling run-time error:', err)
...
Handling run-time error: division by zero
try-finally语句
try-finally语句无论是否发生异常都将执行最后的代码。以下实例中finally语句无论异常是否发生都会执行:
#!/usr/bin/python3
try:
qifen()
except Assertion as error:
print(error)
else:
try:
with open('./testt.txt') as file:
read_data = file.read()
except FileNotFoundError as fnf_error:
print(fnf_error)
finally:
print('无论异常与否都会执行')
抛出异常
Python使用raise
语句抛出一个指定的异常。raise语法格式如下:
raise [Exception[, args[, traceback]]]
以下实例如果x大于5就触发异常:
x = 10
if x > 5:
raise Exception('x不能大于5,x的值为: {}',.format(x))
raise唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是Exception的子类)。
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的raise语句就可以再次把它抛出。
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flow by!')
... raise
...
An exception flow by!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: HiThere
用户自定义异常
你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自Exception类,可以直接继承,或者间接继承,例如:
>>> class MyError(Exception):
... def __init__(self, value):
... self.value = value
... def __str__(self):
... return repr(self.value)
...
>>> try:
... raise MyError(2 * 2)
... except MyError as e:
... print('My exception occurred, value:', e.value)
...
My exception occurred, value: 4
>>> raise MyError('oops!')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyError: 'oops!'
在这个例子中,类Exception默认的__init__()被覆盖。
当创建一个模块有可能抛出多种不同的异常时,一种通常的做法是为这个包建立一个基础异常类,然后基于这个基础类为不同的错误情况创建不同的子类:
class Error(Exception):
"""Base class for exception in this module"""
pass
class InputError(Error):
"""Exception raise for
errors in the input"""
def __init__(self, expression, message):
self.expression = expression
self.message = message
class TransitionError(Error):
"""Raised when an operation attemopts a state transition
that's not allowed"""
def __init__(self, previous, next, message):
self.previons = previous
self.next = next
self.message = message
大多数的异常的名字都以"Error"结尾,就跟标准的异常命名一样。
定义清理行为
try语句还有另外一个可选的语句,它定义了无论在任何情况下都会执行的清理行为。例如:
>>> try:
... raise KeyboardInterrupt
... finally:
... print('goodbye,world!')
...
goodbye,world!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
KeyboardInterrupt
以上例子不管try子句里面有没有发生异常,finally子句都会执行。
如果一个异常在try子句里(或者在except和else子句里)被抛出,而又没有任何的except把它截住,那么这个异常在finally子句执行后被抛出。
下面是一个更加复杂的例子(在同一个try语句里包含了except和finally子句):
>>> def divide(x, y):
... try:
... result = x / y
... except ZeroDivisionError:
... print('division by zero')
... else:
... print('result is', result)
... finally:
... print('executing finally clause')
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero
executing finally clause
>>> devide('2', '1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'devide' is not defined
预定义的清理行为
一些对象定义了标准的清理行为,无论系统是否成功的使用了它,一旦不需要它了,那么这个标准的清理行为就会执行。
下面这个例子展示了尝试打开一个文件,然后把内容打印到屏幕上:
for line in open('./test.txt'):
print(line, end = '')
以上这段代码的问题是,执行完毕后,文件会保持打开状态,并没有被关闭。
关键字with
语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行他的清理方法:
#!/usr/bin/python3
with open('./test.txt') as f:
for line in f:
print(line, end = '')
以上这段代码执行完毕后,就算在处理中出了问题,文件f总是会关闭。
Python3面向对象
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。
面向对象技术简介
- 类:用于描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类并且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关数据
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用self修饰的变量。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
- 实例:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
和其它编程语言相比,Python在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中同名方法。
类定义
语法格式如下:
class ClassName:
def def1:
def defN:
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
类对象
类对象支持两种操作:属性引用和实例化。
属性引用使用和Python中所有的属性引用一样的标准语法:obj.name。
类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样的:
#!/usr/bin/python3
class MyClass:
"""一个简单的类实例"""
i = 12345
def f(self):
return 'hello world'
#实例化类
x = MyClass()
#访问类的属性和方法
print("MyClass类的属性 i 为:", x.i)
print("MyClass类的方法 f 输出为", x.f())
以上创建了一个新的类实例并将该对象赋给局部变量x, x为空的对象,输出:
MyClass类的属性 i 为: 12345
MyClass类的方法 f 输出为 hello world
类有一个名为__init__()的特殊方法(构造方法
),该方法在类实例化时会自动调用,像下面这样:
def __init__(self):
self.data = []
类定义了__init__()方法,类的实例化操作会自动调用__init__()方法。如下实例化类MyClass,对应的__init__()方法就会被调用:
x = MyClass()
当然,__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上。例如:
#!/usr/bin/python3
class Complex:
def __init__(self, realpart, imagpart):
self.r = realpart
self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i) #输出结果:3.0 -4.5
self代表类的实例,而非类
类的方法与普通的函数只有一个特别的区别–他们必须有一个额外的第一个参数名称,按照惯例它的名称是self。
class Test:
def prt(self):
print(self)
print(self.__class__)
t = Test()
t.prt()
输出:
<__main__.Test object at 0x7f679f680e10>
<class '__main__.Test'>
从执行结果可以明显看出,self代表的是类的实例,代表当前对象的地址,而self.class则指向类。
self不是python关键字,我们把他换成qifen也是可以正常执行的:
class Test:
def prt(qifen)
print(qifen)
print(qifen.__class__)
t = Test()
t.prt()
#输出和上面一样
类的方法
在类的内部,使用def
关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数self,且为第一个参数,self代表的是类的实例。
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print('%s 说: 我 %d 岁。'%(self.name, self.age))
#实例化类
p = people('qifen', 10, 30)
p.speak()
输出:qifen 说: 我 10 岁。
继承
Python同样支持类的继承,如果一种语言不支持继承,类就没有意义了,派生类的定义如下所示:
class DerivedClassName(BaseClassName1):
def fun1:
def funN:
需要注意圆括号中基类的顺序,若是基类中有相同的方法名,而在子类使用时未指定,Python从左到右搜索,即方法在子类中未找到时,从左到右查找基类中是否包含方法。
BaseClassName(示例中基类名),必须与派生类定义在一个作用域内,除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用。
class DerivedClassName(modname.BaseClassName):
案例:
#!/usr/bin/python3
#类定义
class people:
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接进行访问
__weight = 0
#定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print('%s 说:我 %d 岁。'%(self.name, self.age))
#单继承示例
class student(people):
grade = ''
def __init__(self, n, a, w, g):
#调用父类的构造
people.__init__(self, n, a, w)
self.grade = g
#覆写父类的方法
def speak(self):
print('%s 说:我 %d 岁了,在读 %d 年级'%(self.name, self.age, self.grade))
s = student('qifen', 10, 60, 3)
s.speak()
输出:qifen 说:我 10 岁了,在读 3 年级
多继承
Python同样有限的支持多继承形式。多继承的类定义如下例:
class DerivedClassName(Base1, Base2, Base3):
def fun1:
def funN:
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左到右搜索,即方法在子类中未找到时,从左到右查找父类中是否包含方法。
#!/usr/bin/python3
#类定义
class people:
#定义基本属性
name = ''
age = 0
#定义私有属性,私有属性在类外部无法直接访问
__weight = 0
#定义构造方法
def __init__(self, n, a, w):
self.name = n
self.age = a
self.__weight = w
def speak(self):
print('%s 说:我 %d 岁。'%(self.name, self.age))
#单例继承示例
class student(people):
grade = ''
def __init__(self, n, a, w, g):
people.__init__(self, n, a, w)
self.grade = g
#覆写父类的方法
def speak(self):
print('%d 说:我 %d 岁了,我在读 %d 年级'%(self.name, self.age, self.grade))
#另一个类,多重继承之前的准备
class speaker():
topic = ''
name = ''
def __init__(self, n, t):
self.name = n
self.topic = t
def speak(self):
print('我叫 %s,我是一个演说家,我演讲的主题是 %s'%(self.name, self.topic))
#多重继承
class sample(speaker, student):
a = ''
def __init__(self, n, a, w, g, t):
student.__init__(self, n, a, w, g)
speaker.__init__(self, n, t)
test = sample('qifen', 25, 80, 4, 'Python')
test.speak() #方法名同,默认用的是在括号中排前地父类的方法
输出:我叫 qifen,我是一个演说家,我演讲的主题是 Python
方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:
#!/usr/bin/python3
class Parent:
def myMethod(self):
print('调用父类方法')
class Child(Parent): #定义子类
def myMethod(self):
print('调用子类方法')
c = Child() #子类实例
c.myMethod() #子类调用重写方法
super(Child, c).myMethod() #用子类对象调用父类已被覆盖的方法
super()函数是用于调用父类(超类)的一个方法。执行后输出:
调用子类方法
调用父类方法
类属性与方法
类的私有属性
__private_sttrs:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时self.__private_attrs。
类的方法
在类的内部,使用def关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数self
,且为第一个参数,self代表的是类的实例。self的名字并不是规定死的,也可以使用this,但是最好还是按照约定是用self。
类的私有方法
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用,不能在类的外部调用。self.__private_methods。
实例
类的私有属性实例如下:
#!/usr/bin/python3
class JustCounter:
__secretCount = 0 #私有变量
publicCount = 0 #公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print(self.__secretCount)
counter = JustCounter()
counter.count()
counter.count()
print(counter.publicCount)
print(counter.__secretCount) #报错,实例不能访问私有变量
输出:
1
2
2
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 13, in <module>
print(counter.__secretCount) #报错,实例不能访问私有变量
AttributeError: 'JustCounter' object has no attribute '__secretCount'
类的私有方法实例如下:
#!/usr/bin/python3
class Site:
def __init__(self, name, url):
self.name = name #public
self.__url = url #private
def who(self):
print('name:', self.name)
print('url:', self.__url)
def __foo(self): #私有方法
print('这是私有方法')
def foo(self): #公共方法
print('这是公共方法')
self.__foo()
x = Site('qifen', 'www.qifen.site')
x.who() #正常输出
x.foo() #正常输出
x.__foo() #报错
输出:
name: qifen
url: www.qifen.site
这是公共方法
这是私有方法
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 17, in <module>
x.__foo() #报错
AttributeError: 'Site' object has no attribute '__foo'
类的专有方法
- __init__:构造方法,在生成对象时调用
- __del__:解构函数,释放对象时使用
- __repr__:打印,转换
- __setitem__:按照索引赋值
- __getitem__:按照索引获取值
- __len__:获得长度
- __cmp__:比较运算
- __call__:函数调用
- __add__:加运算
- __sub__:减运算
- __mul__:乘运算
- __truediv__:除运算
- __mod__:求余运算
- __pow__:乘方
运算符重载
Python同样支持运算符重载,我们可以对类的专有方法进行重载,实例如下:
#!/usr/bin/python3
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)'%(self.a, self.b)
def __add__(self, other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
v2 = Vector(5, -2)
print(v1 + v2)
输出:Vector(7, 8)
Python3命名空间和作用域
命名空间
先看官方文档的一段话:
A namespace is a mapping from names to objects,Most namespaces are currently implemented as Python dictionaries.
命名空间(Namespace)是从名称到对象的映射,大部分的命名空间都是通过Python字典来实现的。
命名空间提供了在项目中避免名字冲突的一种方法。各个命名空间都是独立的,没有任何关系的,所以一个命名空间中不能有重名,但不同的命名空间是可以重命名而没有任何影响。
一般有三种命名空间:
- 内置名称(built-in names),Python语言内置的名称,比如函数名abs、char和异常名称BaseException、Exception等等。
- 全局名称(global names),模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称(local names),函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
命名空间查找顺序:假设我们要使用变量qifen,则Python的查找顺序为:局部命名空间->全局命名空间->内置命名空间,如果找不到变量qifen,他将放弃查找并引发一个NameError异常:
NameError: name 'qifen' is not defined.
命名空间的生命周期:命名空间的生命周期取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。因此我们无法从外部命名空间访问内部命名空间的对象。案例:
#!/usr/bin/python3
#var1是全局变量
var1 = 5
def some_func:
#var2是局部名称
var2 = 6
def some_inner_func():
#var3是内嵌的局部名称
var3 = 7
作用域
作用域就是一个Python程序可以直接访问命名空间的正文区域。在一个Python程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则报未定义的错误。在Python中,程序的变量访问权限决定这个变量是在哪里赋值的。
变量的作用域决定了在哪一部份程序可以访问哪个特定的变量名称。Python的作用域分四种,分别是:
- L(local):最内层,包含局部变量,比如一个函数/方法内部。
- E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。
- G(Global):当前脚本的最外层,比如当前模块的全局变量。
- B(Built-in):包含了内建的变量/关键字等,最后被搜索
在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内置中找。规律顺序:L->E->G->B
g_count = 0 #全局作用域
def outer():
o_count = 1 #闭包函数外的函数中
def inner():
i_count = 2 #局部作用域
内置作用域是通过一个名为builtin的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能使用它。再Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:
>>>import builtins
>>>dir(builtins)
Python中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:
>>>if True:
... msg = 'I am from qifen'
...
>>>msg
'I am from qifen'
实例中msg变量定义在if语句块中,但外部还是可以访问的。
如果将msg定义在函数中,则它就是局部变量,外部不能访问:
>>>def test():
... msg_inner = 'qifen'
...msg_inner
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'msg_inner' is not defined
从报错的信息上看,说明了msg_inner未定义,无法使用,因为它是局部变量,只有在函数内可以使用。
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局变量作用域。
局部变量只能再其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:
#!/usr/bin/python3
total = 0 #这是全局变量
#可写函数说明
def sum(arg1, arg2):
#返回两个参数的和
total = arg1 + arg2 #total在这里是局部变量
print('函数的局部变量是:', total)
return total
#调用sum函数
sum(10, 20)
print('函数外是全局变量:', total)
输出:
函数的局部变量是: 30
函数外是全局变量: 0
global和nonlocal关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了。以下实例修改全局变量num:
#!/usr/bin/python3
num = 1
def fun1():
global num #需要使用global关键字声明
print(num)
num = 123
print(num)
fun1()
print(num)
输出:
1
123
123
如果要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量则需要nonlocal关键字了,如下实例:
#!/usr/bin/python3
def outer():
num = 10
def inner():
nonlocal num #nonlocal关键字声明
num = 100
print(num)
inner()
print(num)
outer()
输出:
100
100
另外有一种特殊情况,假设下面这段代码被运行:
#!/usr/bin/python3
a = 10
def test():
a = a + 1
print(a)
test()
以上程序执行,报错信息如下:
Traceback (most recent call last):
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 6, in <module>
test()
File "/home/qifen/Projects/vscodecprojects/test/app.py", line 4, in test
a = a + 1
UnboundLocalError: local variable 'a' referenced before assignment
错误信息为局部作用域引用错误,因为test函数中a使用的是局部,未定义,无法修改。修改a为全局变量,通过函数参数传递,可以正常执行输出结果为:
#!/usr/bin/python3
a = 10
def test(a):
a = a + 1
print(a)
test(a)
输出:11
Python3标准库概览
操作系统接口
os模块提供了不少与操作系统相关联的函数。
>>>import os
>>>os.getcwd() #返回当前的工作目录
'/home/qifen/'
>>>os.chdir('/home') #修改当前的工作目录
>>>os.system('ls') #执行系统命令ls
qifen
0
建议使用’import os’,而非’from os import *’。这样可以保证随操作系统不同而有所变化的os.open()不会覆盖内置函数open()。
在使用os这样的大型模块时内置的dir()和help()函数非常有用:
>>>import os
>>>dir(os)
<returns a list of all module functions>
>>>help(os)
<returns an extensive manual page created from the module's docstrings>
针对日常的文件和目录管理任务,:mod:shutil模块提供了一个易于使用的高级接口:
>>>import shutil
>>>shutil.copyfile('data.db', 'archive.db')
>>>shutil.move('/build/executable', 'installdir')
文件通配符
glob模块提供了一个函数用于从目录通配符搜索中生成文件列表:
>>>import glob
>>>glob.glob('*.py')
['primes.py', 'random.py', 'quote.py']
命令行参数
通用工具脚本经常调用命令行参数。这些命令行参数以链表形式存储在sys模块的argv变量。例如在命令行中执行’python demo.py one two three’后可以得到以下输出结果:
>>>import sys
>>>print(sys.argv)
['demo.py', 'one', 'two', 'three']
错误输出重定向和程序终止
sys还有stdin,stdout和stderr属性,即使在stdout被重定向时,后者也可以用于显示警告和错误信息。
sys.stderr.write('Warning, log file not found starting a new one\n')
Warning, log file not found starting a new one
47
大多脚本的定向终止都使用’sys.exit()’。
字符串正则匹配
re模块为高级字符串处理提供了正则表达式工具。对于复杂的匹配和处理,正则表达式提供了简洁、优雅的解决方案:
>>>import re
>>>re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>>re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
如果只需要简单的功能,应该首先考虑字符串方法,因为他们非常简单,易于阅读和调试:
>>>'tea for too'.replace('too', 'two')
'tea for two'
数学
math模块为浮点运算提供了对底层C函数库的访问:
>>>import math
>>>math.cos(math.pi / 4)
0.7071067811865476
>>>math.log(1024, 2)
10.0
random提供了生成随机数的工具
>>> random.choice(['apple', 'pear', 'banana']) #匹配3个里面的一个
'pear'
>>> random.sample(range(100), 10) #在一个区间匹配10次
[15, 81, 63, 43, 53, 67, 87, 9, 10, 83]
>>> random.random() #浮点随机
0.5962925102892486
>>> random.randrange(6) #0-6随机
3
访问互联网
有几个模块用于访问互联网以及处理网络通信协议。其中最简单的两个是用于处理从urls接收的数据的urllib.request以及用于发送电子邮件的smtplib:
>>>form urllib.request import urlopen
>>>for line in urlopen('http://www.qifen.site'):
... line = line.decode('utf-8')
... print(line)
...
省略get请求到的一堆内容...
>>>import smtplib
>>>server = smtplib.SMTP('localhost')
>>>server.sendmail('858810078@qq.com', 'xxx@qq.com','hello world')
>>>server.quit()
注意发邮件需要本地有一个在运行的邮件服务器。
日期和时间
datatime模块为日期和时间处理同时提供了简单和复杂的方法。
支持日期和时间算法的同时,实现的重点放在更有效的处理和格式化输出,该模块还支持时区处理:
>>> from datetime import date
>>> now = date.today()
>>> now
datetime.date(2020, 3, 6)
>>> now.strftime('%m-%d-%y. %d %b %y is a %A on the %d day of %B.')
'03-06-20. 06 Mar 20 is a Friday on the 06 day of March.'
>>> birthday = date(2000, 2, 15)
>>> age = now - birthday
>>> age.days
7325
数据压缩
以下模块直接支持通用的数据打包和压缩格式:zlib、gzip、gzip、bz2、zipfile,以及tarfile。
>>>import zlib
>>>s = b'witch witch has which witches wrist watch'
>>>len(s)
41
>>>t = zlib.compress(s) #压缩
>>>len(t)
37
>>>zlib.decompress(t) #解压
b'witch witch has which witches wrist watch'
>>>zlib.crc32(s)
226805979
性能度量
有些用户对了解解决同一问题的不同方法之间的性能差异很感兴趣。Python提供了一个度量工具,为这些问题提供了直接答案。
例如,使用元组封装和拆封来交换元素看起来要比传统的方法要诱人的多,timeit证明了现代的方法更快一些。
>>>from timeit import Timer
>>>Timer('t = a; a = b; b = t', 'a = 1; b = 2').timeit()
0.042132629023399204
>>>Timer('a, b = b, a', 'a = 1; b = 2').timeit()
0.045468199998140335
相对于timeit的细粒度,:mod:profile和pstats模块提供了针对更大代码块的时间度量工具。