1.简介
这个帖子的主要对Python的一些语法进行了总结,主要包括的是Python语言与其他编程语言所不同的部分,内容大多来源于网络。
2.Python编程基础
2.1 id()
id()函数可返回对象的内存地址,python中会为每个对象分配内存,哪怕他们的值完全相等。id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。
2.2 输入输出函数
2.2.1 Input()
输入函数格式为input([prompt]),prompt是可选的,是提示信息。返回值是从键盘输入的一行文本,默认为字符串类型。不过也可以用类型转换函数进行显式的转换。
a = input("请输入字符串:")
b = int(input(("请输入一个整数:")))
c = float(input("请输入一个数值:"))
2.2.2 eval()
用于去掉字符串最外侧的引号,并按照Python语句方式执行去掉引号后的字符串,eval()函数经常和input()函数一起使用。
具体语法为:
eval(expression[, globals[, locals]])
-
expression – 表达式。
-
globals – 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。
-
locals – 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。
使用实例
s='3.14+3'
print(s,type(s))
x=eval(s) # 使用eval函数去掉s这个字符串中左右的引号 ,执行加法运算
print(x,type(x))
hello='北京欢迎你'
print(hello)
print(eval('hello')) # 输出了"北京欢迎你"
print(eval('北京欢迎你')) # NameError: name '北京欢迎你' is not defined
输出结果
3.14+3 <class 'str'>
6.140000000000001 <class 'float'>
北京欢迎你
北京欢迎你
NameError: name '北京欢迎你' is not defined
特别注意的是最后一行运行会报错。
2.2.3print()
输出函数,其具体语法为:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
输出函数可以支持输出多个对象,输出拼接的字符串和输出到文本文件中,还可以输出ASCII码和Unicode码对应的文字。
a=100
b=50
print(a,b,'要么出众,要么出局!!!')
#输出ASCII和Unicode对应字符
print(8)
print(chr(56))
print('[')
print(chr(91))
print(ord('北'))
print(ord('京'))
print(chr(21271),chr(20140))
# 输出到文件
fp=open('note.txt','w') # 打开文件 w-->write
print('北京欢迎你',file=fp) # 将"北京欢迎你" 输出(写入)到note.txt文件中
fp.close() # 关闭文件
如果需要输出一定位数的浮点型数字,可以用函数round()
2.4 基础运算符
赋值运算符包含-=、+=、/=、//=
运算符优先级如下
与C++不同的是,多了个整除运算符“//”,其返回值是整数,除法运算符“/”的返回值为浮点型。
此外~表示按位取反。
2.5 程序流程控制
Python在程序流程控制这里有if判断语句、for和while循环语句,其中如果为空语句,则需要写pass。
在python 3.10加入了switch语句,即match…case,其具体语法为:
match expression:
case pattern1:
# 处理pattern1的逻辑
case pattern2 if condition:
# 处理pattern2并且满足condition的逻辑
case _:
# 处理其他情况的逻辑
3.关键字
3.1 with
Python 中的 with 语句用于异常处理,封装了 try…except…finally 编码范式,提高了易用性。
例如
file = open('./test_runoob.txt', 'w')
file.write('hello world !')
file.close()
以上代码如果在调用 write 的过程中,出现了异常,则 close 方法将无法被执行,因此资源就会一直被该程序占用而无法被释放。 接下来我们呢可以使用 try…except…finally 来改进代码:
file = open('./test_runoob.txt', 'w')
try:
file.write('hello world')
finally:
file.close()
以上代码我们对可能发生异常的代码处进行 try 捕获,发生异常时执行 except 代码块,finally 代码块是无论什么情况都会执行,所以文件会被关闭,不会因为执行异常而占用资源。
with open('./test_runoob.txt', 'w') as file:
file.write('hello world !')
使用 with 关键字系统会自动调用 f.close() 方法, with 的作用等效于 try/finally 语句是一样的。
4.组合数据类型
4.1 可变与不可变类型
一些组合的数据类型只能存储可变数据,一些只能存储不可变数据。
不不可变类型 | 可变类型 |
---|---|
Number | List |
String | Dict |
Tuple | Set |
4.2 序列切片操作
可以对序列进行切片操作,不同于matlab的是,其最后一个参数表示步长。
序列[start:end:step]#参数可以省略,如果step为负值的话,则倒序计数
4.3 序列和索引操作
操作符/函数 | 描述说明 |
---|---|
x+y | 两个序列拼接 |
x in s | 如果x是s的元素,结果为True,否则结果为False |
x not in s | 如果x不是s的元素,结果为True,否则结果为False |
len(s) | 序列s中元素的个数(即序列的长度) |
max(s) | 序列s中元素的最大值 |
min(s) | 序列s中元素的最小值 |
s.index(x) | 序列s中第一次出现元素x的位置 |
s.count(x) | 序列s中出现x的总次数 |
4.4 list
Python中内置的可变序列,在Python中使用[]定义列表,元素与元素之间使用英文的逗号分隔,列表中的元素可以是任意的数据类型。
- 列表的创建
- 使用[]直接创建列表
列表名=[element1,element2,......elementN]
# 直接使用[]创建列表
lst=['hello','world',98,100.5]
print(lst)
- 使用内置函数list()创建列表
列表名=list(序列)
# 可以使用内置的函数list()创建列表
lst2=list('helloworld')
lst3=list(range(1,10,2)) # 从1开始到10结束,步长为2,不包含10
- 列表的遍历
列表的遍历有如下三种方法
# 使用遍历循环for遍历列表元素
for item in lst:
print(item)
# 使用for循环,range()函数,len()函数,根据索引进行遍历
for i in range(0,len(lst)):
print(i,'-->',lst[i])
# 第三种遍历方式 enumearte()函数
for index,item in enumerate(lst):
print(index,item) #index是序号,不是索引
# 手动修改序号的起始值
for index,item in enumerate(lst,start=1): #
print(index,item)
for index, item in enumerate(lst,1): # 省略start不写,直接写起始值
print(index, item)
- 列表相关操作
列表的方法 | 描述说明 |
---|---|
del lst | 删除列表 |
lst.append(x) | 在列表lst最后增加一个元素 |
lst.insert(index,x) | 在列表中第index位置增加一个元素 |
lst.clear() | 清除列表lst中所有元素 |
lst.pop(index) | 将列表lst中第index位置的元素取出,并从列表中将其删除 |
lst.remove(x) | 将列表lst中出现的第一个元素x删除 |
lst.reverse(x) | 将列表lst中的元素反转 |
lst.copy() | 拷贝列表lst中的所有元素,生成一个新的列表 |
- 列表排序
- 列表对象的sort方法
该方法并不会生成新的列表对象
lst.sort(key=None,reverse=False)
# key表示排序规则
# reverse表示排序方式
- 内置函数sorted()
该方法会生成一个新的列表对象
sorted(iterable,key=None,reverse=False)
# iterable表示排序对象
- 列表生成式
列表生成式是一种基于其他iterable(如集合、元组、其他列表等)创建列表的方法。它还可以用更简单、更吸引人的语法表示for和if循环。不过,列表生成式比for循环要快得多。
其语法为:
lst=[expression for item in range if condition]
实例:
lst=[item for item in range(1,11)]
print(lst)
lst=[item*item for item in range(1,11)]
print(lst)
lst=[random.randint(1,100) for _ in range(10)]
print(lst)
# 从列表中选择符合条件的元素组成新的列表
lst=[i for i in range(10) if i%2==0]
print(lst)
输出结果为
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[82, 24, 7, 20, 45, 2, 44, 44, 76, 56]
[0, 2, 4, 6, 8]
4.5 enumerate()
函数用于将一个可遍历的数据对象(如列表、元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中。语法如下
enumerate(sequence, [start=0])
# sequence -- 一个序列、迭代器或其他支持迭代对象。
# start -- 下标起始位置的值。
# 返回 enumerate(枚举) 对象。
4.6 元组
元组是Python中内置的不可变序列,在Python中使用()定义元组,元素与元素之间使用英文的逗号分隔元组中只有一个元素的时候,逗号也不能省略。
- 元组的创建与删除
- 使用()直接创建元组
语法如下:
元组名=(element1,element2,......elementN)
# 使用小括号创建元组
t=('hello',[10,20,30],'python','world')
print(t)
输出结果为
('hello', [10, 20, 30], 'python', 'world')
- 使用内置函数tuple()创建元组
元组名=tuple(序列)
# 使用内置函数tuple()创建元组
t=tuple('helloworld')
print(t)
t=tuple([10,20,30,40])
print(t)
- 元组的删除
元组的删除可以使用关键字del
del 元组名
-
元组的遍历与访问
元组的遍历方式和访问的方式与列表相同,这里不在叙述。 -
元组生成式
- 元组生成式的结果是一个生成器对象,需要转换成元组或列表才能查看到元素内容
t=(i for i in range(1,4))
print(t)
t=tuple(t)
print(t)
输出结果如下
<generator object <genexpr> at 0x00000287BF9A9820>
(1, 2, 3)
可以看到第一个是生成器对象的地址,无法打印出我们所需要的1,2,3。而在用tuple()函数处理过后,我们可以输出元组,此时为元组类型。
如果不将其转化为元组或者列表,我们可以用__next__()方法将其中的元素取出来。
print(t.__next__())
print(t.__next__())
print(t.__next__())
输出结果为
1
2
3
但是就如同上面一样,所有的元素被遍历过一遍后,都已经被取出,这个生成器对象中已经不含元素。所以,我们再用tuple()函数将其转化为元组,得到的是一个空的元组。
- 元组和列表的对比
元组 | 列表 |
---|---|
不可变序列 | 可变序列 |
无法实现添加、删除和修改元素等操作 | append()、insert()、remove()、pop()等方法实现添加和删除列表元素 |
支持切片访问元素,不支持修改操作 | 支持切片访问和修改列表中的元素 |
访问和处理速度快 | 访问和处理速度慢 |
可以作为字典的键 | 不能作为字典的键 |
4.7 字典dictionary
字典是一种可变的数据类型,根据一个信息查找另一个信息的方式构成了“键值对”,它表示索引用的键和对应的值构成的成对关系。这一点有点类似于map。
字典的一个特点是键key是不可以重复的,而值value是可以重复的,学过数据库的人应该不难理解,key就像是主键一样。key是唯一标识,不能有重复的,且不允许为空。
特别注意的是,字典中的键是不可变序列,故而列表是不可以作为字典中的键,而元组、字符串等都可以。
- 字典的创建与删除
字典的创建有两种方法
- 用{}创建
语法如下
d={key1:value1,key2:value2......}
d={10:'cat',20:'dog',30:'pet',20:'zoo'}# 当key一样的时候,value会自动覆盖
- 使用内置函数dict()创建字典
dict()的语法为
dict(key1=value1,key2=value2......)
# 使用参数创建字典
d=dict(cat=10,dog=20) # 左侧cat是key ,右侧的是value
print(d)
- 映射函数zip(lst1,lst2)
zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
>>> a = [1,2,3]
>>> b = [4,5,6]
>>> c = [4,5,6,7,8]
>>> zipped = zip(a,b) # 返回一个对象
>>> zipped
<zip object at 0x103abc288>
>>> list(zipped) # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
>>> list(zip(a,c)) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
>>> a1, a2 = zip(*zip(a,b)) # 与 zip 相反,zip(*) 可理解为解压,返回二维矩阵式
>>> list(a1)
[1, 2, 3]
>>> list(a2)
[4, 5, 6]
>>>
- 字典也是序列,支持序列的操作
# 字典属于序列
print('max:',max(d))# 输出的结果是最大的键对应的值
print('min:',min(d))
print('len:',len(d))
# 字典的删除
del d
#print(d)
- 字典的访问与遍历
- 字典的访问
d[key]或d.get(key)
两者不同的是d[key]在键不存在时,会报错。而d.get(key)在键不存在的时候,返回值为None或者返回默认值(如果给了的话)。
print(d.get('java')) # None
print(d.get('java','不存在'))
其输出结果为
None
不存在
- 字典的遍历
1) 遍历出key与value的元组
# 字典的遍历
for item in d.items():
print(item) # key=value组成的一个元素
输出结果为:
('hello', 10)
('world', 20)
('python', 30)
2) 遍历出key和value
# 在使用for循环遍历时,分别获取key,value
for key,value in d.items():
print(key,'--->',value)
输出结果为:
hello ---> 10
world ---> 20
python ---> 30
- 字典的操作方法
字典的方法 | 描述说明 |
---|---|
d.keys() | 获取所有的key数据 |
d.values() | 获取所有的value数据 |
d.pop(key,default) | key存在获取相应的value,同时删除key-value对,否则获取默认值 |
d.popitem() | 随机从字典中取出一个key-value对,结果为元组类型,同时将该key-value从字典中删除 |
d.clear() | 清空字典中所有的key-value对 |
- 字典生成式
字典生成式的语法为
d={ key:value for item in range }
或
d={key:value for key,value in zip(lst1,lst2)}
示例
import random
d={item :random.randint(1,100) for item in range(4)}
print(d)
# 创建两个列表
lst=[1001,1002,1003]
lst2=['a','b','c']
d={key:value for key,value in zip(lst,lst2)}
print(d)
其输出结果为:
{0: 97, 1: 25, 2: 47, 3: 24}
{1001: 'a', 1002: 'b', 1003: 'c'}
4.8 集合(set)
Python中的集合与数学中集合的概念一致,它是一个无序的不重复元素序列,集合中只能存储不可变数据类型。在Python中集合使用{}定义,与列表、字典一样,都是Python中的可变数据类型,即其中内容是可以改变的。
特点:集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。
- 集合的创建与删除
集合的创建有两种方法
- 用{}创建
语法如下
s={element1,element2,......elementN}
s={10,20,30,40}
print(s)
# 集合中只能存储不可变数据类型
#s={[10,20],[30,40]} #TypeError: unhashable type: 'list'
注意s={},创建结果为字典类型。
- 使用内置函数set()创建集合
set()的语法为
s=set(可迭代对象)
s=set('helloworld')
print(s)
#删除使用del
- 集合也是序列,支持序列的操作,但是集合是无序的,不可以遍历。
- 集合的遍历和集合生成式
# 集合的遍历操作
for item in s:
print(item)
# 使用enumerate()函数
for index,item in enumerate(s):
print(index,'-->',item)
# 集合的生成式
s={i for i in range(1,10)}
print(s)
s={i for i in range(1,10) if i%2==1}
print(s)
- 集合的操作方法
集合的方法 | 描述说明 |
---|---|
A&B | 交集 |
A|B | 并集 |
A-B | 差集 |
A^B | 补集 |
s.add(x) | 如果x不在集合s中,则将x添加到集合s |
s.remove(x) | 如果x在集合中,将其删除,如果不在集合中,程序报错 |
s.clear() | 清除集合中所有元素 |
这里仅仅介绍了部分常用操作,更多细节可以查看菜鸟教程里面关于集合的描述。
4.9 组合数据类型对比总结
数据类型 | 序列类型 | 元素是否可重复 | 是否有序 |
---|---|---|---|
列表list | 可变序列 | 可重复 | 有序 |
元组tuple | 不可变序列 | 可重复 | 有序 |
字典dict | 可变序列 | Key不可重复,Value可重复 | 无序 |
集合set | 可变序列 | 不可重复 | 无序 |
5.字符串
5.1 字符串的操作方法
方法名 | 描述说明 |
---|---|
str.lower() | 将str字符串全部转成小写字母,结果为一个新的字符串 |
str.upper() | 将str字符串全部转成大写字母,结果为一个新的字符串 |
str.split(sep=None) | 把str按照指定的分隔符sep进行分隔,结果为列表类型 |
str.count(sub) | 结果为sub这个字符串在str中出现的次数 |
str.find(sub) | 查询sub这个字符串在str中是否存在,如果不存在结果为-1,如果存在,结果为sub首次出现的索引 |
str.index(sub) | 功能与find()相同,区别在于要查询的子串sub不存在时,程序报错 |
str.startswith(s) | 查询字符串str是否以子串s开头 |
str.endswith(s) | 查询字符串str是否以子串s结尾 |
str.replace(old,news) | 使用news替换字符串s中所有的old字符串,结果是一个新的字符串 |
str.center(width,fillchar) | 字符串str在指定的宽度范围内居中,可以使用fillchar进行填充 |
str.join(iter) | 在iter中的每个元素的后面都增加一个新的字符串str |
str.strip(chars) | 从字符串中去掉左侧和右侧chars中列出的字符串 |
str.lstrip(chars) | 从字符串中去掉左侧chars中列出的字符串 |
str.rstrip(chars) | 从字符串中去掉右侧chars中列出的字符串 |
5.2 字符串的格式化方法
字符串的格式化有三种方法
- 占位符
用占位符去格式化字符串,其中%s表示字符串格式,%d 表示十进制整数格式,%f 表示浮点数格式 - f-string
这是一种引入的格式化字符串的方式,用{}标明被替换的字符 - str.format()方法
format 函数可以接受不限个参数,位置可以不按顺序。
三种方法的具体实例为
#(1)使用占位符进行格式化
name='马冬梅'
age=18
score=98.5
print('姓名:%s,年龄:%d,成绩:%f' % (name,age ,score))
print('姓名:%s,年龄:%d,成绩:%.1f' % (name,age ,score))
# (2)f-string
print(f'姓名:{name},年龄:{age},成绩:{score}')
# (3)使用字符串的format方法
print('姓名:{0},年龄:{1},成绩:{2}'.format(name,age,score))
print('姓名:{2},年龄:{0},成绩:{1}'.format(age,score,name))
"{} {}".format("hello", "world") # 不设置指定位置,按默认顺序
"{0} {1}".format("hello", "world") # 设置指定位置
"{1} {0} {1}".format("hello", "world") # 设置指定位置
5.3 详细的format格式化方法
- 示例
s='helloworld'
print('{0:*<20}'.format(s)) # 字符串的显示宽度为20,左对齐,空白部分使用* 号填充
print('{0:*>20}'.format(s))
print('{0:*^20}'.format(s))
# 居中对齐
print(s.center(20,'*'))
# 千位分隔符(只适用于整数和浮点数)
print('{0:,}'.format(987654321))
print('{0:,}'.format(987654321.7865))
# 浮点数小数部分的精度
print('{0:.2f}'.format(3.1419826))
# 字符串类型 .表示是最大的显示长度
print('{0:.5}'.format('helloworld')) # hello
# 整数类型
a=425
print('二进制:{0:b},十进制:{0:d},八进制:{0:o},十六进制:{0:x},十六进制:{0:X}'.format(a))
# 浮点数类型
b=3.1415926
print('{0:.2f},{0:.2E},{0:.2e},{0:.2%}'.format(b) )
5.4 字符串分割
split() 方法语法:
str.split(str="", num=string.count(str)).
# str -- 分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。
# num -- 分割次数。默认为 -1, 即分隔所有。
6.函数
6.1 定义方法
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
# 定义格式
def 函数名称(参数列表):
函数体
[return返回值列表]
# 举例如下
def get_sum(num): #num叫形式参数
s=0
for i in range(1,num+1):
s+=i
print(f'1到{num}之间的累加和为:{s}')
# 函数的调用
get_sum(10) # 1-10之间的累加和 10是实际参数值
get_sum(100) # 1-100之间的累加和 100是实际参数值
get_sum(1000) # 1-1000之间的累加和 1000是实际参数值
6.2 参数传递
-
对于不可变类型如数字、元组等,函数并不改变数据。
-
对于可变类型如列表、字典,函数中若修改了该参数,原数据也会发生变化,有点类似于是C++中的传引用。
python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。
6.2.1 四种传参方式
- 位置参数
位置参数必须以正确的顺序传入函数。调用时的数量必须和声明时的一样,这是一种最常见的参数传递方式。
def happy_birthday(name,age):
print('祝'+name+'生日快乐')
print(str(age)+'岁生日快乐')
happy_birthday('小明',18)# 参数位置不能反,也不能缺失
- 关键字参数
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。
使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
但是要注意的是,若同时有位置参数和关键字参数的话,必须关键字参数在后,位置参数在前传递,否则会报错。
#可写函数说明
def printinfo( name, age ):
"打印任何传入的字符串"
print "Name: ", name
print "Age ", age
return
#调用printinfo函数
printinfo( age=50, name="miki" )
- 默认值参数
默认参数的值如果没有传入,则被认为是默认值,类似于是缺省值的意思。
def printinfo( name, age = 35 ):
"打印任何传入的字符串"
print "Name: ", name
print "Age ", age
return
#调用printinfo函数
printinfo( age=50, name="miki" )
printinfo( name="miki" )
- 可变参数
分为个数可变的位置参数和个数可变的关键字参数两种,其中个数可变的位置参数是在参数前加一颗星(*para),para形式参数的名称,函数调用时可接收任意个数的实际参数,并放到一个元组中。**个数可变的关键字参数是在参数前加两颗星(para),在函数调用时可接收任意多个 “参数=值”形式的参数,并放到一个字典中。
# 个数可变的位置参数
def fun(*para):
print(type(para))
for item in para:
print(item)
# 调用
fun(10,20,30,40)
fun(10)
fun(20,30)
fun([11,22,33,44]) # 实际上传递的是一个参数,
# 在调用时,参数前加一颗星,分将列表进行解包
fun(*[11,22,33,44])
# 个数可变的关键字参数
def fun2(**kwpara):
print(type(kwpara))
for key,value in kwpara.items():
print(key,'-----',value)
# 调用
fun2(name='小明',age=18,height=170) # 关键字参数
d={'name':'小明','age':18,'height':170}
#fun2(d) # TypeError: fun2() takes 0 positional arguments but 1 was given
fun2(**d) #系列解包操作
6.3 返回值
return可以出现在函数中的任意一个位置,用于结束函数。返回值可以是一个值,或多个值,如果返回的值是多个,结果是一个元组类型。
6.4 变量作用域
在函数内部用global可以声明全局变量。
6.5 lambda表达式
这种函数只能使用一次,一般是在函数的函数体只有一句代码且只有一个返回值时,可以使用匿名函数来简化。
# 语法格式
result=lambda 参数列表:表达式
def calc(a,b):
return a+b
print(calc(10,20))
# 匿名函数
s=lambda a,b:a+b # s表示就是一个匿名函数
print(type(s)) # <class 'function'>
# 调用匿名函数
print(s(10,20))
print('-'*30)
# 列表的正常取值操作
lst=[10,20,30,40,50]
for i in range(len(lst)):
print(lst[i])
print('-'*30)
for i in range(len(lst)):
result=lambda x:x[i] # 根据索引取值 ,result是的类型是function ,x是形式参数
print(result(lst)) # lst是实际参数
#
student_scores=[
{'name':'陈梅梅','score':98},
{'name': '王一一', 'score': 95},
{'name': '张天乐', 'score': 100},
{'name': '白雪儿', 'score': 65}
]
# 对列表进行排序, 排序的规则 是字典只的成绩
student_scores.sort(key=lambda x:x.get('score'),reverse=True) # 降序
print(student_scores)
6.6 常用函数
6.6.1 类型转换函数
函数名称 | 描述说明 |
---|---|
bool(obj) | 获取指定对象obj的布尔值 |
str(obj) | 将指定对象obj转成字符串类型 |
int(x) | 将x转成int类型 |
float(x) | 将x转成float类型 |
list(sequence) | 将序列转成列表类型 |
tuple(sequence) | 将序列转成元组类型 |
set(sequence) | 将序列转成集合类型 |
6.6.2 数学计算函数
函数名称 | 描述说明 |
---|---|
abs(x) | 获取x的绝对值 |
divmod(x,y) | 获取x与y的商和余数 |
max(sequence) | 获取sequence的最大值 |
min(sequence) | 获取sequence的最小值 |
sum(iter) | 对可迭代对象进行求和运算 |
pow(x,y) | 获取x的y次幂 |
round(x,d) | 对x进行保留d位小数,结果四舍五入 |
6.6.3可迭代对象操作函数
函数名称 | 描述说明 |
---|---|
sorted(iter) | 对可迭代对象进行排序 |
reversed(sequence) | 反转序列生成新的迭代器对象 |
zip(iter1,iter2) | 将iter1与iter2打包成元组并返回一个可迭代的zip对象 |
enumerate(iter) | 根据iter对象创建一个enumerate对象 |
all(iter) | 判断可迭代对象iter中所有元素的布尔值是否都为True |
any(iter) | 判断可迭代对象iter中所有元素的布尔值是否都为False |
next(iter) | 获取迭代器的下一个元素 |
filter(function,iter) | 通过指定条件过滤序列并返回一个迭代器对象 |
map(function,iter) | 通过函数function对可迭代对象iter的操作返回一个迭代器对象 |
7.面向对象的编程
7.1 类(class)和实例(instance)
在python中一切皆对象。类就是一个模板,对象则是这个模板具体的实例。
一个类主要有如下几个部分构成
- 类属性:直接定义在类中,方法之外的变量。
- 实例属性:定义在_init_() 方法中,使用self打点的变量。这也说明了self是实例。
- 实例方法:定义在类中的函数,自带参数self。
- 静态方法:使用装饰器@staticmethod修饰的方法。
- 类方法:使用装饰器@classmethon修饰的方法。
简而言之,self对应的是实例方法和实例属性。
7.2 类的创建及调用
class Student:
# 类属性:定义在类中,方法外的变量
school = "xx大学"
# 初始化方法
def __init__(self,xm,age): # name和age是该方法的变量,为局部变量,其作用域为该方法
self.name=xm # =左侧为实例属性,其定义在实例方法中。
self.age=age # 允许实例属性和参数同名
# 定义在类中的函数称为方法,自带参数self
def show(self):
print(f'我叫:{self.name},今年:{self.age}岁了')
# 静态方法
@staticmethod
def good():
print('这是一个静态方法') # 不能调用实例属性和实例方法
# 类方法
@classmethod
def bad(cls): # 自带参数cls,它是class的简写
print('这是一个类方法') # 不能调用实例属性和实例方法
# 创建类的对象
stu=Student('zhangyang',18) # 不传入self
# 实例属性调用,使用对象名打点调用
print(stu.name,stu.age)
# 类属性调用,类名打点调用
print(Student.school)
# 实例方法,使用对象名打点调用
stu.show()
# 类方法调用
Student.bad()
# 静态方法调用
Student.good()
- 其中还可以定义私有属性,用两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs。
类属性和实例属性
7.2.1 动态绑定属性和方法
python中可以动态的给对象绑定属性和方法,举例如下。
class Student:
# 类属性:定义在类中,方法外的变量
school = "xx大学"
# 初始化方法
def __init__(self,xm,age): # name和age是该方法的变量,为局部变量,其作用域为该方法
self.name=xm # =左侧为实例属性,其定义在实例方法中。
self.age=age # 允许实例属性和参数同名
# 定义在类中的函数称为方法,自带参数self
def show(self):
print(f'我叫:{self.name},今年:{self.age}岁了')
stu1 = Student('Alice', 17)
# 动态绑定一个属性
stu1.gender = '女'
print(stu1.gender)
# 绑定一个方法
def introduce():
print('普通该函数被动态绑定成了stu1对象的方法')
stu1.fun = introduce # 将该函数赋值过去,即绑定完毕方法,但是不要有括号
#调用
stu1.fun()
7.2.2 权限控制
- 单下划线开头:表示被保护的成员protected,可以允许类本身和子类访问。
- 双下划线开头:表示private私有成员,仅允许定义该属性或者方法的类进行访问
- 首位双下划线:表示特殊方法
访问方式
stu._name # 访问受保护的属性
stu._fun1() # 子类和本身可以直接访问
stu._Student__Age #访问私有的属性
stu._Studnet__fun2() # 访问私有的方法
7.2.3 属性设置
上面的对于私有方法和属性的调用是极其不推荐的,可以用property函数或者函数装饰器@property来设置访问。
7.2.3.1 property() 函数
-
语法:
property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
-
说明:
fget
是获取属性值的方法。
fset
是设置属性值的方法。
fdel
是删除属性值的方法。
doc
是属性描述信息。如果省略,会把fget
方法的docstring
拿来用(如果有的话) -
示例代码:
class Student:
def __init__(self):
self._age = None
def get_age(self):
print('获取属性时执行的代码')
return self._age
def set_age(self, age):
print('设置属性时执行的代码')
self._age = age
def del_age(self):
print('删除属性时执行的代码')
del self._age
age = property(get_age, set_age, del_age, '学生年龄')
student = Student()
# 注意要用 类名.属性.__doc__ 的形式查看属性的文档字符串
print('查看属性的文档字符串:' + Student.age.__doc__)
"""
查看属性的文档字符串:学生年龄
"""
# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""
# 获取属性
print('学生年龄为:' + str(student.age))
"""
获取属性时执行的代码
学生年龄为:18
"""
# 删除属性
del student.age
"""
删除属性时执行的代码
"""
7.2.3.2 @property 装饰器
@property
语法糖提供了比 property()
函数更简洁直观的写法。
- 被
@property
装饰的方法是获取属性值的方法,被装饰方法的名字会被用做 属性名。 - 被
@属性名.setter
装饰的方法是设置属性值的方法。 - 被
@属性名.deleter
装饰的方法是删除属性值的方法。
以下示例代码与使用 property()
函数版本的代码等价:
class Student:
def __init__(self):
self._age = None
@property
def age(self):
print('获取属性时执行的代码')
return self._age
@age.setter
def age(self, age):
print('设置属性时执行的代码')
self._age = age
@age.deleter
def age(self):
print('删除属性时执行的代码')
del self._age
student = Student()
# 设置属性
student.age = 18
"""
设置属性时执行的代码
"""
# 获取属性
print('学生年龄为:' + str(student.age))
"""
获取属性时执行的代码
学生年龄为:18
"""
# 删除属性
del student.age
"""
删除属性时执行的代码
"""
这段内容转载自博客Python 中 property() 函数及 @property 装饰器的使用
所以说,利用上述方法可以用于读取、修改和删除私有属性。
7.3 继承
在python中一个子类可以继承N多个父类,且一个父类也可以拥有多个子类。如果说一个类没有继承任何类,这个类默认继承了object
类
- 语法结构
class 类名(父类1,父类2,......,父类N)
- 示例代码
#类定义
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('ken',10,60,3)
s.speak()
7.3.1 多继承
python允许一个子类同时继承多个父类。
- 语法结构
class DerivedClassName(Base1, Base2, Base3):
pass
需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
- 示例代码
#类定义
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))
#另一个类,多继承之前的准备
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("Tim",25,80,4,"Python")
test.speak() #方法名同,默认调用的是在括号中参数位置排前父类的方法
7.3.2 方法重写
子类继承了父类就拥有了父类中公有成员和受保护的成员。但是父类的方法如果不能够完全适合子类的需要的时候,子类就可以重写父类的方法。
子类重写父类的方法时候,要求方法名称相同,在子类重写后仍然可以通过super().xxx()调用父类的方法。
class Parent: # 定义父类
def myMethod(self):
print ('调用父类方法')
class Child(Parent): # 定义子类
def myMethod(self):
print ('调用子类方法')
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法
7.3.3 多态
python根据变量所引用对象的数据类型,动态的决定调用哪个对象中的方法。在python中,并不关心对象的数据类型和继承关系,只关心对象的方法。只要不同类中有同名方法,就可以实现多态。
"""
面向对象 - 多态
"""
class Animal:
name = "Animal"
age = 0
def make_sound(self):
print("动物发音")
class Dog(Animal):
def make_sound(self):
print("汪汪")
class Cat(Animal):
def make_sound(self):
print("喵喵")
def fun(obj):
obj.make_sound()
animal = Animal()
dog = Dog()
cat = Cat()
fun(animal)
fun(dog)
fun(cat)
7.4 object类
object是所有类的父类。
object类中的特殊方法 | 描述说明 |
---|---|
_new()_ | 由系统调用,用于创建对象 |
_init()_ | 创建对象的时候手动调用,用于初始化 |
_str()_ | 对象的描述,返回值为str,默认输出对象的内存地址,print(对象)自动调用 |
dir()函数可以用于查看该对象属性和方法。
7.5 类的浅拷贝和深拷贝
- 变量的赋值:只是形成两个变量,实际上还是指向同一个对象
class CPU:
pass
class Disk:
pass
class Computer:
def __init__(self,cpu,disk):
self.cpu = cpu
self.disk = disk
# 声明一个cpu1变量并将CPU实例对象赋予它
cpu1 = CPU()
print(cpu1,id(cpu1))
# 将cpu1赋予cpu2
cpu2 = cpu1
print(cpu2,id(cpu2))
<__main__.CPU object at 0x00000182116B6820> 1658149627936
<__main__.CPU object at 0x00000182116B6820> 1658149627936
赋值对应的内存地址是相同的
- 浅拷贝:拷贝时,对象包含的子对象内容不拷贝,因此源对象和拷贝对象引用的是同一个对象
import copy
disk = Disk()
comp1 = Computer(cpu1, disk)
print(comp1,id(comp1),id(comp1.cpu),id(comp1.disk))
comp2 = copy.copy(comp1)
print(comp2,id(comp2),id(comp2.cpu),id(comp2.disk))
<__main__.Computer object at 0x000001FAFD3986A0> 2177501857440 2177503160352 2175472490912
<__main__.Computer object at 0x000001FAFD4AC460> 2177502987360 2177503160352 2175472490912
变量comp1和comp2分别指向两个不同的对象实例,是对原有的对象实例的一个拷贝,而在对象中的子对象cpu和disk指向同一个对象实例,因此为浅拷贝。
- 深拷贝:使用copy模块的deepcopy函数。递归拷贝对象中包含的子对象,源对象和拷贝对象所有的子对象也不相同
import copy
disk = Disk()
comp1 = Computer(cpu1, disk)
print(comp1,id(comp1),id(comp1.cpu),id(comp1.disk))
comp3 = copy.deepcopy(comp1)
print(comp3,id(comp3),id(comp3.cpu),id(comp3.disk))
```bash
<__main__.Computer object at 0x000001FC093586A0> 2181997889184 2181999192096 2182115809696
<__main__.Computer object at 0x000001FC0946C490> 2181999019152 2182117519712 2182117519904
id均不相同,即为深拷贝,深拷贝改变对象的值会影响源的值,而浅拷贝不会。
参考资料:
[1] python子木https://www.bilibili.com/video/BV1wD4y1o7ASp=8&vd_source=3c45104f01803b9a022fe28bbd87a603
[2] 菜鸟教程https://www.runoob.com/python/python-tutorial.html