项目
博客
文档
归档
资源链接
关于我
项目
博客
文档
归档
资源链接
关于我
Python总结
2024-09-23
·
·
原创
·
Python
·
本文共 6,287个字,预计阅读需要 21分钟。
### 1. python相关介绍说明 python是一种广泛使用的解释型,高级编程,通用型编程语言,由吉多范罗苏姆创造,第一次发布与1991年,它的设计哲学强调代码可读下和简洁性。使用空格缩进进行划分代码块。 > 编译型语言:源代码一次编译为机器码,多次执行后输出,例如:c,c++等语言 > > 解释型语言:源代码要通过代码解析器解释为机器语言,再执行输出;例如:python, javascript等 python特点: ```python 优点: 简单易上手,代码风格简,免费开源,完善的基础代码库,众多的第三方库,代码可读性高,程序可移植 缺点:相对于编译型语言速度会慢点,代码不能加密 ``` > python的主要应用场景:
网络爬虫,数据处理,web编程,人工智能,机器学习,自动化运维,数据处理,数据挖掘,大数据领域,自动化测试
。 ### 2.python数据类型 ###### python的数字类型(三种) >
整数(int)
:可正可负。python3中不限大小 > >
浮点型(float)
: 可正可负。可使用科学计数法表示:`1.1e2` = 1.1x10^2 =110.0 > >
复数
: 由实数和虚数部分构成。` 12 +3j`,或者`complex(12,3)` 方法介绍: >
type(xx)
: 返回xx的类型 > >
id(xx)
: 返回xx指向的地址id > > 举例: a=1 b=1 --->此时id(a)是等于id(b)的,因为他们指向的地址是相同的 进制的默认表示: >
二进制: 0b
+二进制的数: 0b1010 =10 > >
八进制:0o
+八进制的数: 0o12 =10 > >
十六进制: 0x
+十六进制的数:0x11 =17 方法介绍: >
bin(xx)
: 其他进制转换为二进制:bin(0o12) = 0b1010 >
oct(xx)
: 其他进制转八进制: oct(0b1010) = 0o12 >
int('xx',x)
: 其他进制转十进制: int('0b1010',2) =10, int('0o12',8) =10 >
hex(xx)
: 其他进制转十六进制进制:hex(0b1010) = 0xa ###### python的布尔类型(True,False) 方法介绍: >
isinstance(xx,x)
: 判断xx是否是x类型,返回布尔类型:isinstance(12,int) =True > >
bool(xx)
: 布尔类型: bool(0) =False bool(1) =True ###### python的字符串类型('xx' "xx" '''xxx ''') > 在字符串中存在`''或者""或者'''`的时候,使用反斜杠转义\: 'I\'m yuan' = I'm yuan > '''中的的字符串中存在换行的,返回的数据也是换行的: > > ``` > '''你好 > 吗''' ==> 你好 > 吗 > ``` > > 在`''`或者`""`中换行使用`\n`来进行换行操作 特殊符号的转义字符: ``` \a 发出系统铃声 \' 单引号 \n 换行 \\ 反斜杠 \" 双引号 \b 退格 \t 纵向制表符 \v 横向制表符 \t 回车 \f 换页 ``` 方法介绍: >
a[x]
: 获取a的下标为x(为负时,是从右到左)的字符: a="qwerty" a[1]=w a[-1]=y > >
a[x:xx]
: 获取从下标x到下标xx的字符串(不包括xx) a[0:2] = qw a[-3:-1]=rt > >
a[x:]
: 获取从下标x到字符串结尾 a[2:] =erty > >
a[:xx]
: 获取字符串从o位到下标xx的字符串(不包括xx) a[:3] =qwe >
占位符: %c字符 %s字符串 %d整数 %f浮点数
> > ```python > a="my name is %s,l\'m from %s" %("yuan","sichuan") > print(a) = my name is yuan,l'm from sichuan > > b="my name is yuan","l\'m from sichuan" > print(b) = ('my name is yuan', "l'm from sichuan") > ``` ### 3.python运算 > 算术运算符: + - * / % // ** 对应 加 减 乘 除 取余 取整 取幂 > > 比较运算符:> < == >= <= != <>(低版本存在,为不等于,python3已废弃) > > 赋值运算符:= += -= *= /= //= %= **= > > 位运算符: & | << >> ~ ^ 按位与 按位或 左移动 右移动 按位取反 按位异或 > > 逻辑运算符:and or not 与 或 非 > > 成员运算符:in not in 在xx里面 不在xx里面 > > 身份运算符: is is not 是xx 不是xx > > ```python > 10//3 =3 2**3 =8 > a=3 a**=2=a**2 =9 > a=1 b=2 (a=1 and b=2) (not a=1) > a="123" b="12" b in a =>True > a="123" b="123" a is b =>True > ``` > > is与==的区别:is用于判断两个变量`引用的对象是否是同一个`, ==用于判断`引用的变量的值`是否相等 > > ``` > a=[1,2,3] b=a[:] (a is b)=False (a==b)=True > ``` 运算符的优先级:(优先级越大的越优先) | 运算符说明 | Python运算符 | 优先级 | | ---------- | ------------------------------------ | :----: | | 小括号 | () | 20 | | 索引运算符 | x[index] 或 x[index:index2[:index3]] | 18、19 | | 属性访问 | x.attrbute | 17 | | 乘方 | ** | 16 | | 按位取反 | ~ | 15 | | 符号运算符 | +(正号)或 -(负号) | 14 | | 乘、除 | *、/、//、% | 13 | | 加、减 | +、- | 12 | | 位移 | >>、<< | 11 | | 按位与 | & | 10 | | 按位异或 | ^ | 9 | | 按位或 | \| | 8 | | 比较运算符 | ==、!=、>、>=、<、<= | 7 | | is 运算符 | is、is not | 6 | | in 运算符 | in、not in | 5 | | 逻辑非 | not | 4 | | 逻辑与 | and | 3 | | 逻辑或 | or | 2 | ### 4.python流程控制语句 ###### 条件控制 > ```python > if 条件: > 处理 > elif 条件2: > 处理 > else: > 处理 > ``` > > 三元表达式: 条件为真的结果 if 条件判断 else 条件为假的结果 > > ```python > a=1 b=2 a if a>b else b # a = a > b?a:b > > c=a if a>b else b # c = a > b?a:b > ``` ###### for循环 > ```python > for variable in sequence: > do something > else: > do something > ``` > > 举例: > > ```python > result=0 > for i in range(101): > result+=i > else: > print('i的值大于100') > print('最后的结果是:%d'%(result)) > ``` > > 方法介绍: > > >
range[xx]
: 生成序列(最后一位不包含xx) : `for i in range(101):` > > > >
end=""
: 不换行 > > > > ``` > > print('12',end='') > > print('13') > > ``` > > 多层嵌套: > > ```python > for i in range(101): > for j in range(2): > xxx > xxx > ``` ###### while循环 > ```python > while condition: # 开发中避免生成死循环(while True:xx) > do something > ``` > > 举例: > > ```python > i=1 > result=0 > while i<=100: > result+=i > i+=1 > else: > print("条件不满足") > print("最后的结果:%d" %result) > ``` ###### python中替代switch 方式一: 字典的方式 ```python def A(): xx; def B(): xx def default(): xx switch = {'A': case1,'B': case2} choice = 'A' # 获取选择 switch.get(choice, default)() # 执行对应的函数,如果没有就执行默认的函数 ``` 方式二: lambda表达式 ```python result = { 'A': lambda x: x * 5, 'B': lambda x: x + 7 }[value](x) ``` ###### break(跳出)与continute(继续) > break跳出循环(只是最近的循环,外侧的不会跳出),此层的for循环会跳出,不在执行 > > continute继续,在for循环中满足此条件的不在执行,接着相信执行 > > ```python > for i in range(2): > for j in range(5): > if j==2: > break > else > print(j) #当j==2时会跳出j层的循环,但是不会跳出i层的循环 > > for i in range(6): > if i==5: > break > xxx #当i==5时,不执行xxx,其他的还是继续执行xxx > ``` ### 5.python的数据结构 ###### 列表(list) > 一种数据构成的有效序列(有序,成员可重复出现),一定的线性序列排列而成的数据项集合,适合对元素查询,插入和删除. > > 方法介绍: > > 创建list: ` a=[1,2,4] a=[] a=list()` > > 添加元素: `i.append(5)` ==>i=[1,2,4,5] > > 删除元素:` del i[1] ` ==> i=[1,4] > > 获取长度 `len(i)` ==>3 > > 获取某个下标的元素 `i[1] `==>2 ` i[-1]` ==>4 > > 获取某个元素对应的下标:` i.index(2)` ==>1 ==>元素不存在会报错 > > 将某个元素插入到某个下标下:` i.insert(1,6) `==>[1,6,2,4] > > 拿出某个下标元素,使其元列表减少此元素: pop =`i.pop(2) `=4 i=[1,2] ###### 集合(set) > 创建set: `a= {1,2,3} 或者 s= set(), 不能设置为: a ={}, 此处a为字典dict了` > > 添加元素:` s.add(1)` > > 添加集合(相同元素不再添加):`s.update([1,2,3])` > > 移除某个元素(不存在报错): `s.remove(2)` > > 移除某个元素(不存在不报错): `s.discard(6)` > > 随机取出一个元素并删除:` s.pop()` > > 获取集合长度:`len(s)` > > 清空集合: `s.clear()` > > 两集合取并集:` s.union(d)` > > ```python > s =set() > s.add(2) # {2} > s.update({2,4,5}) > s.update([2,4,5]) #{2,4,5} > s.remove(2) #{4,5} > s.discard(6) #{4,5} > a=a.pop() #返回一个随机元素,并将s中此元素删除 > d={4,7,9} > s.union(d) #{4,5,7,9} > ``` ###### 元组(tuple) 形式: `()或者 tuple()` > 注意:当元组中只有一个元素时,要加`,`来区分:` s=(1,)` > > 元组的整个内容`不能新增,修改,删除`等变动操作,`可以去取`元素:s[xx] 或者 s[x:xx] > > 当元组中的是列表或者集合,可以修改对应的某个列表或者集合元素. > > ```python > s =(1,2,4,["111","222","333"]) > s[-1][1]="666" # s[-1] = ["111","222","333"] > print(s) ==>(1,2,4,["111","666","333"]) > ``` ###### 字典(dict) 形式:`s= {key:vaule,key2:vaule2} 或者 s={} 或者 s = dict()` > key是不能重复的,如果放入相同的key,后者会覆盖前者;字典中的key必须是不可变 > 添加元素: `s.update({key:vaule})` > > 删除字典中key对应的数据以及整个字典: `del s[key] ` `del s` > > 获取字典中key的值:` s[key]` > > 修改key的值:`s[key]=xxx` > > 获取字典的大小:`len(s)` > > > 注意: d={['2']:'we'} ==>错误,典中的key必须是不可变 ###### range类型 > range转list: ` a = range(5)` print(list(a)) ==>[0, 1, 2, 3, 4] > > `range(start,stop,step)` =>start开始值,stop结束值,step步长 > > ```python > a =range(1,10,2) print(list(a)) #[1, 3, 5, 7, 9] > a = range(1,-10,-3) print(list(a)) #[1, -2, -5, -8] > ``` ###### 可变与不可变 > 可变类型:列表,字典 > > 不可变类型:数字,字符串,元组 ### 6.python高级特性 ###### 切片 > 可切片的对象:`字符串,列表,元组`。集合与字典是不可切片 > > ```python > a=[1,2,3,4,5,6,7,8,9] > a[1:3] #[2, 3] > a[::5] #[1, 6] =>从下标为1的开始,每5个切片 > ``` ###### 列表生成式 > [expr for iter_var in iterable] > [expr for iter_var in iterable if cond_expr] > ```python > range_ =[x*2 for x in range(1,5)] #[2, 4, 6, 8] > ``` > > 说明:range(1,5)的数按照各自的2倍生成列表 > > ```python > range_ =[x for x in range(1,5) if x%2==0] #[2, 4] > ``` > > 说明:range(1,5)的数能被2整除的数生成列表 > > ```python > range_=[[x,y] for x in range(1,3) for y in range(6)] > #[[1, 0], [1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [2, 0], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5]] > ``` ###### 迭代 > 判断一个对象是否是可迭代,再进行迭代处理.同时要先引入依赖包 > > ```python > from collections.abc import Iterable > > a = "123" > print(isinstance(a, Iterable)) # Ture > for i in a: > print(i) > ``` > > > > 多个参数迭代: > > ```python > i = [[1, 2, 3], [2, 3, 4], [4, 5, 6]] > for x, y, z in i: > print("x+y+z=", x + y + z) > ``` > > ``` > x+y+z= 6 > x+y+z= 9 > x+y+z= 15 > ``` ###### 生成器(generator) > 生成器与生成式的区别在于最外层是(),是一种一边循环一边计算的机制,可以节约内存空间 > > ```python > generator = (x * 2 for x in range(1, 8)) > print(next(generator)) # 2 > print(next(generator)) #4 > for i in generator: > print(i) > ``` ### 7.python函数 > 形式: > > ```python > def 函数名(入参): > 业务逻辑 > return > ``` > > 举例: > > ```python > def circle_area(r): > result =3.14*r*2 > return result > ``` > > > > 定义一个空函数: > > ```python > def 函数名(入参): > pass > ``` > > 注意: `函数返回多个值时用逗号隔开,此时返回的类型是元组()` ##### 递归 > 递归说到底,就是自己调用自己。需要特别注意的点:当自己写递归函数时,首要步骤是要先写函数的最终结束条件. > > ```python > def factorial(n): > if n == 1: > return 1 > else: > return n * factorial(n-1) > ``` > > ### 8.python参数 形参: `def fn(a,b): xxx` 实参: `fn(2,3)` 位置参数 > 默认参数:`def fn(a,b=3): xx ` > > > 注意要在`最后一个`参数或者都有一个`默认值`,此时调用可以:fn(3)或者fn(3,4) > > > > 必需要的参数在前,默认参数在后,否则会报错 > > ```python > def test(a=1,b=2,c=3):xx # test(b=4) > ``` > > 注意: 编写默认参数时,默认参数必须`指向不可变的对象`: def t(l=[]):xx ==>这种是可变参数,存在问题 可变参数 > 形式: > > ```python > def fn(*numbers):xxx > ``` > > > 可变参数是在参数前加`*`,调用可传入多个参数,`使用逗号隔开`:fn(1,2) 命名关键字参数 > 形式: > > ```python > def persion(name,*,sex):xx > ``` > > > 命名关键字使用`*`做分隔,`*`之前的参数,基于位置参数,`*`后面的参数,在调用的时候必需指定其参数名. sex是命名关键字,调用要命名:persion("元",sex='男') 关键字参数 > 形式: > > ```python > def persion(name, **keys): > print('name:', name, 'other:', keys) > > > persion("swer", age=12, where="xx") # name: swer other: {'age': 12, 'where': 'xx'} > other_info = {"pet": "cat"} > persion("swer", **other_info) # name: swer other: {'pet': 'cat'} > ``` > > 改变的只是内部,将info拷贝一份用于调用,不影响外部的 > > > > 定义参数的顺序:`形参,默认,可变,命名关键字参数,关键字参数` > > 在关键字参数前必定是一个命名关键字参数,所以前面的命名关键字参数的*,可以去掉: > > ` def persion(name,sex="男",*num,pet_name,**info)` ### 9.python函数式编程 查询python函数用法: help(要查询的函数):eg: `help(filter)` ##### 高阶函数之lambda表达式 lambda表达式的使用场景: > 一般适用于创建一些临时性的,小巧的函数。使用 lambda 来创建会显得很简洁,尤其是在高阶函数的使用中 > lambda表达式: > > ```python > power = lambda x:x**2 > power = lambda x,n:x**n #两个入参 print(power(2,3)) = 8 > ``` > > 定义一个函数,传入一个list,将list每个元素的值加1: > > ```python > def add(l = []): > return [x +1 for x in l] > > print(add([1,2,3])) #[2, 3, 4] > ``` > > 值加2呢? 使用lambda > > ```python > def add(func, l=[]): > return [func(x) for x in l] > > print(add(lambda x: x + 2, [1, 2, 3])) > ``` ##### 高阶函数之map map的基本格式 ```python map(func, *iterables) #map(lambda表达式(或者方法),可变参数) ``` > map()函数接收两个以上的参数,开头一个是函数,剩下的是序列,将传入的函数依次作用到序列 > > 的每个元素,并把结果作为新的序列返回。也就是类似map(func,[1,2,3]) > > ```python > result =map(lambda x:x+1,[1,2,3]) > type(result) # map > list(result) #[2,3,4] > ``` > > 多个参数: 当参数个数不对应或者不一致时,以少的为准. > > ```python > result2 =map(lambda x,y:x+y,[1,2,3],[4,5,6]) > list(result2) #[5,7,9] > > result3=map(lambda x,y:x+y,[1,2,3],[4,5]) > list(result3) #[5,7] > ``` ##### 高阶函数之reduce累积 reduce函数的基本格式 > ```python > reduce(function, sequence, initial=None) #函数,序列,初始值) > ``` > > reduce把一个函数作用在一个序列上,这个函数必须接收两个参数,reduce函数把结果继续和序列的 > > 下一个元素做累积计算,跟递归有点类似,reduce函数会被上一个计算结果应用到本次计算中. > > `reduce(func, [1,2,3]) = func(func(1, 2), 3) ` > > > 先要引入包:`from functools import reduce ` > > ```python > result = reduce(lambda x,y:x*y,[1,2,3,4]) # 24=1*2*3*4 > result =reduce(lambda x,y:x*y,[1,2,3,4],2) # 48=2*1*2*3*4 > ``` ##### 高阶函数之filter过滤 filter函数的基本格式 > ```python > filter(function_or_None, iterable) > ``` > > `filter()`接收一个函数和一个序列。把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。 > > ```python > def my_fun(x): # 筛选出my_fun返回True的参数 > return x%2==0 > > result = filter(my_fun,[1,2,3,4,5]) > type(result) #
> list(result) # [2,4] > ``` > > ##### 高阶函数之sorted排序 sorted的基本格式 > ```python > sorted(iterable, key=None, reverse=False) > ``` > > > 说明: `iterable` -- 可迭代对象。 > > > > ` key `-- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指 定可迭代对象中的一个元素来进行排序。 > > > > `reverse` -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。 > > ```python > sorted([1,2,6,88,23,67,45]) #[1, 2, 6, 23, 45, 67, 88] > sorted([1, 2, 6, 88, 23, 67, 45], reverse=True) #[88, 67, 45, 23, 6, 2, 1] > ``` > >
对元组中某个下标数进行排序
> > ```python > data = [['python', 89], ['c', 45], ['java', 120], ['javascript', 67]] > data2 = sorted(data, key=lambda x: x[1]) #对第二元素排序(默认升序) > ``` > > ##### 闭包-nonlocal > 在python中支持`函数中调用函数并返回里面的函数` > > ```python > def my_power(): > n = 2 > > def power(x): > return x ** n > > return power #注意:这里返回不要加(),eg:power() > n = 3 > print(my_power()(4)) # 16 闭包 > > n = 2 > def my_power(): > > def power(x): > return x ** n > > return power #注意:这里返回不要加(),eg:power() > n = 3 > print(my_power()(4)) # 64 非闭包 > ``` > > > my_power函数在返回的时候,将其引用的值n一同带回,n的值被新的函数所使用,这种情况我们称之为闭包。同时`在调用这个函数前设置n=2是不会在函数中使用此值的`。 > > > > 当`内层函数没有n值的时候,会使用外层最后的n设置的值`,这种的不是闭包 > > > > 使用my_power().__closure__方法会返回闭包带的环境变量的值,也就说明是闭包在函数中的函数是不能改变外层函数的值的,如果要改变,要使用`nonlocal`关键字 > > > > ```python > > def my_power(): > > n = 2 > > def power(x): > > nonlocal n > > n += 1 > > return x ** n > > return power > > print(my_power()(3)) > > ``` > > > > > > ##### 装饰器-@ > 使用`@`来处理: > > > 装饰器模式(Decorator Pattern)允许向一个现有的对象`添加新的功能`,同时又`不改变其结构`。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 > > > > 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。 > > 添加要装饰的功能方法: > > ```python > def change_func(func): # 装饰后的函数 > def test(): > print("交易前处理") > func() > print("交易后处理") > > return test > ``` > > 原函数添加@装饰: > > ```python > @change_func > def my_func(): > print("这是交易处理") > > my_func() > ``` ### 10.python之核心 ###### 工程结构包,模块等 > 包 > 模块 > 类 >方法 > > 包与目录的区别是在此目录下是否有`__init__.py`文件,有就是包 > > `.py`后缀的文件就称之为模块 ###### 命名空间-global/globals()/locals() > 命名空间是`变量到对象的映射集合`。一般都是通过`字典`来实现的。主要可以分为三类: > > 1. 每个函数都有着自己的命名空间,叫`局部命名空间`,它记录了函数的变量,包括函数的参数和局部定义的变量。 > 2. 每个模块拥有它自建的命名空间,叫`全局命名空间`,它记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。 > 3. 还有就是`内置命名空间`,`任何模块均可访问它`,它存放着内置的函数和异常。 > > 命名空间的查找顺序: `局部命名空间,全局命名空间,内置命名空间,最后都没有找到就会报NameError错` > > 当函数嵌套时的查找规则: > > > 先在当前 (嵌套的或 lambda) 函数的命名空间中搜索 > > > > 然后是在父函数的命名空间中搜索 > > > > 接着是模块命名空间中搜索 > > > > 最后在内置命名空间中搜索 > > ```python > def my_func(): > name = " wiggin " > > def func_son(): > name = "xdclass " > print(name) # xdclass > > func_son() > print(name) # wiggin > > my_func() > print(name) # msg > > ``` > > 命名空间的生命周期: > > > `内置命名空间`在 Python 解释器启动时创建,会一直保留,不被删除。 > > > > 模块的`全局命名空间`在模块定义被读入时创建,通常模块命名空间也会一直保存到解释器退出。 > > > > 当函数被调用时创建一个`局部命名空间`,当函数返回结果 或 抛出异常时,被删除。每一个递归调用的函数都拥有自己的命名空间 > > > > > **在python的函数中和全局同名的变量,如果你有修改变量的值就会变成局部变量,在修改之前对该变量的引用自然就会出现没定义这样的错误了,如果确定要引用全局变量,并且要对它修改,必须加上`global`关键字**。 > > ```python > a = 1 > > def my_func(str): > global a # 必须要定义a,否则要报 > if a == 1: > print(str) > print(a) # 1 > a = 24 > > my_func("file") > print(a) # 24 此时对a值进行了修改 > ``` > > 命名空间的访问: > > 1. 局部命名空间的访问: 使用 `locals() ` > > > locals 返回一个名字/值对的 `dictionary`。这个 dictionary 的键是字符串形式的变量名字, > > > > dictionary 的值是变量的实际值。 > > ```python > def my_func(): > a = 1 > b = 2 > print(locals()) > > my_func() # {'a': 1, 'b': 2} > ``` > > 2.全局命名空间的访问-通过`globals() ` > > ```python > a = 1 > b = 2 > print(globals()) > ``` > > ```json > { > '__name__': '__main__', > '__doc__': None, > '__package__': None, > '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000013D66AD6CD0>, > '__spec__': None, > '__annotations__': {}, > '__builtins__':
, > '__file__': 'E:\\py_workspace\\start_project\\sf.py', > '__cached__': None, > 'my_func':
, > 'a': 1, > 'b': 2 > } > ``` > > **locals 与 globals 之间的区别: ` locals 是只读的,但globals是可读写`的** > > ```python > def my_func(): > x = 123 > print(locals()) #{'x': 123} > locals()["x"] = 456 > print("x=", x) #x= 123 > > y = 123 > my_func() > globals()["y"] = 111 > print("y=", y) #y= 111 > ``` > > ###### 导入模块-import/as/from > 使用`import` 关键字进行模块的导入 > > ```python > import xxx > ``` > > 导入模块并重命名` as` > > ```python > import xxx as xd > ``` > > > 特别注意:当模块首次被导入时,会执行模块里面的代码 > > 使用xx(importlib)`模块进行模块`的导入: > > ```python > import importlib > module = importlib.import_module("xdclass_python_chapter12_class3") > ``` > > 导入一个包中的模块`from` > > ```python > from package import module > ``` > > `导入多层包中的模块` > > ```python > from x.xx import module > ``` > > **要一次性导入包中所有的模块,可以使用通配符`*`。但是要配合`__init__.py`** ###### 导入变量 > 样式:`from 模块名字 import 变量名字 as 本模块命名此变量名` > > 导入一个变量: > > ```python > from class3 import a > ``` > > 导入多个变量: > > ```python > from class3 import a, b > ``` > > 导入的变量非常多,可以使用`*` > > ```python > from class3 import * > ``` ###### 导包机制 > 对` from class5_import import a`: > > 1. 在`sys.modules`中查找符号"class5_import" > > 2. 如果符号存在,则获得符号`class5_import`对应的`module`对象`
` > > - 从`
`的**dict**中获得符号"a"对应的对象,如果"a"不存在,则抛出异常 > > 3. 如果符号class5_import不存在,则创建一个新的`module`对象
,注意,这时,module对象的**dict**为空 > > 4. 执行class5_import.py中的表达式,填充
的**dict** > 5. 从
的**dict**中获得"a"对应的对象,如果"a"不存在,则抛出异常 ###### __ init __.py的作用及用法 > `__init__.py` 文件是模块的入口它告诉使用者那些功能会被导出和使用。 > > 作用: > > > 1. 标志所在目录是一个模块包,本身也是一模块 > > 2. 可用于定义模糊导入的时候要导入的内容 > > 3. 导入包的时候,会执行__init__.py里的内容 > > 4. 可用于批量导入模块 > > 举例: > > 在yuan目录下存在:`__init__.py,bread.py,coffee.py`文件 > > `bread.py`: > > ```python > def get_bread(): > print('A bread.') > def test(): > print('TEST') > ``` > > `coffee.py`: > > ```python > def get_coffee(): > print('A cup of coffee.') > > def test2(): > print('TEST2') > ``` > > 如果配置`__init__.py`为: > > ```python > from .bread import * > from .coffee import * > ``` > > 在其他模块可调用: > > ```python > import yuan > > yuan.test() #TEST > ``` > > 如果配置`__init__.py`为: > > ```python > from .bread import get_bread > from .coffee import get_coffee > ``` > > 在其他模块可调用: > > ```python > import yuan > yuan.get_bread() #A bread. 无法调用test() > ``` > > `__ all__`用法:某些模块`高频使用`场景 > > 如果配置`__init__.py`为: > > ```python > __all__ =['bread'] > ``` > > 在其他模块可调用: > > ```python > from yuan import * > > bread.get_bread() # coffee未导入,此处无法调用coffee.get_coffee() > ``` > > ###### __ all__ ,__ name__的作用及用法 > `__all__`是list结构,放在ini里,可以标志模糊导入时的模块。放在普通的模块下。标志一个模块中,允许那些属性被导入到其他模块. > > 同一目录下的两个模块:`model1.py, model2.py` > > ` model1.py` > > ``` > __all__ = ['getName'] > > def getName(): > print('name') > > def getSex(): > print('sex') > ``` > > `model2.py`直接调用`model1`中的方法: > > ```python > from model1 import * > getName() #getSex没有加入__all__中,所以只能调用getName() > ``` > > `__name__`的作用及其用法 > > > 1. `__name__`这个系统变量显示了`当前模块执行过程中的名称`,如果当前程序运行在这个模块中,`__name__` 的名称就是`__main__`如果不是,则为这个模块的名称。 > > > > 2. `__main__`一般作为函数的入口,类似于C语言,尤其在大型工程中,常常有`if __name__ =="__main__`": 来表明整个工程开始运行的入口 > > 定义模块 `test.py` > > ```python > def my_fun(): > if __name__=="__main__": > print("this is main") ##此方法在本模块中执行结果为这个:__name__ = __main__ > else: > print(__name__) #此方法在其他模块中执行结果为: __name__ = test > ``` > > `单元测试`会经常使用`__name__ ` ### 11.python的错误处理 ###### 异常捕获与处理 > `错误SyntaxError` :还没运行,在语法解析的时候,就发现语法存在问题。 > > `异常ZeroDivisionError`:运行的时候,会发生错误 > > `警告DeprecationWarning`: > > ```python > import warnings > > def fxn(): > warnings.warn("deprecated", DeprecationWarning) > ``` > > 异常的处理形式: > > ```python > try: > 做想做的事 > except 可能发生的异常: > except 可能发生的异常2: > finally: > ``` > > 举例: > > ```python > try: > print(10 / 0) > except ZeroDivisionError: > print("除数不能为0") > raise #抛出异常 > finally: > print("finally结果") > ``` > > 还有一种异常处理:python提供的语法,叫预处理,预定义清理, 来避免因为异常而导致程序奔溃,比如在进行IO操作的时候,可以使用。一旦运行时发生异常,程序会自动帮你关闭文件,避免整个程序奔溃 > > ```python > with open("myfile.txt") as f: > for line in f: > print(line,end="") > ``` > > ###### 异常的抛出及自定义异常 ```python class MyException(Exception): def __init__(self,parameter): err="非法入参{0},分母不能为0",format(parameter) Exception.__init__(self,err) self.parameter=parameter def my_func(x): if x==0: raise MyException(x) else: print(10/x) my_func(0) ``` ###### debug分析问题 > 第一步从日志中最下面分析异常跟java的debug一样,不同与快捷键:`F7是下一步` > 设置断点 在行号后单击(双击取消) > ` F8 跳过` > `Alt + Shift + F9 运行debug模式 ` > 参考资料:cnblogs.com/lijunjiang2015/p/7689822.html ###### 单元测试 > 单元测试(Unit Testing):又称模块测试,是针对程序模块来进行正确性检查的测试工作 > > 编写测试类: > > 先进入要测试的方法中:双击要测试的方法 ->右键 Go TO到Test(或者ctrl+shift+t) ->create new test > > 要测试的方法: > > ```python > class MyTest: > def my_func(x): > return 10/x > ``` > > 测试类: > > ```python > import unittest > from unittest import TestCase > from Test01 import MyTest > > class TestMy_func(TestCase): > def my_func(self): > test = MyTest() > self.assertEqual(test.my_func(2),5) #10/2=5 所以返回的是OK > > if __name__=='__main__': > unittest.main() > ``` > > ### 12.IO操作 ###### 输入输出流 ```python print("请输入内容,按回车健结束:") str =input() print("你输入的内容是:",str) ``` ###### 文件读取open > 形式: > > ```python > open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None,closefd=True, opener=None) > ``` > > 参数说明: > > > 1. `x ` 写模式,新建一个文件,二u给文件已存在会报错 > > 2. `b ` 二进制模式 > > 3. `+` 打开一个文件进行跟新(可读可写) > > 4. `r ` 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 > > 5. `rb ` 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等 > > 6. `r+` 打开一个文件用于读写。文件指针将会放在文件的开头。 > > 7. `rb+` 以二进制格式打开文件用于读写。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等 > > 8. `w` 打开一个文件只用于写入。如果该文件已存在则打开文件,并从头开始编辑,即原有内容会被删除。如果文件不存在则创建文件。 > > 9. `wb` 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件.并从头开始编辑,即原有内容会被删除。如果文件不存在则创建文件。一般用于非文本如图片等 > > 10. `w+` 打开一个文件用于读写。如果该文件已存在则打开文件.并从头开始编辑,即原有内容会被删除。如果文件不存在则创建文件。 > > 11. `wb+` 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件.并从头开始编辑,即原有内容会被删除。如果文件不存在则创建文件。一般用于非文本如图片等 > > 12. `a` 打开一个文件用于追加。如果该文件已存在,文件指针将会放到文件结尾。也就是说,新的内容会写在原有内容之后。 如果文件不存在,创建文件用于读写入 > > 13. `ab+` 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放到文件结尾。 如果文件不存在,创建文件用于读写入 > > 写法一: > > ```python > try: > file_path="C:\\Users\\DELL\\Desktop\\python\\python笔记.md" > file =open(file_path,"r",encoding="utf-8") > #content =file.readline() 读取第一行 > #content = file.read() 一次性读取所有 > content = file.readlines() 每行数据放入list中返回 > print(content) > finally: > file.close() > > ``` > > **写法二**: > > ```python > file_path="C:\\Users\\DELL\\Desktop\\python\\python笔记.md" > with open(file_path,"r",encoding="utf-8") as file: > #content =file.readline() > #content = file.read() > content = file.readlines() > print(content) > ``` ###### 文件写入write > 写入文件内容时,需要些使用open打开文件,再使用write写入: > > 1. `w - 写入`,每次写入都会覆盖前面的 > 2. `a - 追加`(示append) ,保留前面的 > > ```python > file_path = "D:\we.txt" > with open(file_path, "w", encoding="utf-8") as file: > file.write('好好学习') > ``` ###### 文件夹操作 > 创建文件夹: 以使用`os.mkdir(dir_name)`来在当`前目录下创建一个目录` > > ```python > import os > os.mkdir("test") #当前目录下创建test文件夹 > ``` > > 创建`多级`文件夹`os.makedirs` > > ```python > import os > os.makedirs("test\\my") #当前目录下创建test/my多层文件夹 == >相对路径 > os.makedirs("D:\\wer\\yrt") #D盘下创建wer/yrt多次文件夹 == >绝对路径 > ``` > > 获取当前所在目录`os.getcwd` > > ```python > import os > print(os.getcwd()) #E:\py_workspace\model #只获取到了文件所在的文件夹路径 > ``` > > 改变当前的工作目录`chdir`: 进入子目录 > > ```python > import os > os.chdir("test") #进入当前目录下中的test目录 > print(os.getcwd()) #E:\py_workspace\model\test > ``` > > 删除空文件夹`os.rmdir` > > ```python > import os > os.rmdir("test") > ``` > > 删除多层空文件夹`os.removedirs` > > ```python > import os > os.removedirs("test\\my") > ``` > > 判断一个路径是否是文件夹`os.path.isdir(dir)` > > ```python > import os > os.path.isdir("test\\my") # False > ``` > > 获取一个路径下所有的文件和目录名`os.listdir(path)` > > ```python > import os > print(os.listdir("test")) #['we'] > ``` > > `删除`文件夹下`所有子文件夹: shutil.rmtree`: > > ```python > import shutil > shutil.rmtree("D:\cache") > ``` > > ###### StringIO与BytesIO > **使用场景** > > 在某些场景下,我们`只是要缓存`相应的文本内容,方便后续处理,此时,我并`不需要往新建文件并写入`,我 > > 只想直接在内存中缓存这些文本。 > > `StringIO`跟`ByteIo`的区别在于前者写入`字符串`,后者写入`二进制` > > `赋值StringIO,读取readline` > > ```python > from io import StringIO > > str_io = StringIO("hello world") > print(str_io.readline()) > str_io.close() > ``` > > `写入write,读取getvalue` > > ```python > from io import StringIO > > str_io = StringIO() > str_io.write("hello") > str_io.write("world") > print(str_io.getvalue()) > str_io.close() > ``` > > 可使用`with语法自动关闭`: > > ```python > from io import StringIO > > with StringIO() as str_io: > str_io.write("hello") > str_io.write("world") > print(str_io.getvalue()) > ``` > > ### 13.面向对象编程 ##### 面向对象及其三大特性 > 并不是我们要说的面向对象,在这里,没有对象也可以进行面向对象编程 > > 面向对象的三大特性分别为`封装、继承和多态` > > 多态:python中的多态,本质也是通过继承获得多态的能力。(**不同的** 子类对象调用 **相同的** 父类 > > 方法,产生 **不同的** 执行结果,可以增加代码的外部 **调用灵活度**) ##### 类的定义class及实例化 > 类中`所有类方法`,无论是否要用到,都`必须有self`参数 > > 定义类`class`: > > ```python > # 定义person类 > class Person(): > > # 所有类方法,无论是否要用到,都必须有self参数 > def method_self(self): > print("method_self") > ``` > > 实例化: 使用`类名()`,即可完成实例化 > > ```python > persion = Person(); > ``` > > > 注意:定义类的时候,类名需使用`驼峰`的命名方式(即单词`首字母大写`,如果类名由多个单词组成,同样每个单词的首字母都大写) > > 实例化多个对象 它们之间是不相等的,因为他们的id不同: > > ```python > p1 = Person(); > p2 = Person(); > # 通过id函数证明实例化出来的两个对象都是不同的 > print(id(p1)) > print(id(p2)) > ``` ##### 类的构造函数`def __init__()` > 主要用来在创建对象的时候去初始化对象。 > > **python中不支持多个构造函数** > > > > ```python > class Person(): > #自定义构造函数 > def __init__(self, name, age): > self.name = name > self.age = age > > def print(self): > print('name = %s, age = %s' % (self.name, self.age)) > > p1 = Person('张三', '35'); > p1.print() > ``` > > > 当`使用了构造函数`,且构造函数式带参的且无默认参数,此时,实例化对象的时候,`必须显式入参`,否则会报错。若要避免错误,可以在构造函数使用默认参数 ##### 类变量与实例变量`self.__class__/__dict__` > 类变量(属于类的): 在类中且在函数体之外。类变量通常不作为实例变量使用。类变量在整个实例化的对象中是公用的。 > > 实例变量(属于实例化之后的变量的):定义在方法中的变量,用 self 绑定到实例上,只作用于当前实例的类 > > `定义及访问`: > > 访问`实例变量`可以使用`对象名.属性`,访问`类变量`可以使用`类名.属性` , 类似与java中的静态变量,但是它可变 > > ```python > class Person(): > num = 0 > def __init__(self, name, age): > self.name = name > self.age = age > > p1 = Person('张三', '35'); > # 访问实例变量 > print(p1.name) > # #访问类变量 > print(Person.num) > ``` > > `修改实例变量与类变量的值` > > > 1. 如果要修改实例变量的值,可以使用`对象名.属性=新值`的方式进行赋值 > > > > 2. 如果要修改类变量的值,可以使用`类名.属性=新值`的方式进行赋值,在实例方法里,可以使用`self.__class__ ` > > ```python > p1.name = '里斯' > Person.num = 24 > ``` > > ```python > class Person(): > num = 0 > def __init__(self, name, age): > self.__class__.num = 23 #实例方法中修改类变量 > self.name = name > self.age = age > ``` > > `实例变量查找规则`: > > > 先从实例变量里面找,找不到,看看类变量有没有,没有的话,去父类找,还是找不到报错在对象里面,有一个`__dict__`对象,存储着`对象相关的属性`。 类也有对应的`__dict__`,存储着与`类相关的信息` > > ```python > print(p1.__dict__) #{'name': '里斯', 'age': '35'} > print(Person.__dict__) # {'__module__': '__main__', 'num': 23, '__init__':
, '__dict__':
, '__weakref__':
, '__doc__': None} > ``` ##### self关键字 > 作用: `self`指向实例本身,我们在实例方法中要访问实例变量,必须使用`self.变量名`的形式。 > > `self`名称不是必须的,在python中`self不是关键词`,你`可以定义成a或b或其它名字`都可以,但是约定成俗(为了和其他编程语言统一,减少理解难度) > > ```python > def __init__(aa,name): > aa.name = name > ``` > > 在实例方法中,如果不使用`self.属性名`的方式去访问对应的属性会`报错` > > 如果直接使用`类名.实例方法名`也会`报错` > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, na): > self.name = na > print(name) # 编译时就报错 > > def print(self): > print('name = %s' % self.name) > > > p1 = Person('张三', '35'); > print(Person.print()) # 执行时报错 > ``` ##### 类方法@classmethod与静态方法@staticmethod > **类方法**: 使用装饰器`@classmethod`。`第一个参数`必须是当`前类对象`,该参数名一般约定为`“cls`”(不是cls也没关系,但是,约定俗成的东西不建议变动),通过它来传递类的属性和方法(不能传实例的属性和方法);其`调用对象`可以是`实例对象和类` > > **虽然`能对象能访问类方法`,但是`不建议`这么用** > > ```python > class Person(): > num = 0 > > @classmethod > def change_num(cls, change): > cls.num = change > print(cls.num) > Person.change_num(34) # 通常使用方式 > p1 = Person(); > p1.change_num(23) #不建议这样使用 > ``` > > **静态方法**:使用装饰器`@staticmethod`。`参数随意`,没有“self”和“cls”参数,但是`方法体中不能使用类或实例的任何属性和方法`; > > 静态方法是类中的函数,`不需要实例`。静态方法主要是`用来存放逻辑性的代码`,逻辑上属于类,但是和类本身没有关系,也就是说在静态方法中,不会涉及到类中的属性和方法的操作。可以理解为,静态方法是个**独立的、单纯的**函数,它仅仅托管于某个类的名称空间中,便于使用和维护 > > ```python > @staticmethod > def print_hello(): > print("hello world") > ``` > > ##### 访问限制(属性字段前加__定义为私有变量) > **定义私有变量** :当我们不希望外部可以随意更改类内部的数据,可以`将变量定义为私有变量`,并提供相应的操作方法为了保证外部不可以随意更改实例内部的数据,可以在构造函数中,`在属性的名称前加上两个下划线__`,这样改属性就变成了一个私有变量,`只有内部可以访问,外部不能访问` > > **方法私有化,同样也是在方法名前面加上__ ** > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, name): > self.__name = name > > def __change(self, name): > self.__name = name > > > person = Person("xx") > print(person.name) #运行报错,name为私有变量,外部不可访问 > person.__change('we') # 运行报错,change为私有方法,外部不可访问 > ``` ##### 打破访问限制(`__xx__/_类_属性/方法`) > 在python中,仅属性或方法`前面`加上`__`时,表示私有,如果`后面`再加上`__`,此时含义就发生改 > > 变,变成了`普通`的属性或方法。 > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, name): > self.__name__ = name > > def __change__(self, name): > self.__name = name > > > person = Person("xx") > print(person.__name__) # xx > person.__change__('we') # 此时name变为了we > ``` > > 通过对象的`__dict__`来查看上面的访问限制中的例子: > > 发现多出了`_类_属性/方法`,因此可以根据这种方式来访问类的私有属性。 > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, name): > self.__name = name > > def __change(self, name): > self.__name = name > > > person = Person("xx") > print(person.__dict__) # {'_Person__name': 'xx'} > print(Person.__dict__) # { '_Person__change': ...} > # 打破访问限制 > print(person._Person__name) # xx > # 打破访问限制 > person._Person__change('we') > print(person._Person__name) # we > ``` > > ### 14.面向对象高级特性 ##### 继承(`子类(父类)`) > 在定义类的时候,`类名后有个括号`,当括号里`写着另外一个类`的名字时,表示该类继承于另外一个类 > > 1. 通过继承,调用子类方法 > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, name): > self.name = name > > def change(self, name): > self.name = name > > # People继承 > class People(Person): > pass > > p = People('人类') > print(p.name) # 人类 > p.change('f') > print(p.name) # f > ``` > > 2. 子类可以有`自己的属性与方法` > > ```python > class People(Person): > def work(self): > print('work') > > p = People('人类') > print(p.work()) > ``` > > 3. `子类具备父类所有的属性与功能`,但是父类并不具备子类的属性与功能 > > 4. 当子类`有自己的构造方法`时,将会`覆盖父类的构造方法` > > ```python > # People继承 > class People(Person): > def __init__(self): > print('People') > > p = People() #People > ``` > > 5. **子类重写父类方法** > > > 特别注意: > > > > 1. 当且仅当`子类方法与父类同名`,`入参相同`,才可称之为`重写父类`的方法 > > > > 2. 不要为了获得某些属性或功能而继承 > > ```python > class Person(): > # 自定义构造函数 > def __init__(self, name): > self.name = name > def change(self, name): > self.name = name > > # People继承 > class People(Person): > def __init__(self): > print('People') > def change(self, name): # 重写 > print('name is %s' % name) > > p = People() #People > p.change('qq') # name is qq > ``` > > ##### super作用及用法 > 子类自己写了`init方法`,程序运行的时候就`不会去调用父类的构造` > > 当子类不创建(或者没有)父类中的属性时,此时通过`子类.父类属性`会报错。怎样处理? > > 方式一:`直接通过类名去调用`,但是这种方式通常`不建议` > > ```python > class People(Person): > def __init__(self, name): > Person.__init__(self, name) > > p = People('wangwu') > print(p.name) > ``` > > 方式二: `通过super去进行调用` > > ```python > class People(Person): > def __init__(self, name): > super(People, self).__init__(name) > > p = People('wangwu') > print(p.name) > ``` > > > **super()** 函数是用于`调用父类`(超类)的一个方法。一般是用来`解决多重继承问题`的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果`使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承`)等种种问题。 > > super函数的基本语法 > > ```python > super(类名,self) > ``` > > 在python3中,`可以直接使用super()而无需任何参数来调用父类` ##### 抽象方法(abc/@abstractmethod/ABCMeta )与多态 >`抽象方法`指一些`只有方法声明`,而没有具体方法体的方法。抽象方法一般存在于`抽象类或接口`中。`抽象类`的一个特点是它不能直接被实例化,`子类`要么是`抽象类`,要么,必须`实现父类抽象类里定义的抽象方法` > >抽象类的`子类必须实现抽象类`中所定义的`所有方法`,否则,程序不能正确运行 > >> **在python3中可以通过使用`abc模块`轻松的定义抽象类** > >```python >from abc import ABCMeta, abstractmethod > ># 定义抽象类时,使用metaclass=ABCMeta >class Person(metaclass=ABCMeta): > @abstractmethod > def do(self): > pass > ># 子类实现抽象父类方法 >class P(Person): > def do(self): > print('do something') > >p = P() >p.do() # do something >``` > > > >**多态**: **不同的** 子类对象调用 **相同的** 父类方法,产生 **不同的** 执行结果,可以增加代码的外部 **调用灵活度** > >**多态的好处**: 增加了程序的`灵活性`;增加了程序额`可扩展性` > >```python ># 定义animal类 >from abc import ABCMeta, abstractmethod > > ># 定义抽象类时,使用metaclass=ABCMeta >class Animal(metaclass=ABCMeta): > @abstractmethod > def eat(self): > pass > @abstractmethod > def run(seft): > pass > def activity(self): > self.eat() > self.run() > >class Dog(Animal): > def eat(self): > print("Dog is eating") > def run(self): > print("dog is running") > >class Cat(Animal): > def eat(self): > print("cat is eating") > def run(self): > print("cat is running") > ># 不同的子类对象,调用父类的activity方法,产生不同的执行结果 >dog = Dog() >cat = Cat() >dog.activity() >cat.activity() >``` > > ##### 多重继承 > 如果使用多继承来表达,肯定也是同时继承两个类 > > 表达式 :`子类(父类1,父类2)` > > **当继承多个父类时,如果父类中`有相同的方法`,那么子类会`优先使用最先被继承的方法`** > > ```python > class Person(): > def A(self): > print('A') > > def C(self): > print('Person- C') > > class Man(): > def B(self): > print('B') > > def C(self): > print('Man-C') > > class People(Person,Man): > pass > > p = People() > p.A() > p.B() > p.C() # Person- C Person在前,优先继承 > ``` > > ##### 多重继承问题(菱形继承(`super().__init__() `)、查找的优先级) > 新式类与旧式类 > > > 1. 新式类都从object继承(python3中,默认都继承自object),经典类不需要。 > > > > 2. 新式类的MRO(method resolution order 基类搜索顺序)算法采用`C3算法`广度优先搜索,而旧式类的`MRO算法`是采用深度优先搜索 > > > > 3. 新式类相同父类只执行一次构造函数,经典类重复执行多次。 > > 菱形继承(钻石继承) > > 要执行父类构造有两种方式,一种是直接`使用父类名字调用构造`,一种是使用`super()`, > > ```python > class A(): > def __init__(self): > print('A') > > > class B1(A): > def __init__(self): > A.__init__(self) > > > class B2(A): > def __init__(self): > A.__init__(self) > > > class C(B1, B2): > def __init__(self): > B1.__init__(self) # A > B2.__init__(self) # A > c = C() > ``` > > **解决菱形继承`多次调用构造`的问题** : 使用`super()` > > ```python > class A(): > def __init__(self): > print('A') > > > class B1(A): > def __init__(self): > super().__init__() > > > class B2(A): > def __init__(self): > super().__init__() > > > class C(B1, B2): > def __init__(self): > super().__init__() # A > > c = C() > ``` > > ##### 枚举类Enum/name/value/@unique > 定义:在数学和计算机科学理论中,一个集的**枚举**是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数。这两种类型经常(但不总是)重叠 > > 创建枚举类: > > ```python > from enum import Enum, unique > > # 创建 Enum > class MyEn(Enum): > A = 1 > B = 2 > C = 3 > > # 使用 Enum > x = MyEn.B > if x == MyEn.A or x == MyEn.B: > print('into enum') > > print(MyEn.B.name) #B > print(MyEn.B.value) #2 > > print(MyEn(3)) #MyEn.C > ``` > > **通过名字获取枚举成员** ` MyEn.B` > > **通过枚举成员获取名字(`Cls.X.name`)以及值(`Cls.X.value`)**: `MyEn.B.name /MyEn.B.value` > > 通过值(`value`)获取枚举成员 : `Cls(value)` `MyEn(3)` > > 特性: > > 1. **定义枚举时,其枚举成员的名称(name)不允许相同** > > 2. **默认情况下,不同的成员值允许相同。但是两个相同值的成员,其第二个成员名称是第一个成员名称的别名;因此在访问枚举成员时,`只能获取第一个成员`。** > > 3. **如果要限定枚举里面所有的值必须唯一,可以在定义枚举类时,加上@unique** > > ```python > from enum import Enum, unique > class MyEn(Enum): > A = 1 > B = 1 > print(MyEn(1)) # MyEn.A > ``` > > ```python > from enum import Enum, unique > > @unique > class MyEn(Enum): > A = 1 > B = 1 > print(MyEn(1)) #加了@unique,表示枚举唯一,此时存在相同的值,不唯一,所以执行会报错 > ``` > > 4. **枚举成员的比较(`Cls.X.value == xx`)** > > > 注意:枚举的比较,只能是成员与成员,或者值与值,不能成员与值比较 > > ```python > from enum import Enum > > class MyEn(Enum): > A = 1 > B = 2 > > print(MyEn.A == 1) # False > print(MyEn.A.value == 1) # True > print(MyEn.A.value is 1) # True > ``` ### 15.网络编程 ##### socket > 套接字(socket)是一个抽象层,应用程序可以通过它发送或接收数据,可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将I/O插入到网络中,并与网络中的其他应用程序进行通信。网络套接字是IP地址与端口的组合. > > socket是一个接口,在用户进程与TCP/IP协议之间充当中间人,完成TCP/IP协议的书写,用户只需理解接口即可 > > 在python里面,提供了两个级别访问的网络服务: > > 1. 低级别的网络服务支持基本的 `Socket`,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法。 > 2. 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发。 > > 通信协议可分为TCP、UDP: > > 1. TCP(Transmission Control Protocol传输控制协议)是一种面向连接的,可靠的,基于字节流的传输通信协议。 > 2. UDP(User Data Protocol,用户数据报协议)是无连接的,即发送数据之前不需要建立连接,UDP尽最大努力交付,即不保证可靠交付(类似于发短信,我只管发,能不能接受到跟我关系不大) > > Google QUIC正式更名 HTTP/3 协议 https://cloud.tencent.com/developer/news/355488 ##### UDP实现通信 > 使用socket开发的基本格式: > > ```python > socket.socket(family,type,proto) > ``` > > 1. `family`: 套接字家族可以使`AF_UNIX`或者`AF_INET` > > 2. `type`: 套接字类型可以根据是面向连接(TCP)的还是非连接分(UDP)为` SOCK_STREAM` 或 `SOCK_DGRAM` > > 3. `protocol`: 一般不填默认为`0` > > 4. `AF_INET`: AF_UNIX需经过多个协议层的编解码,消耗系统cpu,并且数据传输需要经过网卡,受到网卡带宽的限制。AF_UNIX数据到达内核缓冲区后,由内核根据指定路径名找到接收方socket对应的内核缓冲区,直接将数据拷贝过去,不经过协议层编解码,节省系统cpu,并且不经过网卡,因此不受网卡带宽的限制。 > > 5. `AF_UNIX`: AF_UNIX的传输速率远远大于AF_INET > > 6. `AF_INET`不仅可以用作本机的跨进程通信,同样的可以用于不同机器之间的通信,其就是为了在不同机器之间进行网络互联传递数据而生。而AF_UNIX则只能用于本机内进程之间的通信。 > > 服务端: > > ```python > import socket > > server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) > server.bind(("127.0.0.1", 8888)) > print("UDP 服务端启动") > > # 开机之后一直等着我跟他通信 > while True: > # 接收到信息,信息里面包括客户端发送的内容以及客户端的信息(ip,端口) > data, client = server.recvfrom(1024) > print("接受到客户端发来的消息:", data.decode('utf-8')) > server.sendto("您好,这是服务端".encode("utf-8"), client) > ``` > > 客户端 > > ```python > import socket > > client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) > # 有服务端(ip,端口) > client.sendto("您好,我是客户端".encode('utf-8'), ("127.0.0.1", 8888)) > # 接受服务端的消息 > data, server = client.recvfrom(1024) > print(data.decode("utf-8")) > client.close() > > ``` ##### TCP实现通信 > 服务端 > > ```python > import socket > > server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > server.bind(("127.0.0.1", 9999)) > # 同一时刻 ,允许多少客户端跟我通信 > server.listen(5) > print("服务端已启动,等待客户端连接=======》") > client, address = server.accept() > print("客户端已经连接") > while True: > recv = client.recv(1024) > msg = recv.decode("utf-8") > if msg == "close": > print("服务端关闭=======》") > server.close() > break > print("客户端发送的内容:", msg) > print("请输入回复内容:") > client.send(input().encode("utf-8")) > ``` > > 客户端 > > ```python > import socket > > client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) > > # 拨打电话 > client.connect(("127.0.0.1", 9999)) > # 通话 > while True: > print("请输入内容:") > send_data = input() > client.send(send_data.encode("utf-8")) > if send_data == "close": > client.close() > print("关闭连接") > break > data = client.recv(1024).decode("utf-8") > print("接受到服务端响应:", data) > ``` > > ##### requests模块发送http请求 > 安装requests模块 > > ```python > import requests > > result = requests.get("xx") > text = result.content > print(text.decode('utf-8')) > ``` > > ### 16.多线程 ##### 线程与进程的区别 > 进程:是系统进行分配和管理资源的基本单位 > > 线程:进程的一个执行单元,是进程内调度的实体、是CPU调度和分派的基本单位,是比进程更小的独立运行的基本单位。线程也被称为轻量级进程,线程是程序执行的最小单位。 ##### Python中的多线程 > 在python3之前的版本,可以使用`thread、threading` 两个模块新建线程 > > 在python3中,可以可以使用`_thread、threading `两个模块新建线程。`thread` 模块`已被废弃`。为了兼容性,Python3 将 thread 重命名为 "`_thread`"。 > > `threading`是高级模块,对`_thread`进行了封装。所以在平常的开发中,`更加推荐使用threading模块` > > 1. 使用`_thread`模块创建线程 > > **基本语法**: > > ```python > _thread.start_new_thread(函数, 函数入参) > ``` > > ```python > import _thread > import time > > # 为线程定义一个函数 > def print_name(thread_name): > count = 0 > while count < 5: > time.sleep(1) > count += 1 > print(thread_name) > > > _thread.start_new_thread(print_name, ("Thread-1",)) > _thread.start_new_thread(print_name, ("Thread-2",)) > while 1: > pass > ``` > > 2. 使用`threading`创建线程 - 方式1 > > **基本语法**: > > ```python > threading.Thread(group=None, target=None, name=None, args=(), kwargs=None, *, daemon=None) > ``` > > > 参数说明: > > > > 1. `group`:在当前的版本保持为None,不要进行修改 > > 2. `target:` 这个线程要干的活(函数) > > 3. `name`: 线程名 > > 4. `args`: 上面target参数的入参(),tuple类型,对应taget参数中的可变参数 > > 5. kwargs:上面target参数的入参,dict类型,对应taget参数中的关键字参数 > > ```python > import threading > > def my_fun(): > print("Hello world") > > threading.Thread(target=my_fun).start() > ``` > > 3. 使用threading创建线程 (**直接通过继承**) > > ```python > import threading > > class MyThread(threading.Thread): > def run(self): > print("hello world") > > thread = MyThread() > thread.start() > ``` > > ##### 线程的状态及其转换 > NEW: `Thead.start()` => RANNABLE > > RANNABLE : 获取到相应的锁 => BLOCKED > > RANNABLE : 运行结束 => TERMINATED > > BLOCKED: 等待获取锁 => RANNABLE > > WAITING: 被唤醒 => RANNABLE > > TIME_WAITING: 时间到了被唤醒 => RANNABLE > > RANNABLE : `thearding.Event().waiit()`=> WAITING > > RANNABLE : `thearding.Event().waiit(3)` => TIME_WAITING ##### 线程安全性问题 > **线程安全性问题的三要素:** > > 1 多线程环境下 > > 2 共享变量 > > 3 并发对共享变量进行修改 > > **如何解决线程安全性问题?** > > 1 单线程化 > > 2 不要共享变量 > > 3 对共享变量的操作串行化 > > 使用到`锁threading.Lock()` > > ```python > import threading > > > class MyThread(threading.Thread): > sum = 0 > lock = threading.Lock() > > def run(self): > with MyThread.lock: > for i in range(1000000): > MyThread.sum += 1 > > > thread = MyThread() > thread2 = MyThread() > thread3 = MyThread() > thread.start() > thread2.start() > thread3.start() > thread.join() > thread2.join() > thread3.join() > print(MyThread.sum) > ``` > > ##### 多进程以及GIL机制 > 在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势。 > > 延伸阅读: python中的GIL详解: https://www.cnblogs.com/SuKiWX/p/8804974.html > > 既然同一时刻只有一个线程在运行,那为什么还会有线程安全性问题? > > 延伸阅读: https://segmentfault.com/q/1010000008235951 > > https://www.cnblogs.com/hwlong/p/8952510.html#_label5 > > > > 多进程使用`Multiprocessing` 模块,总体的使用跟多线程差不多 > > ```python > # 为线程定义一个函数 > import multiprocessing > import time > > def print_name(thread_name): > count = 0 > while count < 5: > time.sleep(1) > count += 1 > print(thread_name) > > if __name__ == "__main__": > process = multiprocessing.Process(target=print_name, args=("多进程",)) > process.start() > process.join() > ``` > > ### 17.正则表达式 ##### 正则表达式regexp-findall/match/search > 作用: 使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本 > > 特点: > > 1. 灵活性、逻辑性和功能性非常强 > > 2. 可以迅速地用极简单的方式达到字符串的复杂控制 > > 使用: `findall`方法, 需要导入`re`模块 > > ```python > re.findall(pattern, string, flags=0) > ``` > > 参数说明 > > 1. ` pattern`:匹配的正则表达式 > > 2. `string `:要匹配的字符串 > > 3. `flags` :标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等。 > > > ` flags`可选值: > > > > 1. `re.I` :使匹配对大小写不敏感 > > 2. `re.L` :做本地化识别(locale-aware)匹配 > > 3. `re.M` :多行匹配,影响` ^` 和` $` > > 4. `re.S` :使` . `匹配包括换行在内的所有字符 > > 5. `re.U` :根据Unicode字符集解析字符。这个标志影响` \w, \W, \b, \B`. > > 6. `re.X` :该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 > > ```python > import re > str = 'how old are you?' > result = re.findall('you',str) > print(result) # ['you'] ,当匹配不到时,返回 [] ,当匹配多个时,返回['xx','xx'...] > ``` > > `match`方法 > > > `re.match`尝试从字符串的`起始位置匹配`一个模式,如果不是起始位置匹配成功的话,`match()`就返回`none`。要获取匹配的结果,可以使用`group(n)`,匹配结果又多个的时候,n从0开始递增。当匹配结果有多个的时候,也可以使用`groups()`一次性获取所有匹配的结果 > > ```python > import re > > str = 'howh old are you?' > result = re.match('how', str) > print(result.group(0)) #how > ``` > > ` search`方法 > > > `re.search` 扫描`整个`字符串并返回`第一个`成功的匹配 > > ```python > import re > > str = 'how old are you?' > result = re.search('how', str) > print(result.group(0)) #how > ``` > > ##### 元字符 > 正则表达式语言由两种基本字符类型组成:原义(正常)文本字符和元字符。元字符使正则表达式具有处理能力。所谓元字符就是指那些`在正则表达式中具有特殊意义的专用字符`,可以用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式 > > 元字符参考 > > 1. `\d ` 匹配一个数字字符。等价于`[0-9]`。`grep` 要加上`-P`,`perl`正则支持 > > 2. `\D` 匹配一个非数字字符。等价于`[^0-9]`。grep要加上-P,perl正则支持 > > 3. `\f ` 匹配一个换页符。等价于`\x0c和\cL`。 > > 4. `\n ` 匹配一个换行符。等价于`\x0a和\cJ`。 > > 5. `\r ` 匹配一个回车符。等价于\x0d和\cM。 > > 6. `\s ` 匹配任何不可见字符,包括空格、制表符、换页符等等。等价于`[ \f\n\r\t\v]`。 > > 7. `\S` 匹配任何可见字符。等价于`[^ \f\n\r\t\v]`。 > > 8. `\t ` 匹配一个制表符。等价于\x09和\cI。 > > 9. `\v` 匹配一个垂直制表符。等价于\x0b和\cK。 > > 10. `\w ` 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。 > > 11. `\W ` 匹配任何非单词字符。等价于“`[^A-Za-z0-9_]`”。 > > 12. `\` 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“`\\n`”匹配`\n`。“\n”匹配换行符。序列“\”匹配“\”而“(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。 > > 13. `^` 匹配输入字行首。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。 > > .... > > ##### 匹配单一字符 > 匹配字符串中所有的数字 > > ```python > import re > > str = "hel0,234 5 6nme sd" > result = re.findall("\d", str) > print(result) #['0', '2', '3', '4', '5', '6'] > ``` > > 匹配字所有非数字(包括空格等字符) > > ```python > result = re.findall("\D", str) > #['h', 'e', 'l', ',', ' ', ' ', 'n', 'm', 'e', ' ', 's', 'd'] > ``` > > 正则匹配换页符 - `\f` > > 匹配换行符 - `\n` > > 匹配回车符 - `\r` ##### 重复出现数量匹配 ##### 匹配字符集 ##### 边界匹配 ##### 表达式之组 ##### 贪婪与非贪婪 > 贪婪就是想要的东西越多越好,非贪婪就是拿到自己想要的. > > Python里数量词`默认是贪婪`的,总是尝试匹配`尽可能多的字符` ,如果需要正则进行非贪婪的匹配,这个时候,就需要在正则表达式后面加个`问号?` ### 18.爬虫 ##### robots协议 >什么是robots协议 > >Robots协议是国际互联网界通行的道德规范,基于以下原则建立: > >1、搜索技术应服务于人类,同时尊重信息提供者的意愿,并维护其隐私权; > >2、网站有义务保护其使用者的个人信息和隐私不被侵犯。 > >robots协议的主要功能 > >> Robots协议用来告知搜索引擎哪些页面能被抓取,哪些页面不能被抓取;可以屏蔽一些网站中比较大的文件,如:图片,音乐,视频等,节省服务器带宽;可以屏蔽站点的一些死链接。方便搜索引擎抓取网站内容;设置网站地图连接,方便引导蜘蛛爬取页面。 > >robots协议的写法 > >较为常见的有: > >User-agent:指定对哪些爬虫生效 > >Disallow:指定要屏蔽的网址 > >https://blog.csdn.net/qq_40491569/article/details/83473703 ### 19.Python开发规范 https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/ ``` from pathlib import Path folder_path = Path('C:\\Users\\XC-YJS\\Desktop\\文档\\') file_list = folder_path.glob('*.xls*') lists = [] for i in file_list: file_name = i.name lists.append(file_name) print(i.parent) print(i.suffix) print(i.stem) print(lists) ```