一 基础入门 1.1 变量和标识符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 a = 10 a = 'hello' _b123 = 20
1.2 数值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 a = 10 b = 20 c = 123 _456_789 c = 0b10 c = 0o10 c = 0x10 c = -100 c = c + 3 c = 1.23 c = 4.56 c = 0.1 + 0.2 print(c)
1.3 字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 s = 'hello' s = 'hello' s = "hello" s = '子曰:"学而时习之,乐呵乐呵!"'
长字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 s = '锄禾日当午,\ 汗滴禾下土,\ 谁知盘中餐,\ 粒粒皆辛苦' s = '''锄禾日当午, 汗滴禾下土, 谁知盘中餐, 粒粒皆辛苦'''
转义字符
1 2 3 4 5 6 7 8 9 10 11 12 13 s = "子曰:\"学而时习之,\\\\n乐呵乐呵!\"" s = '\u2250' print(s)
1.3.1 格式化字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 a = 'hello' a = 'abc' + 'haha' + '哈哈' a = 123 b = 'Hello %s' %'孙悟空' b = 'hello %s 你好 %s' %('tom' ,'孙悟空' ) b = 'hello %3.5s' %'abcdefg' b = 'hello %s' %123.456 b = 'hello %.2f' %123.456 b = 'hello %d' %123.95 b = '呵呵' c = f'hello {a} {b} ' print(f'a = {a} ' )
1.3.2 复制字符串 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 name = '孙悟空' print('欢迎 ' +name+' 光临!' ) print('欢迎' ,name,'光临!' ) print('欢迎 %s 光临!' %name) print(f'欢迎 {name} 光临!' ) a = 'abc' a = a * 20 print(a)
1.4 布尔值与空值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 a = True a = False b = None print(b)
1.5 类型检查 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 a = 123 b = '123' c = type('123' ) c = type(a) print(type(1 )) print(type(1.5 )) print(type(True )) print(type('hello' )) print(type(None ))
1.6 类型转换 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 a = True a = int(a) a = False a = int(a) a = '123' a = int(a) a = 11.6 a = int(a) a = '11.5' a = None a = 1 a = float(a) a = False a = float(a) a = 123 a = str(a) a = None a = bool(a) print('a =' ,a) print('a的类型是' ,type(a))
1.7 运算符 1.7.1 条件运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 a = 30 b = 50 max = a if a > b else b print(max)
1.7.2 运算符的优先级 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 a = 40 b = 50 c = 30 max = a if (a > b and a > c) else (b if b > c else c) a = 1 + 2 * 3 a = 1 or 2 and 3 result = 1 < 2 < 3 result = 10 < 20 > 15 print(result)
二 流程控制 2.1 条件判断 缩进有两种方式,一种是使用tab键,一种是使用空格(四个) Python的官方文档中推荐我们使用空格来缩进 Python代码中使用的缩进方式必须统一
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 num = 10 if False : print(123 ) print(456 ) print(789 ) print(101112 ) num = 28 if num > 10 and num < 20 : print('num比10大,num比20小!' ) if 10 < num < 20 : print('num比10大,num比20小!' )
2.1.1 if-else判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 age = 7 if age > 17 : print('你已经成年了~~' ) else : print('你还未成年~~' )
2.1.2 if-elif-else判断 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 age = 210 age = 68 if age >= 18 and age < 30 : print('你已经成年了!' ) elif age >= 30 and age < 60 : print('你已经中年了!' ) elif age >= 60 : print('你已经退休了!' )
2.2 循环语句 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 i = 0 while i < 10 : i += 1 print(i,'hello' ) else : print('else中的代码块' )
三 序列 3.1 列表 类似于java中的list创建列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 my_list = [] my_list = [10 ] my_list = [10 ,20 ,30 ,40 ,50 ] my_list = [10 ,'hello' ,True ,None ,[1 ,2 ,3 ],print ] my_list = [10 ,20 ,30 ,40 ,50 ]
通过索引获取列表中的元素
获取列表的长度
3.1.1 切片 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ,'蜘蛛精' ,'白骨精' ] print(stus[::-1 ])
3.1.2 通用操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 my_list = [1 ,2 ,3 ] + [4 ,5 ,6 ] my_list = [1 ,2 ,3 ] * 5 stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ,'蜘蛛精' ,'白骨精' ,'沙和尚' ,'沙和尚' ] arr = [10 ,1 ,2 ,5 ,100 ,77 ] print(stus.count('牛魔王' ))
3.1.3 修改元素 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ,'蜘蛛精' ,'白骨精' ] stus[0 ] = 'sunwukong' stus[2 ] = '哈哈' del stus[2 ] stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ,'蜘蛛精' ,'白骨精' ] s = 'hello' s = list(s) print(s)
3.1.4 列表的方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ] my_list = list('asnbdnbasdabd' ) my_list = [10 ,1 ,20 ,3 ,4 ,5 ,0 ,-2 ] print('修改前' ,my_list) my_list.sort(reverse=True ) print('修改后' ,my_list)
3.1.5 遍历列表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 stus = ['孙悟空' ,'猪八戒' ,'沙和尚' ,'唐僧' ,'白骨精' ,'蜘蛛精' ] for s in stus : print(s)
3.2 range函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 r = range(5 ) r = range(0 ,10 ,2 ) r = range(10 ,0 ,-1 ) for i in range(30 ): print(i)
3.3 元组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 my_tuple = () my_tuple = (1 ,2 ,3 ,4 ,5 ) my_tuple = 10 ,20 ,30 ,40 my_tuple = 40 , my_tuple = 10 , 20 , 30 , 40 a,b,c,d = my_tuple a = 100 b = 300 a , b = b , a my_tuple = 10 , 20 , 30 , 40 a , b , *c = my_tuple a , *b , c = my_tuple *a , b , c = my_tuple a , b , *c = [1 ,2 ,3 ,4 ,5 ,6 ,7 ] a , b , *c = 'hello world' print('a =' ,a) print('b =' ,b) print('c =' ,c)
3.4 可变对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 a = [1 ,2 ,3 ] b = a b = [10 ,2 ,3 ] a = [1 ,2 ,3 ] b = [1 ,2 ,3 ] print(a,b) print(id(a),id(b)) print(a == b) print(a is b)
3.5 字典 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 d = {} d = { 'name' :'孙悟空' , 'age' :18 , 'gender' :'男' , 'name' :'sunwukong' }
3.5.1 字典的使用 创建字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 d = dict(name='孙悟空' ,age=18 ,gender='男' ) d = dict([('name' ,'孙悟饭' ),('age' ,18 )]) d = dict(name='孙悟空' ,age=18 ,gender='男' )
获取字典中键值对的个数 检查字典中是否包含指定的键 获取字典中的值 修改字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 d['name' ] = 'sunwukong' d['address' ] = '花果山' result = d.setdefault('name' ,'猪八戒' ) result = d.setdefault('hello' ,'猪八戒' ) d = {'a' :1 ,'b' :2 ,'c' :3 } d2 = {'d' :4 ,'e' :5 ,'f' :6 , 'a' :7 } d.update(d2)
删除
随机删除字典中的一个键值对
根据key删除字典中的key-value会将被删除的value返回
1 2 3 4 5 6 7 8 9 10 11 result = d.pop('d' ) result = d.pop('z' ,'这是默认值' )
清空字典
对字典进行浅复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 d = {'a' :1 ,'b' :2 ,'c' :3 } d2 = d.copy() d = {'a' :{'name' :'孙悟空' ,'age' :18 },'b' :2 ,'c' :3 } d2 = d.copy() d2['a' ]['name' ] = '猪八戒' print('d = ' ,d , id(d)) print('d2 = ' ,d2 , id(d2))
3.5.2 遍历字典 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 d = {'name' :'孙悟空' ,'age' :18 ,'gender' :'男' } for k,v in d.items() : print(k , '=' , v)
3.6 集合 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 s = {10 ,3 ,5 ,1 ,2 ,1 ,2 ,3 ,1 ,1 ,1 ,1 } s = set() s = set([1 ,2 ,3 ,4 ,5 ,1 ,1 ,2 ,3 ,4 ,5 ]) s = set('hello' ) s = set({'a' :1 ,'b' :2 ,'c' :3 }) s = {'a' , 'b' , 1 , 2 , 3 , 1 } s.add(10 ) s.add(30 ) s2 = set('hello' ) s.update(s2) s.update((10 ,20 ,30 ,40 ,50 )) s.update({10 :'ab' ,20 :'bc' ,100 :'cd' ,1000 :'ef' }) s.remove(100 ) s.remove(1000 ) s.clear() print(s , type(s))
3.6.1 集合的运算 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 s = {1 ,2 ,3 ,4 ,5 } s2 = {3 ,4 ,5 ,6 ,7 } result = s & s2 result = s | s2 result = s - s2 result = s ^ s2 a = {1 ,2 ,3 } b = {1 ,2 ,3 ,4 ,5 } result = a <= b result = {1 ,2 ,3 } <= {1 ,2 ,3 } result = {1 ,2 ,3 ,4 ,5 } <= {1 ,2 ,3 } result = {1 ,2 ,3 } < {1 ,2 ,3 } result = {1 ,2 ,3 } < {1 ,2 ,3 ,4 ,5 } print('result =' ,result)
四 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 def fn () : print('这是我的第一个函数!' ) print('hello' ) print('今天天气真不错!' ) def fn2 (a , b) : print(a,"+" ,b,"=" ,a + b) fn2(10 ,20 ) fn2(123 ,456 )
4.1 函数的参数 1 2 3 4 5 6 7 8 9 10 def mul (a,b,c) : print(a*b*c) def welcome (username) : print('欢迎' ,username,'光临' ) mul(1 ,2 ,3 ) welcome('张三' )
输出的结果为
参数默认值
1 2 3 4 5 6 7 8 9 10 11 12 def fn (a = 5 , b = 10 , c = 20 ) : print('a =' ,a) print('b =' ,b) print('c =' ,c) fn(1 , 2 , 3 ) fn(1 , 2 ) fn()
实参的传递方式
关键字参数
1 2 3 4 5 6 7 8 9 10 def fn2 (a) : print('a =' ,a)
函数在调用时,解析器不会检查实参的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 b = 123 b = True b = 'hello' b = None b = [1 ,2 ,3 ] fn2(fn) def fn3 (a , b) : print(a+b) def fn4 (a) : a[0 ] = 30 print('a =' ,a,id(a))
传递副本1 2 3 4 5 6 7 8 c = 10 c = [1 , 2 , 3 ] fn4(c) fn4(c.copy()) fn4(c[:]) print('c =' , c, id(c))
4.2不定参数 4.2.1 基本用法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 def sum (*nums) : result = 0 for n in nums : result += n print(result) def fn (*a) : print("a =" ,a,type(a))
带星号的形参只能有一个1 2 3 4 5 6 7 8 9 10 11 def fn2 (a, b, *c) : print('a =' , a) print('b =' , b) print('c =' , c)
可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递 第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
1 2 3 4 def fn2 (a, *b, c) : print('a =' , a) print('b =' , b) print('c =' , c)
所有的位置参数都给a,b和c必须使用关键字参数1 2 3 4 5 6 def fn2 (*a, b, c) : print('a =' , a) print('b =' , b) print('c =' , c)
对于上述实例,运行时会出现异常,结果如下
1 2 3 4 Traceback (most recent call last): File "F:\python\main.py" , line 5 , in <module> print('b =' , b) NameError: name 'b' is not defined
如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递
1 2 3 4 5 6 7 def fn2 (*, a, b, c) : print('a =' , a) print('b =' , b) print('c =' , c) fn2(a=3 , b=4 , c=5 )
形参只能接收位置参数,而不能接收关键字参数1 2 def fn3 (*a) : print('a =' , a)
4.2.2 接收其他的关键字参数 形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中 字典的key就是参数的名字,字典的value就是参数的值 形参只能有一个,并且必须写在所有参数的最后
1 2 3 4 5 6 7 def fn3 (b, c, **a) : print('a =' , a, type(a)) print('b =' , b) print('c =' , c) fn3(b=1 , d=2 , c=3 , e=10 , f=20 )
输出的结果为
1 2 3 a = {'d' : 2 , 'e' : 10 , 'f' : 20 } <class 'dict '> b = 1 c = 3
对于下面的示例
1 2 3 4 5 6 7 def fn3 (b, f, **a) : print('a =' , a, type(a)) print('b =' , b) print('f =' , f) fn3(b=1 , d=2 , c=3 , e=10 , f=20 )
输出的结果为
1 2 3 a = {'d' : 2 , 'c' : 3 , 'e' : 10 } <class 'dict '> b = 1 f = 20
对于另一个示例
1 2 3 4 5 6 7 def fn3 (b, g, **a) : print('a =' , a, type(a)) print('b =' , b) print('g =' , g) fn3(b=1 , d=2 , c=3 , e=10 , f=20 )
运行程序出现问题,输出结果如下
1 2 3 4 Traceback (most recent call last): File "F:\python\main.py" , line 7 , in <module> fn3(b=1 , d=2 , c=3 , e=10 , f=20 ) TypeError: fn3() missing 1 required positional argument: 'g'
4.2.3 参数的解包(拆包) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def fn4 (a, b, c) : print('a =' , a) print('b =' , b) print('c =' , c) t = (10 , 20 , 30 ) d = {'a' : 100 , 'b' : 200 , 'c' : 300 } fn4(**d)
运行上述程序,得到的结果如下
4.3 返回值 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 def sum (*nums) : result = 0 for n in nums : result += n print(result) def fn () : def fn2 () : print('hello' ) return fn2 r = fn() def fn2 () : a = 10 return def fn3 () : print('hello' ) return print('abc' ) def fn4 () : for i in range(5 ): if i == 3 : return print(i) print('循环执行完毕!' ) def sum (*nums) : result = 0 for n in nums : result += n return result r = sum(123 ,456 ,789 ) def fn5 () : return 10 print(fn5) print(fn5())
4.4 文档字符串 help()是Python中的内置函数
通过help()函数可以查询python中的函数的用法
help(print) # 获取print()函数的使用说明
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 def fn (a: int, b: bool, c: str = 'hello' ) -> int: ''' 这是一个文档字符串的示例 函数的作用:。。。。。 函数的参数: a,作用,类型,默认值。。。。 b,作用,类型,默认值。。。。 c,作用,类型,默认值。。。。 ''' return 10 help(fn)
运行上述示例,输出结果如下
1 2 3 4 5 6 7 8 9 10 Help on function fn in module __main__: fn(a: int, b: bool, c: str = 'hello') -> int 这是一个文档字符串的示例 函数的作用:。。。。。 函数的参数: a,作用,类型,默认值。。。。 b,作用,类型,默认值。。。。 c,作用,类型,默认值。。。。
4.5 作用域和命名空间 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 b = 20 def fn () : a = 10 print('函数内部:' , 'a =' , a) print('函数内部:' , 'b =' , b) fn() print('函数外部:' , 'a =' , a) print('函数外部:' , 'b =' , b)
运行上述示例,得到的结果如下
1 2 3 4 5 6 Traceback (most recent call last): File "F:\python\main.py" , line 14 , in <module> print('函数外部:' , 'a =' , a) NameError: name 'a' is not defined 函数内部: a = 10 函数内部: b = 20
在Python中一共有两种作用域 全局作用域
全局作用域在程序执行时创建,在程序执行结束时销毁
所有函数以外的区域都是全局作用域
在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
函数作用域
函数作用域在函数调用时创建,在调用结束时销毁
在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
变量的查找
当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
如果没有则继续去上一级作用域中寻找,如果有则使用,
如果依然没有则继续去上一级作用域中寻找,以此类推
直到找到全局作用域,依然没有找到,则会抛出异常NameError: name ‘a’ is not defined1 2 3 4 5 6 7 8 9 10 def fn2 () : def fn3 () : print('fn3中:' , 'a =' , a) fn3() fn2() a = 20
运行上述示例,得到的输出如下
1 2 3 4 5 6 7 8 Traceback (most recent call last): File "F:\python\main.py" , line 8 , in <module> fn2() File "F:\python\main.py" , line 5 , in fn2 fn3() File "F:\python\main.py" , line 3 , in fn3 print('fn3中:' , 'a =' , a) NameError: name 'a' is not defined
如果将上述示例改为
1 2 3 4 5 6 7 8 9 10 11 a = 20 def fn2 () : def fn3 () : print('fn3中:' , 'a =' , a) fn3() fn2()
则可以得到运行结果
运行以下示例
1 2 3 4 5 6 7 8 9 10 def fn3 () : global a a = 10 print('函数内部:' , 'a =' , a) fn3() print('函数外部:' , 'a =' , a)
得到的结果如下
1 2 函数内部: a = 10 函数外部: a = 10
命名空间(namespace)
如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间 返回的是一个字典
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 scope = locals() print(scope) print(type(scope)) print("--------------------" ) scope['c' ] = 1000 print(scope) print("--------------------" ) def fn4 () : a = 10 scope = locals() print("内部 scope :" , scope) print("--------------------" ) global_scope = globals() print("内部 scope 的 c :" , global_scope['c' ]) print("--------------------" ) global_scope['a' ] = 30 print("内部的 global_scope :" , scope) fn4()
运行上述示例,得到的结果如下
1 2 3 4 5 6 7 8 9 10 已连接到 pydev 调试器 (内部版本 211.7142 .13 ){'__name__' : '__main__' , '__doc__' : None , '__package__' : None , '__loader__' : <_frozen_importlib_external.SourceFileLoader object at 0x0000023CD7436CD0 >, '__spec__' : None , '__file__' : 'F:/python/main.py' , '__builtins__' : <module 'builtins' (built-in )>, 'scope' : {...}} <class 'dict '> -------------------- {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000023CD7436CD0>, '__spec__': None, '__file__': 'F:/python/main.py', '__builtins__': <module 'builtins' (built-in)>, 'scope': {...}, 'c': 1000} -------------------- 内部 scope : {'a' : 10 } -------------------- 内部 scope 的 c : 1000 -------------------- 内部的 global_scope : {'a' : 10 }
4.6 高阶函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 l = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ] def fn2 (i) : if i % 2 == 0 : return True return False def fn3 (i) : if i > 5 : return True return False def fn (func , lst) : ''' fn()函数可以将指定列表中的所有偶数获取出来,并保存到一个新列表中返回 参数: lst:要进行筛选的列表 ''' new_list = [] for n in lst : if func(n) : new_list.append(n) return new_list def fn4 (i) : return i % 3 == 0 def fn5 (a , b) : return a + b fn6 = lambda a,b : a + b r = filter(lambda i : i > 5 , l) l = [1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,10 ] r = map(lambda i : i ** 2 , l) l = ['bb' ,'aaaa' ,'c' ,'ddddddddd' ,'fff' ] l = [2 ,5 ,'1' ,3 ,'6' ,'4' ] l.sort(key=int) l = [2 ,5 ,'1' ,3 ,'6' ,'4' ] print('排序前:' ,l) print(sorted(l,key=int)) print('排序后:' ,l)
4.7 闭包 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 def fn () : a = 10 def inner () : print('我是fn2' , a) return inner r = fn() def make_averager () : nums = [] def averager (n) : nums.append(n) return sum(nums)/len(nums) return averager averager = make_averager() print(averager(10 )) print(averager(20 )) print(averager(30 )) print(averager(40 ))
4.8 装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 def add (a , b) : ''' 求任意两个数的和 ''' r = a + b return r def mul (a , b) : ''' 求任意两个数的积 ''' r = a * b return r
希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
如果要修改的函数过多,修改起来会比较麻烦
并且不方便后期的维护
并且这样做会违反开闭原则(OCP)
程序的设计,要求开发对程序的扩展,要关闭对程序的修改
1 2 3 4 5 6 7 8 9 10 11 12 def fn () : print('我是fn函数....' ) def fn2 () : print('函数开始执行~~~' ) fn() print('函数执行结束~~~' ) fn2()
运行上述程序,得到的结果如下
1 2 3 函数开始执行~~~ 我是fn函数.... 函数执行结束~~~
而对于下面的的示例
1 2 3 4 5 6 7 8 9 def new_add (a, b) : print('计算开始~~~' ) r = add(a, b) print('计算结束~~~' ) return r r = new_add(111 , 222 ) print(r)
运行结果为
上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了 但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了 为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 def begin_end (old) : ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' def new_function (*args , **kwargs) : print('开始执行~~~~' ) result = old(*args , **kwargs) print('执行结束~~~~' ) return result return new_function f = begin_end(fn) f2 = begin_end(add) f3 = begin_end(mul) def fn3 (old) : ''' 用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束 参数: old 要扩展的函数对象 ''' def new_function (*args , **kwargs) : print('fn3装饰~开始执行~~~~' ) result = old(*args , **kwargs) print('fn3装饰~执行结束~~~~' ) return result return new_function @fn3 @begin_end def say_hello () : print('大家好~~~' ) say_hello()
五 对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 a = int(10 ) b = str('hello' ) class MyClass () : pass mc = MyClass() mc_2 = MyClass() mc_3 = MyClass() mc_4 = MyClass() result = isinstance(mc_2,MyClass) result = isinstance(mc_2,str) mc.name = '孙悟空' mc_2.name = '猪八戒' print(mc_2.name)
5.1 定义类 5.1.1 基本定义 类和对象都是对现实生活中的事物或程序中的内容的抽象
实际上所有的事物都由两部分构成: 1.数据(属性) 2.行为(方法)
在类的代码块中,我们可以定义变量和函数, 变量会成为该类实例的公共属性,所有的该类实例都可以通过 对象.属性名 的形式访问 函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法
注意: 方法调用时,第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参!
实例为什么能访问到类中的属性和方法 类中定义的属性和方法都是公共的,任何该类实例都可以访问
属性和方法查找的流程 当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性, 如果有,则直接返回当前的对象的属性值, 如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值, 如果类对象中依然没有,则报错!
类对象和实例对象中都可以保存属性(方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Person : name = 'swk' def say_hello (self) : print('你好!我是 %s' % self.name) p1 = Person() p2 = Person() print(p2.name) p1.name = '猪八戒' p2.name = '沙和尚' p1.say_hello() p2.say_hello() del p2.name print(p1.name) print(p2.name)
5.1.2 name 属性 一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用name 属性来使该程序块仅在该模块自身运行时执行。
1 2 3 4 5 6 7 if __name__ == '__main__' : print('程序自身在运行' ) else : print('我来自另一模块' )
运行输出如下:
1 2 $ python using_name.py 程序自身在运行
1 2 3 4 $ python >>> import using_name我来自另一模块 >>>
说明: 每个模块都有一个name 属性,当其值是’main ‘时,表明该模块自身在运行,否则是被引入。
说明:name 与 main 底下是双下划线, 是这样去掉中间的那个空格。
5.2 类的初始化 在类中可以定义一些特殊方法(魔术方法)
特殊方法都是以 开头, 结尾的方法
特殊方法不需要我们自己调用,不要尝试去调用特殊方法
特殊方法将会在特殊的时刻自动调用
学习特殊方法: 1.特殊方法什么时候调用 2.特殊方法有什么作用
创建对象的流程
创建一个变量
在内存中创建一个新对象
init (self)方法执行
将对象的id赋值给变量
1 2 3 4 5 6 7 8 9 10 11 class Person : def __init__ (self,name) : self.name = name def say_hello (self) : print('大家好,我是%s' %self.name)
目前来讲,对于Person类来说name是必须的,并且每一个对象中的name属性基本上都是不同.而我们现在是将name属性在定义为对象以后,手动添加到对象中,这种方式很容易出现错误.我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Person : def __init__ (self, name) : self.name = name def say_hello (self) : print('大家好,我是%s' % self.name) p1 = Person() p1.name = '孙悟空' p3 = Person() p3.name = '沙和尚' p3.say_hello()
运行上述示例,运行时出现异常,结果如下
1 2 3 4 Traceback (most recent call last): File "F:\python\main.py" , line 14 , in <module> p1 = Person() TypeError: __init__() missing 1 required positional argument: 'name'
修改上述示例为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Person : def __init__ (self, name) : self.name = name def say_hello (self) : print('大家好,我是%s' % self.name) p1 = Person('孙悟空' ) p2 = Person('猪八戒' ) p3 = Person('沙和尚' ) p4 = Person('唐僧' ) print(p1.name) print(p2.name) print(p3.name) print(p4.name) p4.say_hello()
运行程序,得到的结果为
5.3 类中的属性和方法 5.3.1 基本定义 类的私有属性
__private_attrs :两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs 。
类的方法
在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self ,且为第一个参数,self 代表的是类的实例。
self 的名字并不是规定死的,也可以使用 this ,但是最好还是按照约定使用 self 。
类的私有方法
__private_method :两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 class A (object) : count = 0 def __init__ (self) : self.name = '孙悟空' def test (self) : print('这是test方法~~~ ' , self) @classmethod def test_2 (cls) : print('这是test_2方法,他是一个类方法~~~ ' , cls) print(cls.count) @staticmethod def test_3 () : print('test_3执行了~~~' ) a = A() a.count = 10 A.count = 100 print('A.count = ,' , A.count) print('a.count = ,' , a.count) print('a.name ,' , a.name) a.test() A.test(a) A.test_2() a.test_2() A.test_3() a.test_3()
运行结果如下
1 2 3 4 5 6 7 8 9 10 11 A.count = , 100 a.count = , 10 a.name , 孙悟空 这是test方法~~~ <__main__.A object at 0x00000190A1B3EF70 > 这是test方法~~~ <__main__.A object at 0x00000190A1B3EF70 > 这是test_2方法,他是一个类方法~~~ <class '__main__ .A '> 100 这是test_2 方法,他是一个类方法~~~ <class '__main__ .A '> 100 test_3 执行了~~~test_3 执行了~~~
5.3.2 静态方法、普通方法、类方法 静态方法 : 用 @staticmethod 装饰的不带 self 参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。
普通方法 : 默认有个self参数,且只能被对象调用。
类方法 : 默认有个 cls 参数,可以被类和对象调用,需要加上 @classmethod 装饰器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Classname : @staticmethod def fun () : print('静态方法' ) @classmethod def a (cls) : print('类方法' ) def b (self) : print('普通方法' ) Classname.fun() Classname.a() C = Classname() C.fun() C.a() C.b()
运行结果如下
类方法
使用装饰器@classmethod。
原则上,类方法是将类本身作为对象进行操作的方法。假设有个方法,且这个方法在逻辑上采用类本身作为对象来调用更合理,那么这个方法就可以定义为类方法。另外,如果需要继承,也可以定义为类方法。
静态方法
使用装饰器@staticmethod
静态方法是类中的函数,不需要实例。静态方法主要是用来存放逻辑性的代码,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个独立的、单纯的 函数,它仅仅托管于某个类的名称空间中,便于使用和维护。
5.4 特殊方法 类的专有方法:
init : 构造函数,在生成对象时调用
del : 析构函数,释放对象时使用
repr : 打印,转换
setitem : 按照索引赋值
getitem : 按照索引获取值
len : 获得长度
cmp : 比较运算
call : 函数调用
add : 加运算
sub : 减运算
mul : 乘运算
truediv : 除运算
mod : 求余运算
pow : 乘方
所有专有方法中,init ()要求无返回值,或者返回 None。而其他方法,如str ()、add ()等,一般都是要返回值的,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 class Person (object) : """人类""" def __init__ (self, name, age) : self.name = name self.age = age def __str__ (self) : return 'Person [name=%s , age=%d]' % (self.name, self.age) def __repr__ (self) : return 'Hello' def __bool__ (self) : return self.age > 17 def __gt__ (self, other) : return self.age > other.age p1 = Person('孙悟空' , 18 ) p2 = Person('猪八戒' , 28 ) print("p1 = " , p1) print("p2 = " , p2) print("repr(p1) = " , repr(p1)) print("p1 > p2 : " , p1 > p2) print("p2 > p1 : " , p2 > p1) print("bool(p1) " , bool(p1)) if p1: print(p1.name, '已经成年了' ) else : print(p1.name, '还未成年了' )
运行上述程序,得到的结果
1 2 3 4 5 6 7 p1 = Person [name=孙悟空 , age=18 ] p2 = Person [name=猪八戒 , age=28 ] repr(p1) = Hello p1 > p2 : False p2 > p1 : True bool(p1) True 孙悟空 已经成年了
str 函数
str 是一个类的方法,在打印类对象,获取其属性信息时调用。打印一个实例化对象时,默认打印的其实时一个对象的地址,但是我们可以对其进行重载,打印我们想要的信息。
针对 str 方法给出一个比较直观的例子
1 2 3 4 5 6 7 8 9 10 11 class people : def __init__ (self,name,age) : self.name=name self.age=age def __str__ (self) : return '这个人的名字是%s,已经有%d岁了!' %(self.name,self.age) a=people('孙悟空' ,999 ) print(a)
输出:
1 2 3 4 这个人的名字是孙悟空,已经有999 岁了! 如果没有重载函数的话输出的就是一串看不懂的字符串: <__main__.people object at 0x00000272A730D278 >
类的专有方法中,也是存在默认优先级的,多个方法都有返回值,但一般优先取 str () 的返回值,如下面例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Vector : def __init__ (self, a, b) : self.a = a self.b = b def __repr__ (self) : return 'Vector (%d, %d)' % (self.b, self.a) 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 ) print (v1)
结果是 Vector(2,10),而不是 Vector(10,2)。这里优先使用 str () 的返回值。
结果是:Vector(10,2)
5.5 封装 封装是面向对象的三大特性之一 封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
如何隐藏一个对象中的属性?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Dog : ''' 表示狗的类 ''' def __init__ (self, name, age) : self.hidden_name = name self.hidden_age = age def say_hello (self) : print('大家好,我是 %s' % self.hidden_name) def get_name (self) : ''' get_name()用来获取对象的name属性 ''' return self.hidden_name def set_name (self, name) : self.hidden_name = name def get_age (self) : return self.hidden_age def set_age (self, age) : if age > 0 : self.hidden_age = age d = Dog('旺财' , 8 ) d.say_hello() d.set_name('小黑' ) d.set_age(-10 ) d.say_hello() print(d.get_age())
运行上述程序,得到的结果如下
5.5.1 属性隐藏 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Rectangle : ''' 表示矩形的类 ''' def __init__ (self, width, height) : self.hidden_width = width self.hidden_height = height def get_width (self) : return self.hidden_width def get_height (self) : return self.hidden_height def set_width (self, width) : self.hidden_width = width def set_height (self, height) : self.hidden_height = height def get_area (self) : return self.hidden_width * self.hidden_height r = Rectangle(5 , 2 ) r.set_width(10 ) r.set_height(20 ) print(r.get_area())
运行上述示例,结果为
可以为对象的属性使用双下划线开头,__xxx
双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问 其实隐藏属性只不过是Python自动为属性改了一个名字实际上是将名字修改为了,_类名属性名 比如 name -> _Person__name
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Person : def __init__ (self, name) : self.__name = name def get_name (self) : return self.__name def set_name (self, name) : self.__name = name p = Person('孙悟空' ) print(p.__name)
运行上述示例,得到的结果如下
1 2 3 4 Traceback (most recent call last): File "F:\python\main.py" , line 14 , in <module> print(p.__name) AttributeError: 'Person' object has no attribute '__name'
若将上述程序替换为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Person : def __init__ (self, name) : self.__name = name def get_name (self) : return self.__name def set_name (self, name) : self.__name = name p = Person('孙悟空' ) p.__name = '猪八戒' print(p._Person__name) p._Person__name = '猪八戒' print(p.get_name())
则运行的结果为
重写示例程序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Person : def __init__ (self, name) : self._name = name def get_name (self) : return self._name def set_name (self, name) : self._name = name p = Person('孙悟空' ) print(p._name)
运行以上程序,得到的结果如下
5.5.2 装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Person : def __init__ (self, name, age) : self._name = name self._age = age @property def name (self) : print('get方法执行了~~~' ) return self._name @name.setter def name (self, name) : print('setter方法调用了' ) self._name = name @property def age (self) : return self._age @age.setter def age (self, age) : self._age = age p = Person('猪八戒' , 18 ) p.name = '孙悟空' p.age = 28 print(p.name, p.age)
运行上述程序,得到的结果为
1 2 3 setter方法调用了 get方法执行了~~~ 孙悟空 28
5.6 继承 定义一个类 Animal(动物) 这个类中需要两个方法:run() sleep()
1 2 3 4 5 6 7 8 9 class Animal : def run (self) : print('动物会跑~~~' ) def sleep (self) : print('动物睡觉~~~' ) def bark (self) : print('动物嚎叫~~~' )
定义一个类 Dog(狗)
这个类中需要三个方法:run() sleep() bark()
1 2 3 4 5 6 7 8 9 class Dog : def run (self) : print('狗会跑~~~' ) def sleep (self) : print('狗睡觉~~~' ) def bark (self) : print('汪汪汪~~~' )
有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
如何能让这个类来实现全部的功能呢?
① 直接修改这个类,在这个类中添加我们需要的功能
② 直接创建一个新的类
创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
③ 直接从Animal类中来继承它的属性和方法
继承是面向对象三大特性之一
通过继承我们可以使一个类获取到其他类中的属性和方法
在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super) 子类(衍生类)可以直接继承父类中的所有的属性和方法
通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则 所以我们经常需要通过继承来对一个类进行扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Animal : def run (self) : print('动物会跑~~~' ) def sleep (self) : print('动物睡觉~~~' ) def bark (self) : print('动物嚎叫~~~' ) class Dog (Animal) : def bark (self) : print('汪汪汪~~~' ) def run (self) : print('狗跑~~~~' ) class Hashiqi (Dog) : def fan_sha (self) : print('我是一只傻傻的哈士奇' ) d = Dog() h = Hashiqi() d.run() d.sleep() d.bark() r = isinstance(d, Dog) r = isinstance(d, Animal) print(r)
运行程序,得到的结果如下
1 2 3 4 狗跑~~~~ 动物睡觉~~~ 汪汪汪~~~ True
重写程序,得到以下结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Animal : def run (self) : print('动物会跑~~~' ) def sleep (self) : print('动物睡觉~~~' ) def bark (self) : print('动物嚎叫~~~' ) class Dog (Animal) : def bark (self) : print('汪汪汪~~~' ) def run (self) : print('狗跑~~~~' ) class Person (object) : pass print(issubclass(Animal, Dog)) print(issubclass(Animal, object)) print(issubclass(Person, object)) print(isinstance(print , object))
运行结果如下
另外一种继承的写法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Animal : def __init__ (self,name) : self._name = name def run (self) : print('动物会跑~~~' ) def sleep (self) : print('动物睡觉~~~' ) @property def name (self) : return self._name @name.setter def name (self,name) : self._name = name
父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Dog (Animal) : def __init__ (self, name, age) : super().__init__(name) self._age = age def bark (self) : print('汪汪汪~~~' ) def run (self) : print('狗跑~~~~' ) @property def age (self) : return self._age @age.setter def age (self, age) : self._age = age d = Dog('旺财' , 18 ) print(d.name) print(d.age)
运行结果如下
Python3 类方法总结
普通方法:对象访问
私有方法:两个下划线开头,只能在类内部访问
静态方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
类方法:类和对象访问,不能和其他方法重名,不然会相互覆盖,后面定义的会覆盖前面的
多继承情况下:从左到右查找方法,找到为止,不然就抛出异常
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 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 say : i am %d." % (self.name, self.age)) print("People.age = " , People.age) print("People.name = " , People.name) p = People('Python' , 10 , 20 ) p.speak() print(p.name, '--' , p.age) print("People.age = " , People.age) print("People.name = " , People.name)
运行结果如下
1 2 3 4 5 6 People.age = 0 People.name = Python say : i am 10. Python -- 10 People.age = 0 People.name =
单继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Student (People) : grade='' def __init__ (self,n,a,w,g) : People.__init__(self,n,a,w) self.grade = g def speak () : print("%s 说: 我 %d 岁了,我在读 %d 年级" %(self.name,self.age,self.grade)) class Speak () : topic='' name='' def __init__ (self,n,t) : self.name = n self.topic = t def speak (self) : print("我叫 %s,我是一个演说家,我演讲的主题是 %s" %(self.name,self.topic)) def __song (self) : print('唱一首歌自己听' ,self); @staticmethod def song () : print('唱一首歌给类听:静态方法' ); def song (self) : print('唱一首歌给你们听' ,self); @classmethod def song (self) : print('唱一首歌给类听:类方法' ,self)
5.6.1 多重继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class A : def test (self) : print('AAA' ) class B (object) : def test (self) : print('B中的test()方法~~' ) def test2 (self) : print('BBB' ) class C (A, B) : pass print("C.__bases__ = " , C.__bases__) print("B.__bases__ = " , B.__bases__) print("A.__bases__ = " , A.__bases__) c = C() c.test()
运行结果如下
1 2 3 4 C.__bases__ = (<class '__main__.A'>, <class '__main__.B'>) B.__bases__ = (<class 'object'>,) A.__bases__ = (<class 'object'>,) AAA
5.7 重写 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Animal : def run (self) : print('动物会跑~~~' ) def sleep (self) : print('动物睡觉~~~' ) class Dog (Animal) : def bark (self) : print('汪汪汪~~~' ) def run (self) : print('狗跑~~~~' )
如果在子类中如果有和父类同名的方法,则通过子类实例去调用方法时, 会调用子类的方法而不是父类的方法,这个特点我们成为叫做方法的重写(覆盖,override)
当我们调用一个对象的方法时,会优先去当前对象中寻找是否具有该方法,如果有则直接调用.如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class A (object) : def test (self) : print('AAA' ) class B (A) : def test (self) : print('BBB' ) class C (B) : def test (self) : print('CCC' ) c = C() c.test()
5.8 垃圾回收 就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾。程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理。没用的东西就是垃圾,在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能,所以我们必须进行及时的垃圾回收。所谓的垃圾回收就是讲垃圾对象从内存中删除 在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,所以我们不用手动处理垃圾回收
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class A : def __init__ (self) : self.name = 'A类' def __del__ (self) : print('A()对象被删除了~~~' , self) a = A() b = a print(a.name) a = None b = None input('回车键退出...' )
运行的结果如下
1 2 3 A类 A()对象被删除了~~~ <__main__.A object at 0x000001EE4A36DFD0 > 回车键退出...
5.9 模块 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py。模块可以被别的程序引入,以使用该模块中的函数等功能。这也是使用 python 标准库的方法。
模块(module)
模块化,模块化指将一个完整的程序分解为一个一个小的模块,通过将模块组合,来搭建出一个完整的程序。不采用模块化,统一将所有的代码编写到一个文件中,采用模块化,将程序分别编写到多个文件中 模块化的优点: ① 方便开发 ② 方便维护 ③ 模块可以复用!
在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件
注意:模块名要符号标识符的规范
在一个模块中引入外部模块
1 2 3 import 模块名 (模块名,就是python文件的名字,注意不要py)或者 import 模块名 as 模块别名
可以引入同一个模块多次,但是模块的实例只会创建一个
import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
在每一个模块内部都有一个name 属性,通过这个属性可以获取到模块的名字
name 属性值为 main 的模块是主模块,一个程序中只会有一个主模块 主模块就是我们直接通过 python 执行的模块
1 2 3 4 5 6 import test_module as testprint(__name__)
import 语句
想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:
1 import module1[, module2[,... moduleN]
当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。
搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support,需要把命令放在脚本的顶端:
support.py 文件代码
1 2 3 4 5 6 7 def print_func ( par ) : print ("Hello : " , par) return
test.py 引入 support 模块
test.py 文件代码
1 2 3 4 5 6 7 8 9 import support support.print_func("Runoob" )
以上实例输出结果
1 2 $ python3 test.py Hello : Runoob
一个模块只会被导入一次,不管你执行了多少次import。这样可以防止导入模块被一遍又一遍地执行
使用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 def test2 () : print('这是主模块中的test2' ) from m import *
from … import 语句
Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:
1 from modname import name1[, name2[, ... nameN]]
例如,要导入模块 fibo 的 fib 函数,使用如下语句:
1 2 3 >>> from fibo import fib, fib2 >>> fib(500) 1 1 2 3 5 8 13 21 34 55 89 144 233 377
这个声明不会把整个fibo模块导入到当前的命名空间中,它只会将fibo里的fib函数引入进来。
from … import * 语句
把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:
这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。
5.10 包 5.10.1 基本使用 包是一种管理 Python 模块命名空间的形式,采用”点模块名称”。
比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B 。
就好像使用模块的时候,你不用担心不同模块之间的全局变量相互影响一样,采用点模块名称这种形式也不用担心不同库之间的模块重名的情况。
这样不同的作者都可以提供 NumPy 模块,或者是 Python 图形库。
不妨假设你想设计一套统一处理声音文件和数据的模块(或者称之为一个”包”)。
现存很多种不同的音频文件格式(基本上都是通过后缀名区分的,例如: .wav,:file:.aiff,:file:.au,),所以你需要有一组不断增加的模块,用来在不同的格式之间转换。
并且针对这些音频数据,还有很多不同的操作(比如混音,添加回声,增加均衡器功能,创建人造立体声效果),所以你还需要一组怎么也写不完的模块来处理这些操作。
这里给出了一种可能的包结构(在分层的文件系统中):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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 变量赋值。
用户可以每次只导入一个包里面的特定模块,比如:
1 import sound.effects.echo
这将会导入子模块:sound.effects.echo。 他必须使用全名去访问
1 sound.effects.echo.echofilter(input, output, delay=0.7 , atten=4 )
还有一种导入子模块的方法是
1 from sound.effects import echo
这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
1 echo.echofilter(input, output, delay=0.7 , atten=4 )
还有一种变化就是直接导入一个函数或者变量:
1 from sound.effects.echo import echofilter
同样的,这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:
1 echofilter(input, output, delay=0.7 , atten=4 )
还有一种导入子模块的方法是:
1 from sound.effects import echo
这同样会导入子模块: echo,并且他不需要那些冗长的前缀,所以他可以这样使用:
1 echo.echofilter(input, output, delay=0.7 , atten=4 )
还有一种变化就是直接导入一个函数或者变量:
1 from sound.effects.echo import echofilter
同样的,这种方法会导入子模块: echo,并且可以直接使用他的 echofilter() 函数:
1 echofilter(input, output, delay=0.7, atten=4)
注意当使用 from package import item 这种形式的时候,对应的 item 既可以是包里面的子模块(子包),或者包里面定义的其他名称,比如函数,类或者变量。
import 语法会首先把 item 当作一个包定义的名称,如果没找到,再试图按照一个模块去导入。如果还没找到,抛出一个 :exc:ImportError 异常。
反之,如果使用形如 import item.subitem.subsubitem 这种导入形式,除了最后一项,都必须是包,而最后一项则可以是模块或者是包,但是不可以是类,函数或者变量的名字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from hello import a , bprint(a.c) print(b.d)
5.10.2 从一个包中导入* 如果我们使用 from sound.effects import * 会发生什么呢?
这种方式进行导入,如果不同模块之间有相同的函数命名,最后导入的会覆盖前面的,也就是说只会调用到最后导入进的函数。
Python 会进入文件系统,找到这个包里面所有的子模块,然后一个一个的把它们都导入进来。但这个方法在 Windows 平台上工作的就不是非常好,因为 Windows 是一个不区分大小写的系统。在 Windows 平台平台上,我们无法确定一个叫做 ECHO.py 的文件导入为模块是 echo 还是 Echo,或者是 ECHO。为了解决这个问题,我们只需要提供一个精确包的索引。导入语句遵循如下规则:如果包定义文件 init .py 存在一个叫做 all 的列表变量,那么在使用 from package import * 的时候就把这个列表中的所有名字作为包内容导入。
以下实例在 file:sounds/effects/init .py 中包含如下代码:
1 __all__ = ["echo" , "surround" , "reverse" ]
这表示当你使用from sound.effects import *这种用法时,你只会导入包里面这三个子模块。
如果 all 真的没有定义,那么使用from sound.effects import * 这种语法的时候,就不会导入包 sound.effects 里的任何子模块。他只是把包sound.effects和它里面定义的所有内容导入进来(可能运行 init .py里定义的初始化代码)。
这会把 init .py 里面定义的所有名字导入进来。并且他不会破坏掉我们在这句话之前导入的所有明确指定的模块。看下这部分代码:
1 2 3 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。
1 2 3 from . import echo from .. import formats from ..filters import equalizer
无论是隐式的还是显式的相对导入都是从当前模块开始的。主模块的名字永远是”main “,一个Python应用程序的主模块,应当总是使用绝对路径引用。
包还提供一个额外的属性 path 。这是一个目录列表,里面每一个包含的目录都有为这个包服务的 init .py,你得在其他 init .py被执行前定义哦。可以修改这个变量,用来影响包含在包里面的模块和子包。
这个功能并不常用,一般用来扩展包里面的模块。
5.11 标准库 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 import sysimport pprintimport osos.system('notepad' )
六 异常 Python3 内置异常类型的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError | +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError | +-- UnboundLocalError +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning
对于下面的示例
1 2 3 4 5 6 7 8 9 10 11 12 print('hello' ) try : print(10 / 0 ) except : print('哈哈哈,出错了~~~' ) else : print('程序正常执行没有错误' ) print('你好' ) print(10 / 0 )
运行结果为
1 2 3 4 5 6 7 Traceback (most recent call last): File "F:\python\main.py" , line 12 , in <module> print(10 / 0 ) ZeroDivisionError: division by zero hello 哈哈哈,出错了~~~ 你好
而对于下面的示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def fn () : print('Hello fn' ) print(a) print(10 / 0 ) def fn2 () : print('Hello fn2' ) fn() def fn3 () : print('Hello fn3' ) fn2() fn3()
运行结果为
1 2 3 4 5 6 7 8 9 10 11 12 13 Traceback (most recent call last): File "F:\python\main.py" , line 17 , in <module> fn3() File "F:\python\main.py" , line 14 , in fn3 fn2() File "F:\python\main.py" , line 9 , in fn2 fn() File "F:\python\main.py" , line 3 , in fn print(a) NameError: name 'a' is not defined Hello fn3 Hello fn2 Hello fn
6.1 异常对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 print('异常出现前' ) l = [] try : print(10 / 0 ) except NameError: print('出现 NameError 异常' ) except ZeroDivisionError: print('出现 ZeroDivisionError 异常' ) except IndexError: print('出现 IndexError 异常' ) except Exception as e: print('未知异常' , e, type(e)) finally : print('无论是否出现异常,该子句都会执行' ) print('异常出现后' )
运行上述代码,结果为
1 2 3 4 异常出现前 出现 ZeroDivisionError 异常 无论是否出现异常,该子句都会执行 异常出现后
在 python3 中,处理带有参数的异常的方法如下
1 2 3 4 5 6 7 8 9 10 def temp_convert (var) : try : return int(var) except (ValueError) as Argument: print("参数没有包含数字\n" , Argument) temp_convert("xyz" );
运行结果为
1 2 参数没有包含数字 invalid literal for int() with base 10 : 'xyz'
6.2 抛出异常 Python 使用 raise 语句抛出一个指定的异常。
raise语法格式如下:
1 raise [Exception [, args [, traceback]]]
以下实例如果 x 大于 5 就触发异常:
1 2 3 x = 10 if x > 5 : raise Exception('x 不能大于 5。x 的值为: {}' .format(x))
执行以上代码会触发异常:
1 2 3 4 Traceback (most recent call last): File "test.py" , line 3 , in <module> raise Exception('x 不能大于 5。x 的值为: {}' .format(x)) Exception: x 不能大于 5 。x 的值为: 10
raise 唯一的一个参数指定了要被抛出的异常。它必须是一个异常的实例或者是异常的类(也就是 Exception 的子类)。
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出。
6.3 用户自定义异常 你可以通过创建一个新的异常类来拥有自己的异常。异常类继承自 Exception 类,可以直接继承,或者间接继承,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class MyError (Exception) : pass def add (a, b) : if a < 0 or b < 0 : raise MyError('自定义的异常' ) r = a + b return r print(add(-123 , 456 ))
输出的结果为
1 2 3 4 5 6 Traceback (most recent call last): File "F:\python\main.py" , line 21 , in <module> print(add(-123 , 456 )) File "F:\python\main.py" , line 13 , in add raise MyError('自定义的异常' ) __main__.MyError: 自定义的异常
6.4 异常捕获 使用一个快捕捉多个异常
1 2 3 4 5 6 7 8 9 10 def model_exception (x, y) : try : b = name a = x / y except (ZeroDivisionError, NameError, TypeError): print('one of ZeroDivisionError or NameError or TypeError happend' ) model_exception(2 , 0 )
输出如下:
1 one of ZeroDivisionError or NameError or TypeError happend
捕获所有异常
1 2 3 4 5 try : ... except Exception as e: ... log('Reason:' , e)
这个将会捕获除了 SystemExit 、 KeyboardInterrupt 和 GeneratorExit 之外的所有异常。 如果你还想捕获这三个异常,将 Exception 改成 BaseException 即可。
一个 try 语句可能包含多个except子句,分别来处理不同的特定的异常。最多只有一个分支会被执行。
处理程序将只针对对应的 try 子句中的异常进行处理,而不是其他的 try 的处理程序中的异常。
一个except子句可以同时处理多个异常,这些异常将被放在一个括号里成为一个元组,例如:
1 2 except (RuntimeError, TypeError, NameError): pass
最后一个except子句可以忽略异常的名称,它将被当作通配符使用。你可以使用这种方法打印一个错误信息,然后再次把异常抛出
1 2 3 4 5 6 7 8 9 10 11 12 13 import systry : f = open('myfile.txt' ) s = f.readline() i = int(s.strip()) except OSError as err: print("OS error: {0}" .format(err)) except ValueError: print("Could not convert data to an integer." ) except : print("Unexpected error:" , sys.exc_info()[0 ]) raise
运行结果为
1 OS error: [Errno 2 ] No such file or directory: 'myfile.txt'
一个最全面的示例
1 2 3 4 5 6 7 8 9 10 11 12 try : runoob() except AssertionError as error: print(error) else : try : with open('file.log' ) as file: read_data = file.read() except FileNotFoundError as fnf_error: print(fnf_error) finally : print('这句话,无论异常是否发生都会执行。' )
运行结果为
1 2 3 4 5 Traceback (most recent call last): File "F:\python\main.py" , line 2 , in <module> runoob() NameError: name 'runoob' is not defined 这句话,无论异常是否发生都会执行。
七 文件读写 7.1 打开文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 file_name = 'demo.txt' file_name = 'hello\\demo.txt' file_name = r'hello\demo.txt' file_name = '../hello/demo.txt' file_name = r'C:\Users\lilichao\Desktop\hello.txt' file_obj = open(file_name)
7.2 关闭文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 file_name = 'demo.txt' file_name = 'hello' try : with open(file_name) as file_obj: print(file_obj.read()) except FileNotFoundError: print(f'{file_name} 文件不存在~~' )
7.3 文件的读取 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 file_name = 'demo2.txt' try : with open(file_name, encoding='utf-8' ) as file_obj: content = file_obj.read(6 ) content = file_obj.read(6 ) content = file_obj.read(6 ) content = file_obj.read(6 ) except FileNotFoundError: print(f'{file_name} 这个文件不存在!' )
读取一个大文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 file_name = 'demo.txt' try : with open(file_name, encoding='utf-8' ) as file_obj: file_content = '' chunk = 100 while True : content = file_obj.read(chunk) if not content: break file_content += content except FileNotFoundError: print(f'{file_name} 这个文件不存在!' ) print(file_content)
另一个示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import pprintimport osfile_name = 'demo.txt' with open(file_name, encoding='utf-8' ) as file_obj: for t in file_obj: print(t)
7.4 文件的写入 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 file_name = 'demo5.txt' with open(file_name, 'x' , encoding='utf-8' ) as file_obj: file_obj.write('aaa\n' ) file_obj.write('bbb\n' ) file_obj.write('ccc\n' ) r = file_obj.write(str(123 ) + '123123\n' ) r = file_obj.write('今天天气真不错' ) print(r)
将一个文件里的内容写入到另一个文件‘
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 file_name = 'c:/Users/lilichao/Desktop/告白气球.flac' with open(file_name, 'rb' ) as file_obj: new_name = 'aa.flac' with open(new_name, 'wb' ) as new_obj: chunk = 1024 * 100 while True : content = file_obj.read(chunk) if not content: break new_obj.write(content)