Python(从零到亿)

目录

第一章、第一个程序 

        一、打印出hello world

        二、查看内置函数

第二章、变量和字符串和注释和简单的代码

一、变量

        ①、什么是变量

        ②、变量名的命名规则

        ③、如何去定义一个变量

二、字符串        

三、注释

四、讲讲input()和比较运算符

input()函数

 比较运算符

第三章、数字类型

数字类型

计算方法、

第四章、分支结构

if 语句

else 语句

elif语句

条件表达式

多层嵌套

第五章、循环结构

while循环

break语句 

continue语句 

循环结构的嵌套

for循环

可迭代对象有哪些?

for循环用法

for循环嵌套

第六章、列表

创建列表

列表切片

列表增加元素

列表删除元素

列表替换元素

列表查询元素

列表进行排序

列表拷贝

列表推导式

 小知识、

is语法

第七章、元组

第八章、字符串

大小写字母互换

        左中右对齐

 查找

替换

判断

 截取

拆分和拼接

格式化字符串

第九章、序列

序列

第十章、字典

创建一个列表

字典增加

字典删除

字典更改

字典查询

字典嵌套

字典推导式

第十一章、集合

创建集合     

拷贝集合

判断集合

集合添加元素 

集合删除元素

第十二章、函数(1)

介绍函数

创建和调用函数

函数返回值

形式参数

实际参数

位置参数

关键字参数

默认参数

可变参数

限制参数语法

混合使用

解包参数

第十二章、函数(2)

函数作用域

函数闭包

函数装饰器

匿名函数

函数生成器

第十二章、函数(3)

函数递归

函数文档、注释类型、内省

高阶函数

@wraps装饰器

第十三章、永久存储

open()方法

 with语句

文件对象的方法和含义

 路径处理

创建文件夹

删除操作

查找操作

pickle模块

第十四章、异常

何为异常

异常处理方法

1、tyr-except语句捕获并处理异常

2、try-except-else 这里else只有在try语句正常执行完毕后才会被执行 如果出现异常则不会执行

3、try-except-finally    这里finally不管有没有异常都会被执行出来 (通常用于最后关闭文件的收尾工作)

4、try和finally的组合    发生异常与否都会执行finally语句

5、异常的嵌套

6、raise语句

7、assert语句

内置异常大合集

第十五章、类和对象(面向对象)

创建类

继承类

多重继承

判断类

组合

构造函数

钻石继承

Mixin

多态

私有变量

魔法方法

运算魔法方法

属性访问类

索引切片迭代协议

代偿

字符串比较魔法方法和让魔法失效

__call__方法

字符串相关的魔法方法

property

类方法

静态方法(放在类里面的函数)

描述符

type()

第一种:

第二种:

元类

元类的应用

给所有的类添加一个属性

对类名的定义规范做限制

修改对象的属性值

限制类实例化时的传参方式

禁止一个类被实例化

抽象基类

第十六章、模块和包

创建模块

调用模块

导入模块

命名冲突

if __name__ == '__main__'

遏制from...import *的附加伤害

总结

与全世界的Pyhon程序员共享你的代码


第一章、第一个程序 

        一、打印出hello world

                        调用内置函数print()里面输入要打印的内容

print('hello world')

        二、查看内置函数

dir(__builtines__)

                         也可以查看内置文档

import this
print(dir(__builtins__))

第二章、变量和字符串和注释和简单的代码

一、变量

        ①、什么是变量

pyhon中的变量是一种用于存储值的名称,它允许程序在运行时引用和操作这些值。

变量在Python中扮演着非常重要的角色,它们是程序中的基本元素,用于存储各种类型的数据,如数字、字符串、列表、元组、字典等。

Python的变量不需要预先声明数据类型,可以直接赋值。这意味着在Python中创建变量的同时,也为该变量赋予了一个值。变量的数据类型可以随时改变,例如,同一个变量可以一会儿被赋值为字符串,一会儿被赋值为整数。

使用type(变量名)可以查看一个变量的类型

        ②、变量名的命名规则

首先我们都知道定义一个变量需要有一个变量名进行储存 比如说变量名是一个水杯那变量就是水

但是Python对水杯的款式也有要求:

1、不能以数字开头

2、变量名区分大小写

3、左边是变量名右边是变量

4、可以使用中文作为变量名来储存变量,但不推荐

5、变量名不可以使用内置函数 (如果硬要使用内置函数作为变量名那内置函数会失效)

6、变量名只取最后一次赋值的值

7、变量名可以用_作为开头 但他如果取了_作为开头通常有特殊含义

        ③、如何去定义一个变量

要想定义一个变量得先有一个变量名 假设变量名为name 变量为spider man我们就该这样去设置

name = 'spider man'
名字 = 'spider man'
_name = 'spider man'

二、字符串        

在Python中,字符串是以数字字母符号组成的一串字符

1.字符串需要两边用相同的引号包裹起来

'hello'
"hello"
'''hello'''
"""hello"""

2.在符号前面加一个\代表标识转义字符

print('hello \n im***')
这个时候打印出来的结果是:hello
                        im***
#但如果你要使\n(换行符)失效的话就可以在他前面多加一个\

print('hello \\n im***')
这时候打印出来的就是 hello im***

3.在字符串前面加一个r表示原始字符串

print(r'hello \n im***')
#这个时候因为在字符串前面写了个r会使得 \n 失效作为字符串来被打印出来

4.字符串末尾加上\表示继续写下一行

如果你要表示你还没写完你可以在这行的结尾加上\来表示还要继续写
print('hello\
im 111111111\
1111111111111')

6.如果用三引号也可以实现和上面相同(直到下一个三引号)

print('''hello
im 123172316238
12371872378912''')

7.字符串可以拼接 也可以被乘

print('hello'+'bitch')
返回hellobitch

a='hello'
b='bitch'
print(a+b)
返回hellobitch

print(a+b*3)
返回hellobitchbitchbitch

三、注释

在编写代码的过程中 注释特别重要 如果你加上了注释可以方便你以后回来看这些代码的时候更加一目了然

添加注释的方法:

1、在要添加注释的地方加上一个#后面就是注释的内容他不会被程序执行只供阅读代码的时候查看

print('hello')#我是注释 我不会被程序执行print('132')

2、也可以用三个引号来作为注释 单引号和双引号都可以

         注意:他和#的区别是他不可以出现在执行代码的后面

'''13212312312'''
"""123
1231
231
"""
print('hello')

四、讲讲input()和比较运算符

input()函数

input()函数 他以字符串的形式用来接收用户传递进来的东西 也就是你传进来的不管是什么他都会变成一串字符串 如果你想传递一个整数进来赋值给a的话也可以这么写

a=int(input('输入一个整数'))

当然也可以用eval()来进行一个去引号处理 如果你传递进来的是列表也可以这样赋值

eval()的作用就是将括号里面的东西两边的引号去掉一次 然后进行返回

a=eval(input('输入一个列表'))

 比较运算符

(<)判断左边是否小于右边

(<=)判断左边是否小于等于右边

(>)判断右边是否大于左边

(>=)判断右边是否大于等于左边

(==)判断作用两边是否相等

(!=)判断左右两边是否不相等

(is)判断两个东西的id是否相等

 (is not)判断两个对象的id是否不相等

如果是返回True 如果不是就会返回False

第三章、数字类型

在Python中一共有八种数据类型

数字类型

1、整数 也就是12、30、5这些数字都是整数类型

整数可以用int方法将字符串里的数字转化为整数 但如果字符串里的是浮点数就无法转换

int('123')
返回123

2、浮点数    1.23 、3.12 、2.0这些都是浮点数类型
    Python浮点数计算具有误差如    0.1+0.2
    Python中 0.3!=0.1+0.2  
    如果要精确计算浮点数需引入decimal模块

    float(x)    将x转化为一个浮点数 

x='150.165'  #这里定义一个字符串给x
float(x)
返回值为150.165

float(105)
返回值为105.0


-------------------python采用科学计数法 0.00005表示为5e-05 表示10的-5次方---------------------------

3、复数 3+2j这种类型为复数类型
    复数包含实部和虚部1+2j(1为实部   2j为虚部)
    x.real可以获得实部数值
    x.imag可以获得虚部数值

    complex(re.im)返回一个复数re为实部 im为虚部

a=complex(3,2j)
a.real
返回3.0
a.imag
返回2.0

4、布尔类型

bool(1)
返回True
bool(0)
返回False

bool(x)如果x为空结果返回False 反之为True
    0     0.0     0j     "0"        Decimal(0)都为False
    空的集合与序列也为False

计算方法、


    abs(x)    返回x的绝对值

abs(-100)
返回值为100


    公式为    x == ( x//y ) * y+( x%y )

    x//y        x除以y的结果(地板除)向下取整    9//2 = 4            -3//2 = -2
    x%y        x除以y的余数                        9%2 = 1            6%2  = 0

    divmod(x,y)    返回的结果为    一个元组(x//y,x%y)

    pow(x,y)返回x的y次方可传入第三个参数,第三个传入后将进行取余运算
    

补充、

    逻辑运算符 (已按顺序排分)not为三者中最高级

    or    左边或者右边一个为True 返回True
    and    左边和右边都为True,结果返回True
    not     结果为True返回False
        结果为False返回True

第四章、分支结构

每个分支结构判断的时候末尾都要加一个:

if 语句

Python非常注重缩减 缩减决定了从属关系

     判断一个条件 如果这个跳出成立就会执行其包含的语句或某个代码块

if 3<5:
    print('我在if里面')
print('我在if外面')

else 语句

判断一个条件

如果条件成立就执行其包含的某条语句或代码块

如果条件不成立就执行另外的某条语句或代码块

if 1>2:
    print('1不大于2')
else:
    print('1大于2')

elif语句

现在有两个语句

第一个语句:

score = int(input('请输入您的分数'))#用input接收用户传入的数据 用int将数据转化为整数
if 0 <= score < 60:
    print('D')
if 60 <= score < 80:
    print('C')
if 80 <= score < 90:
    print('B')
if 90 <= score < 100:
    print('A')
if score == 100:
    print('S')

第二个语句

score = int(input('请输入您的分数'))#用input接收用户传入的数据 用int将数据转化为整数
if 0 <= score < 60:
    print('D')
elif 60 <= score < 80:
    print('C')
elif 80 <= score < 90:
    print('B')
elif 90 <= score < 100:
    print('A')
elif score == 100:
    print('S')

他们两个的区别:

假设考了59分  在第一个语句59<60条件成立的时候会依次向下进行判断然后打印D

而在第二个语句的时候判断59 < 60 条件成立就会停止判断并且打印D

第三种是在前两种的基础上再加一个else用于判断用户输入的分数不在0~100直接的处理

score = int(input('请输入您的分数'))#用input接收用户传入的数据 用int将数据转化为整数
if 0 <= score < 60:
    print('D')
elif 60 <= score < 80:
    print('C')
elif 80 <= score < 90:
    print('B')
elif 90 <= score < 100:
    print('A')
elif score == 100:
    print('S')
else:
    print('请输入0~100直接的整数')

条件表达式

条件成立时执行的雨具 if 判断条件 else 条件不成立时执行的语句

示例:

age = int(input('输入您的年龄'))
print('抱歉您未满十八岁,无法访问') if age<=18 else print('欢迎来到我们网站')

从传统的语法结构变为条件表达式的优点是:简洁 并且 可以很容易将其放进一个语句的内部

a=3
b=5
#传统语法结构:
if a<b:        #当a<b的时候执行其内部语句
    small = a
else:          #如果条件不成立 就执行else里面的语句
    small = b
#条件表达式
small = a if a<b else small = b

用条件表达式优化上面的判断分数

score = int(input('请输入您的分数'))#用input接收用户传入的数据 用int将数据转化为整数

#在想表达要写多行语句才能使代码看起来更规范的时候 可以用'('进行开头等到写完的时候再进行')'封闭

exxe = ('D'if 0 <= score < 60 else
'C' if 60 <= score < 80 else
'B' if 80 <= score < 90 else
'A' if 90 <= score < 100 else
'S' if score == 100 else
'请输入0~100直接的整数')

print(exxe)#判断完成后打印出来判断结果

多层嵌套

可以无限套 但不建议

age = 18
sex = 'girl'
if age<18:
    print('您未满十八岁,无法进入')
else:
    if sex == 'girl':
        print('欢迎女士')
    else:
        print('抱歉,本店男生不得入内')

第五章、循环结构

分支结构能让你的程序根据不同条件去做不同的事情 

循环结构能够让你的程序不断的去左同一件事情

while循环

while循环就是通过条件来决定循环体内的内容是否重复的去执行

他的语法如下

while 条件:
        循环体内的语句

示例一:

study = 'yes'
while study = 'yes':    #判断今天是否学习了
    print('good')
    study = input('今天你学习了吗')

示例二:

i = 1#设置不断添加的值
sum = 0#设置总和
while i <= 1000000:
    sum += i #可以不用写sum = sum+1 这样写更简洁
    i += 1

 前面提到当条件成立的时候会执行循环下的代码 那当条件一直成立的时候 他就会不断的执行下去陷入死循环 (当然 这个时候也有破解的办法 就是Ctrl+c可以强制中断循环 或者手动关闭这个窗口也可以使循环结束)

while True:
    print('hello')

break语句 

break语句如果再循环体内以条件的方法出现就可以退出循环

while True:
    s = input('请问我可以退出循环了吗(yes or no)?:')
    if s == 'yes':
        break    #如果s的值为yes的话就调用break语句跳出循环否则将会一直循环下去

continue语句 

continue语句表示跳出循环体,但只会跳出本轮循环,他还会回到循环体内的判断位置然后进行下一次判断

i = 0         #初始化i = 0
while i < 10: #当i小于10时 调用循环体内的语句
    i += 1
    if i%2 == 0:#当i整除2等于0的时候代表他是偶数 跳出本轮循环
        continue
    print(i)

else语句在while循环起到很大的作用

#示例1
i = 1
while i<5:
    print('我在循环内我现在的值是',i)
    i += 1
print('我在循环外我现在的值是',i)   #这个时候这个语句无论循环停止与否都会被执行


#示例2
i = 1
while i<5:
    print('我在循环内我现在的值是',i)
    if i<2:
        break
else:#只有当循环条件为假的时候才会执行
    print('我在循环外我现在是',i)   #这个时候这条语句不会被执行 因为循环判断条件依然为真
      

质疑声:感觉这个else没什么用啊

错!这个可以非常容易检测循环的退出状态

#每周坚持打卡满七天的小程序
day = 1    #从第一天开始
while day<=7:
    answer = input('今天有学习吗(yes or no)?:')
    if answer != 'yes':
        break
    day += 1    #当他等于yes的时候坚持天数就加一
else:#当循环结束 也就是坚持到七天的时候这个语句被执行
    print('你已经坚持了七天!')

返回值这个时候如果你在某一天输入的不是yes那他就会跳出循环
并且不会执行else里面的语句 这就是else的作用

循环结构的嵌套

九九乘法表示例

i=1
while i<10:
    j = 1
    while j<=i:
        print(i,'*',j,'=',i*j,end=' ')
        j += 1
    i += 1
    print('\n')

循环嵌套里的break只跳出一层循环

#每周学习七天 每天学习八个小时
day = 1
hour = 1
while day<=7:
    while hour<=8:
        print('今天一定学八个小时')
        hour += 1
        if hour>1:
            break
    day += 1

        

for循环

可迭代对象有哪些?

1.列表 2.元组 3.字符串 4.字典 5.集合 6.生成器

for循环用法

for 变量 in 可迭代对象:

        执行的语句

range()的用法        他的参数只能是整形

range(stop)

for i in range(10):
    print(i)
返回值就是从0到9

range(start,stop)

for i in range(1,11):
    print(i)
这个时候返回的是1到10

range(start,stop,step)这里step是可选的 就是你加上去也行不加也行 他是代表步数的意思

for i in range(0,11,2):#这里step参数设置为2所以每次访问都会跳两步 0,2,4这样
    print(i)
返回值是0,2,4,6,8,10

step也可以是负数(左闭右开)

for i in range(11,1,-2):#这里如果step设置为往后跳两步的话起始和末尾需要调换(左闭右开区间)
    print(i)
返回值就是10,8,6,4,2
for循环嵌套
for i in range(2,10):
    for x in range(2,i):
        if i % x == 0:
            print(i,'=',x,'*',i//x)
            break
    else:
        print(i,'是一个素数')

第六章、列表

创建列表

使用[]将准备放入列表中的元素包裹起来 不同元素之间用,分割

列表是可以嵌套的 也就是说列表里面可以有无数个列表

a=[1,'hello',3,1.34]#类别可以存储不同类型的元素

用for语句可以依次访问列表中的每个元素

a=[1,3,5,7,9,'helo']
for i in a:
    print(i)

列表元素和下标的映射关系

元素1'hello'123789'here''spider'
下标012345

如果列表很长你想获得他的最后一个元素这个时候可以这样做

a=[1,1,5,5,5,16,51,561,6,51,56,56,1,65,15,6,1,5656,1,6]
print(a[-1])

如果想要倒数第二个元素
print(a[-2])
以此类推

列表切片

list[start,stop,step]

a=[1,2,3,4,5,6,7,8,9,0]

a[:]--->访问所有元素

a[::-1]--->倒序访问所有元素 本来是从1到0 现在是从0到1

a[0:5]--->从下标0开始访问 到下标5的时候结束 不包含下标5

a[::2]--->1,3,5,7,9

列表增加元素

如果你创建好一个列表后还想添加一个元素你可以使用append()、extend()、insert()、切片添加等方式

1、append()                一次只可以加一个 并且会放到列表最后

a=[1,2,3,4]
这个时候你想使用append方式加一个5进去很简单
a.append(5)
这个时候a列表里的元素就是[1,2,3,4,5]

2、extend()添加的必须是可迭代对象且新添加内容会追加到原列表最后一个元素的后面

a=[1,2,3,4,5]
c=[6,7,8,9,0]
这个时候你想把c里面元素添加到a列表里很简单
a.extend(b)
或者说你想直接添加进去也可以
a.exten([11,12,13])

3、insert(x,y) 在下标x的位置插入y元素

a=[1,3,4,5]
这个列表少了个2对吧 你想插入2进去也很简单
a.insert(1,2)#这里1对应的是下标位置 2对应的是想添加的元素 它可以是任何列表里能放的东西

4、切片添加

s=[1,2,3,4,5]
这个时候你想通过切片的方式添加一个6进去
s[len(s):] = 6

列表删除元素

如果列表里添加了你不想要的元素怎么办

不用慌你可以用remove()、pop()、clear()方法进行删除

1、remove()  一次只能删除一个 多个同样元素只会删除从左往右第一个

a=[1,2,2,3,4,5,6]
a.remove(2)

2、pop(x)删除下标x的元素 这个x是可选参数 也就是说可以写也可以不写 默认删除最后一个

a=[1,2,3,4,5,6,7]
a.pop()默认删除最后一个元素也就是7
a.pop(1)删除下标为1的参数也就是2

3、clear()如果你想删除列表中的所有元素那么可以用clear()方法

a=[1,2,3,4,5,6,7]
a.clear()
这个时候a列表里面就是空的了a=[]

列表替换元素

如果列表里的元素填错了可以用下标索引的方式进行替换

a=[1,2,3,4,8,6,7,8]
a[4] = 5这里索引值为4对应下标为4的元素

index(x)方法也可以用了替换

a=[1,2,4,5,8,7,9,8]
a[a.index(8)] = 6 #你用index获得元素8的下标索引 再用列表索引修改

列表查询元素

count(x)查找x出现的次数

a=[1,2,3,4,4,4,4,4,5,6,7]
a.count(4)查找为4的元素有几个
返回值为5 表示有5个

index(x,start,stop)

a=[1,'hello','xixi','bobo','xixi']

你想查找为xixi的元素在哪个下标
a.index('xixi')

可是这个时候有两个xixi他就只会返回第一个xixi的下标
不过没关系 既然已经知道了第一个xixi的下标那么我们可以传入start和stop参数
a.index('xixi',-1) -1表示从最后开始查找

列表进行排序

sort(reverse = False)

sort()方法可以让列表进行排序

a=[8,5,12,3,4,6]
a.sort()可以让列表里的元素进行从小到大排序
a.sort(reverse = True)默认值是False但是如果改成True的话就会进行从大到小排序

reverse()方法 可以让列表进行翻转

a=[5,3,4,2,8]
a.reverse()
调用完后列表a会变成[8,2,4,3,5]

列表拷贝

想让复制出一个列表可以用复制的方法

浅拷贝:

s=[1,4,2,5]
s1 = s[:] 这样做是浅拷贝
s2 = s 等与创建了一个影子 影子变大后人不会变大 但人变小影子也会变小
s3 = s.copy()也等价于上面的操作

深拷贝:

        如果想创造出一个独立的相同列表可以导入copy的模块进行深拷贝

import copy
s=[1,2,3,4,5]
s1 = copy.deepcopy(s)

列表推导式

 [expression for target in iterable]

操作很简单 一行生成一个列表

x = [x for x in range(10)]
这样做就能生成一个0到9的列表了

 小知识、

用ord()可以将输入的一个值进行编码 相当于加密

用chr()可以将输入的一个值进行解码 相当于解密

a=ord('s')
这里返回的是字符s对应的编码
chr(a)
这里返回的就是s

is语法

第七章、元组

元组是一个不可变序列 他不支持增删改(元组里有列表则列表里的元素可以改变)

元组创建

t = () 创建一个空元组
t = 1,2,3,4,5,6 ----------->他会组成一个(1,2,3,4,5,6)的元组
t = (1,'hdas','hehe',[1,2,3,4])

 元组可以使用下标索引来访问元素

t= ('one','two',3,4,'五')
t[2]

 元组支持count和index方法

t = (1,2,3,4,5,6,7,7,7,7,9)
t.index(5)
返回10
t.count(7)
返回4

元组可以嵌套

t = (123,'456',(7,8,9))

 元组和列表都可以直接把里面的元素赋值给变量名(但变量名数量要和元素数量一致)

t = (10,20,30)
l = [40,50,60]
x,y,z = t
a,b,c = l

第八章、字符串

大小写字母互换

        capitalize()               将字符串的首字母变为大写其他字母变为小写

a = 'hello'
t=a.capitalize()返回首字母变大写其他字母变小写给t


        casefold()                将字符串都变为小写

a = 'HelloWW'
t=a.casefold()返回所有字符串变为小写

        title()                        将字符串每个单词的首字母变为大写,其他字母变为小写

a = 'hello,world'
t=a.title()返回每个单词的首字母变大写 其他字母变为小写

        swapcase()              将字符串的大小写翻转

a = 'HeLlo'
t=a.swapcase()返回将字符串大小写翻转的结果给t

        upper()                    将字符串所有字母变为大写

a = 'HeLlo'
t=a.upper()返回将字符串字母变为大写的结果给t

        lower()                     将字符串所有字母变为小写

a = 'HeLlo'
t=a.lower()返回将字符串所有字母变为小写的结果给t

        左中右对齐


        center(width,fillchar=' ')    中心对齐15个字符

x = 'I love you'
print('中心对齐15个字符')
print(x.center(15))


        ljust(width,fillchar=' ')        左对齐15个字符

x = 'I love you'
print('左对齐15个字符')
print(x.ljust(15))

        rjust(width,fillchar=' ')        右对齐15个字符

x = 'I love you'
print('右对齐15个字符')
print(x.rjust(15))


        zfill(width)                用0填充左侧

x = 'I love you'
print('用0填充左侧')
print('-520'.zfill(7))

 查找

        count(sub,[,start[,end]])        找不到返回0
        

x = '上海自来水来自海上'
print('总共出现了几次海?')
print(x.count('海',0,5))


        find(sub,[,start[,end]])        找不到返回-1
        

x = '上海自来水来自海上'
print('find从左往右找第一次出现在')
print(x.find('海'))


        rfind(sub,[,[start[,end]]])    找不到返回-1
        

​
x = '上海自来水来自海上'
print('rfind从左往右找第一次出现在')
print(x.rfind('海'))

​


        index(sub,[,[start[,end]]])    找不到抛出异常

print('index从左往右找第一次出现在')

print(x.index('海'))

        rindex(sub,[,[start[,end]]])    找不到抛出异常

print('rindex从左往右找第一次出现在')

print(x.rindex('海'))

替换


        expandtabs([tabsize = 8])                                    将字符串中的Tab全部替换成空格
        
        replace(old,new,count = -1)                                替换old字符串为new字符串,count为替换次数 默认为-1 

        translate(str.maketrans('old','new','指定忽略的字符串'))        用str.maketrans制表后再调用translate进行替换

判断


        startswith(prefix[,start[,end]])                                判断测试的字符串是否出现在起始位置
        
        endswith(prefix[,start[,end]])                                判断测试的字符串是否出现在结束位置
        
        istitle()                                               判断字符串单词是否都为大写开头其他为小写
        
        isupper()                                          判断字符串是否都为大写
        
        islower()                                           判断字符串是否都为小写

        isalpha()                                           判断字符串是否都由字母组成

        isspace()                                           判断字符串是否为空白字符串

        isprintable()                                      判断字符串是否都为可打印字符

        isdecimal()                                        判断字符串是否都为数字(小范围)

        isdigit()                                              判断字符串是否都为数字(中范围)

        isnumeric()                                        判断字符串是否都为数字(大范围)

        isalnum()                                           判断字符串是否都为数字(超级大范围)
        
        isidentifier()                                       判断字符串是否为合法Python标识符
        
        keyword.iskeyword()                         判断字符串是否为Python的保留标识符(需导入模块)

 截取


        lstrip(chars = None)                                        删除字符串左侧的指定字符(默认为空)
        
        rstrip(chars = None)                                        删除字符串右侧的指定字符(默认为空)
        
        strip(chars = None)                                        删除字符串左右两侧的指定字符(默认为空)
        
        removeprefix(prefix)                                        删除字符串指定的前缀
        
        removesuffix(suffix)                                        删除字符串指定的后缀

拆分和拼接


        partition(sep)                                            以sep向右分割返回三个元素的元组

        rpartition(sep)                                             以sep向左分割返回三个元素的元组

        split(sep,maxsplit=-1)                                         以sep向右分割返回一个列表
        
        rsplit(sep,maxsplit=-1)                                     以sep向左分割返回一个列表
        
        splitlines(keepends=False)       参数表示结果是否包含换行符默认为(False) 将字符串按行分割以返回一个列表    
        
        join(iterable)

格式化字符串


        可以用下标索引 可多次利用 也可用关键字索引            
        [[fill]align [sign] [#] [0] [width] [grouping_option] [.precision] [type]]
        [fill]        填充字符
        [align]    对齐方式        ^居中        >左对齐        <右对齐
        [withd]    宽度
        #'b'二进制   'c' Unicode字符  'd'十进制   'o'八进制   'x'十六进制   'X'十六进制大写

s='1234'
print('{:#>20,}'.format(s))# 这里#是填充符号 >是左对齐 20是字段长度 ,是千位分隔符

第九章、序列

序列


    列表为可变序列
    元组和字符串为不可变序列
    序列可用+号进行拼接    也可用*进行重复
    id( )    可查看唯一标志
    in(  )和not in(  )可用了查看对象是否在序列中
    del    用于删除一个或多个指定的对象    也可用于删除可变序列中的指定元素

     列表 元组 字符串相互转化
    list(  )将可迭代对象转化为列表
    tuple(  )将可迭代对象转化为元组
    str(  )将可迭代对象转化为字符串

    min(  )和max(  )           可设置default参数进行捕获异常
    min(*,default=  )           获得序列里的最大值
    max(*,default=  )          获得序列里的最小值
    sum(*,start=100  )    用于计算求和 start用于设置计算的起始值

    sorted(  )和reversed(  )
    sorted(*,reverse=False)返回一个全新的列表原来的列表不受影响和sort有区别    reverse默认为False
    sorted(*,key=len)        返回的是元素长度的比较结果

    reversed()             返回一个参数的反向迭代器

    all(  )和any(  )
    all判断对象全为真才为真
    any判断对象任意一个为真就为真
    
    enumerate(  )返回一个枚举对象 将每个元素从0开始共同构成一个二元组的列表 0可以替换成任何数字

    zip(  )        创建一个聚合多个可迭代对象的迭代器 以最短的为主

x = [1,2,3]
y = [4,5,6]
z = 'Hello'
list(zip(x,y,z))
返回[(1, 4, 'H'), (2, 5, 'e'), (3, 6, 'l')]

     map()       创建一个迭代器

     filter()        创建一个迭代器

     iter()          将序列变成一个迭代器

     next(x,y)    从迭代器x里提取一个值  y作为迭代器没了的时候返回的值

     type(x)       查看x的类型

第十章、字典

字典是以键值对进行储存的

d={key:value,....}

创建一个列表

a = {"吕布":"口口布","关羽":"关习习"}

b = dict(吕布='口口布',关羽 = '关习习')

c = dict([('吕布','口口布'),('关羽','关习习')])#以列表作为参数 列表中元素以元组包裹起来作为键值对

d = dict({'吕布':'口口布','关羽':'关习习'})

e = dict({'吕布':'口口布'},关羽='关习习')#混合应用

f = dict(zip(['吕布','关羽'],['吕布','关习习']))

d = dict.fromkeys('spider',250)

创建一个空字典直接赋值{}就可以了

d={}

字典增加

a = {"吕布":"口口布","关羽":"关习习"}

b = dict(吕布='口口布',关羽 = '关习习')

c = dict([('吕布','口口布'),('关羽','关习习')])#以列表作为参数 列表中元素以元组包裹起来作为键值对

d = dict({'吕布':'口口布','关羽':'关习习'})

e = dict({'吕布':'口口布'},关羽='关习习')#混合应用

f = dict(zip(['吕布','关羽'],['吕布','关习习']))

d = dict.fromkeys('spider',250)

字典删除

d.pop('s',default)  #指定一个键删除 default用于找不到时捕获异常

d.popitem() #删除字典里最后一个键值对

del d['p']  #指定一个键删除

d.clear()   #清空字典

字典更改

 直接访问键修改 如果存在则覆盖 不存在则创建

d = dict.fromkeys('spider')

d['s'] = 115

 update()修改

d = dict.fromkeys('spider')

d.update({'i':105,'d':104})

d.update(s='70',r=67)

字典查询

可以通过键(key)直接访问

d={'a':1,'b':2}
d[a]

 get(key,default)访问 如果有则返回 没有则返回default

d={'a':1,'b':2}
d.get('c','这里没有c')
返回 这里没有c

 d.setdefault(x,y) 方法可以访问x键 如果不存在x则自动创建一个并且他的值为y 如果没有写y的值那么他将会自动赋值None(空)

d={}
d.setdefault(a)
d.setdefault(b,'hello')

items()返回字典的动态键值对 也就是字典变化了 再用items查询 他返回的也会不一样

d = {"吕布":"口口布","关羽":"关习习"}
d.items()

返回dict_items([('吕布', '口口布'), ('关羽', '关习习')])

keys()返回字典的动态键

d = {"吕布":"口口布","关羽":"关习习"}
d.keys()

返回dict_keys(['吕布', '关羽'])

values()返回字典的动态值

d = {"吕布":"口口布","关羽":"关习习"}
d.values()

返回dict_values(['口口布', '关习习'])

字典嵌套

除了列表、元组 字典也可以进行嵌套,他的嵌套方式也很简单 只需要将字典作为值传递进去

d = {"吕布":{'语文':70,'数学':80,'英语':90},"关羽":{'语文':80,'数学':70,'英语':60}}

也可以在字典里将列表作为值传递进去 

d = {"吕布":[60,70,80],"关羽":[80,90,70]}

字典推导式

d = dict(zip(['s','p','i','d','e'],[70,105,115,104,67])).
b = {k:v for k,v in d.items() if v>100} 字典推导式 以{}包裹起来

第十一章、集合

集合是无序的 它具有唯一性 也就是说集合里面相同的元素他会只保留一个

创建集合     

集合是以{}进行包裹起来的

a={1,2,3,4,5,6}

用set()进行创建集合

a=[1,2,3,4,5]
b=set(a)

用frozenset()可以创建一个不可变集合

a={1,2,3,4,5,6}
b=frozenset(a)

用{}创建空集合 如果直接将{}赋值过去的话将是字典类型

a={'',}

拷贝集合

如果直接用赋值的方式去拷贝集合那他就是一个浅拷贝

a={1,2,3,4,5}

b=a

如果要实现深拷贝就要使用copy方法

a = {1,2,3,4,5}
b = a.copy()

判断集合

    isdisjoint()        用于判断是否毫不相干    
    
    issubset()        用于判断是否为一个集合的子集        
                               <真子集和子集<=


    issuperset()        用于判断是否为一个集合的超集
                                >真超集和超集>=


    union()            用于与其他集合合并到一起组成一个新集合
                                |并集符号


    intersection()        用于查看交集
                                &交集符号


    difference()        用于查看差集
                                -差集符号


    symmetric_difference    用于排除掉A与B集合共有元素后剩余元素组成的集合 称为对称差集
                                                ^对称差集符号

集合添加元素 

 update(*other) 支持多个参数

a={1,2,3,4}
a.update('5','6','7','8')

add()可以添加一个元素

a={1,2,3,4,5}
a.add(6)

集合删除元素

remove(elem) 删除一个元素 如果不存在则抛出异常

a={1,2,3,4,5,6}
a.remove(3)

discard(elem) 删除一个元素 如果不存在则静默处理

a={1,2,3,4,5,6}
a.discard(7)

pop()随机从集合中弹出一个元素 也就是他下标的最后一位元素

a={1,2,3,4,5,6}
a.pop()

clear()清空集合

a={1,2,3,4,5,6}
a.clear()

hash()可获得一个对象的哈希值 对象需要是不可变对象

hash('哈')

第十二章、函数(1)

介绍函数

函数主要作用就是打包代码    他的好处是:
            1、可以最大程度的实现代码的重用减少冗余的代码
            2、可以将不同功能的代码进行封装分解,从而降低结构的复杂度,提高可读性

help()可以用了查看函数文档 

创建和调用函数

如何创建一个函数和调用呢 很简单

创建函数

def func():这里用func作为函数名字 以:结尾
    pass   这里pass表示不做任何操作


调用函数
func()    调用时只需要函数名加上()就可以进行调用了

函数返回值

有时可能需要函数反馈这时候用return可以实现自定义函数返回
如果没有设置返回内容则会默认返回None
返回多个值会打包成一个元组

def func():
    x,y,z = 1,2,3
    return x,y,z

此时返回(1, 2, 3)

形式参数

def func(name, age):  这个时候name和age就是形参
    print(f"Hello my name{name}! im {age} years old.")

实际参数

实参是调用函数时传递给形参的值。在调用函数时,你需要为函数定义中的每个形参提供一个实参值(除非形参有默认值)

def func(name, age):  
    print(f"Hello my name is {name}! im {age} years old.")

func("Alice", 30)这里Alice对应name  30对应age 这就叫做实参

位置参数

上面的例子就是使用位置参数。实参和形参是通过位置一一对应的

关键字参数

你也可以使用关键字参数来调用函数,这样就不需要按照形参定义的顺序来传递实参

def func(name, age):  
    print(f"Hello my name is {name}! im {age} years old.")

func(age = 30,name="Alice")指定关键字来传递值 这样就可以不遵循位置规则

默认参数

在函数定义时,你可以为形参指定默认值。如果调用函数时没有提供该形参的实参值,那么就会使用默认值 但是默认参数必须放在最后面

def func(name, age=30):  
    print(f"Hello my name is {name}! im {age} years old.")

func("Alice")

可变参数

Python还支持可变数量的参数,这可以通过使用*args(非关键字参数)和**kwargs(关键字参数)来实现

def func(*args, **kwargs):  
    print(args)  # 元组,包含所有位置参数  就算只传递一个也是以元组进行包裹
    print(kwargs)  # 字典,包含所有关键字参数  
  
func(1, 2, 3, a=4, b=5)  # 输出:(1, 2, 3) {'a': 4, 'b': 5}

限制参数语法

可以对用户传递进去的参数进行限制

/在中间表示左侧只能使用位置参数

*在中间表示右边只能是关键字参数

def abc(a,/,b,c):	斜杠左侧只能使用位置参数
    print(a,b,c)
			
def abc(a,*,b,c):	*表示左侧可以是位置参数也可以是关键字参数但右侧只能是关键字参数
    print(a,b,c)

混合使用

*args和**kwargs两种收集参数也可以混合使用

def myfunc(a,*b,**c):
  	  print(a,b,c)
myfunc(1,2,3,4,x=5,y=6)第一个1会传给a 然后剩下的位置参数都传b 其他关键字参数传给c
返回1 (2, 3, 4) {'x': 5, 'y': 6}

解包参数

args = (1,2,3,4)
kwargs = {'a':1,'b':2,'c':3,'d':4}
def myfunc(a,b,c,d):
    print(a,b,c,d)
myfunc(*args)#前面的*用于解包元组进行分配
myfunc(**kwargs)#前面的**用于解包字典进行分配

第十二章、函数(2)

函数作用域

LEGB规则(从大到小)
Local                           
局部作用域
外层有一个x内层也有一个的时候 会调用内层的x

Enclosed
嵌套函数的外层作用域
被包裹的函数外有个x,自己本身也有个x则会调用自己的x

Global
全局作用域

Build-In
内置作用域
像print str都为内置函数 如果用为变量名则会被覆盖 导致函数无法应用

局部作用域、

def myfunc():
    x=520    函数内定义的变量只能在内部进行调用
    print(x)

全局作用域

x=880		全局变量可以在函数内部被访问到
def myfunc():
    print(x)

global语句

如果要在函数内修改全局变量的话要用global语句进行声明

x=520
def myfunc():
    global x
    x = 250
    print(x)

嵌套函数 、       

嵌套函数在内部无法直接调用,要调用只能用外部函数调用,定义时就需要调用

def funA():
    x=520
    def funB():
        x=250
        print(f'in funB x={x}')
    funB()
    print(f'in funA x={x}')

nonlocla语句

当函数被嵌套时无法修改外部函数的值 除非用nonlocal语句声明

def funA():
    x=520
    def funB():
        nonlocal x
        x=250
        print(f'in funB x={x}')
    funB()
    print(f'in funA x={x}')

函数闭包

什么是函数闭包?顾名思义他的意思就是函数闭包

函数只有在定义和被调用的时候才需要用( )

def funA():
    x = 880
    def funB():
        print(x)
    return funB
注意
	这个时候funA() = funB
	而funA()()=funB()

闭包示例:

def outer():
    x=0
    y=0
    def inter(x1,y1):
        nonlocal x,y
        x+=x1
        y+=y1
        print(f'x在{x},y在{y}')
    return inter
move = outer()

将outer函数赋值道move的变量里后就可以通过move调用inter可以实现带记忆功能的函数

函数装饰器

import time
def time_time(func):
    def call_func():
        print('程序开始运行....')
        start = time.time()
        func()
        stop = time.time()
        print('结束程序运行,总共耗费了{:.2f}秒'.format(stop-start))
    return call_func
@time_time		等价于myfunc = time_time(myfunc)相当于狸猫换太子
def myfunc():
    time.sleep(2)
    print('hello 妈的法克')
myfunc()

用了装饰器后方便代码阅读 看起来不会很乱

多个装饰器应用到一个函数上    需注意顺序变化

def add(func):
    def inner():
        x = func()
        return x + 1
    return inner
def cube(func):
    def inner():
        x = func()
        return x*x*x
    return inner

def square(func):
    def inner():
        x = func()
        return x*x
    return inner
@add
@cube
@square
def test():
    return 2
此时的计算流程就是2*2 = 4 然后4*4*4=64 紧接着64+1 结果为65

给装饰器传递参数

import time
def logger(msg):
    def time_master(func):
        def call_time():
            print('open')
            start = time.time()
            func()
            stop = time.time()
            print(f'[{msg}]over in {stop-start} s')
        return call_time
    return time_master
@logger('A')
def myfun():
    time.sleep(2)
    print('hello~')
@logger('B')
def myfun2():
    time.sleep(1.5)
    print('fuck you')
#funA = logger(msg='A')(myfun)
#funB = logger(msg='B')(myfun2)

myfun()
myfun2()

匿名函数

匿名函数        ````````````一行流函数
lambda整个表达式就是一个函数的引用

#普通函数
def squareX(x):
    return x*x
print(squareX(3))
#匿名函数
squareY = lambda y : y*y
print(squareY(5))
#匿名函数创建列表
y = [lambda x:x*x,2,3]
print(y[0](y[1]))
print(y[0](y[2]))

利用匿名函数进行编码
mapp=map(lambda x:ord(x) + 10,'SPIDER')

普通函数进行编码
def boring(x):
    return ord(x)+10
print(list(map(boring,'spider')))

另一种运用方式
print(list(filter(lambda x:x%2,range(10))))

函数生成器

每调用一次提供一个数据,并且会记住当时状态,而列表元组这些可迭代对象则是容器

def counter():
    i = 0
    while i <= 5:
        yield i
        i += 1
c=counter()
next(c)

斐波那契数列

def fib():
    back1,back2 = 0,1
    while True:
        yield back1
        back1,back2 = back2,back1+back2

第十二章、函数(3)

函数递归

普通程序员用迭代、天才程序员用递归
递归就是函数调用自身的过程
每次调用递归函数他并不会马上返回而是等到最底层的那个数返回

错误递归用法

def funC():
    print('AWBDYL')
    funC()

这样写会无限调用自己本身 也就是一直打印

用递归求一个数的阶乘

def factIter1(n):
    if n==1:
        return 1 等到最后一次等于1的时候就返回1
    else:
        return n*factIter1(n-1)

这里比较烧脑 实际过程如下
5*factIter1(5-1)
    return 4*factIter1(4-1)
	    return 3*factIter1(3-1)
		    2*factIter1(2-1)这个时候这里n=1了 结果返回1
			return 1
然后再对他们进行大的一次运算
5*(5-1)*(4-1)*(3-1)*(2-1)

示例1:兔子生育

迭代方式

def fib(n):
    a = 1#上上个月的兔子数量
    b = 1#上个月的兔子数量
    c = 1#这个月的兔子数量
    while n>2:
        c = a+b
        a = b
        b = c
        n -= 1
    return c

递归的方式

def fibRecur(n):
    if n==1 or n==2:
        return 1
    else:
        return fibRecur(n-1)+fibRecur(n-2)

 示例2:高级难度(汉诺塔)

def hanoi(n,x,y,z):#n为层数 x z y为放置位置		代入只有两层进去操作
    if n == 1:#如果汉诺塔只有一层 就直接把A移动到C
        print(x,'-->',z)
    else:
        hanoi(n-1,x,z,y)塔A通过塔C移动到B#形参进行变化 调用的时候才不会出现一直是塔A移动到塔C
        print(x,'-->',z)移动完后把塔A-->塔C
        hanoi(n-1,y,x,z)塔B-->塔A-->塔C
n=eval(input('请输入汉诺塔层数:'))
hanoi(n,'A','B','C')

函数文档、注释类型、内省

help()函数可以查看函数文档 函数的说明书

第三方模块Mypy可以让python做检测
函数文档

def exchange(dollar,rate=6.32):
    '''
    汇率转换 美元转换为人民币
    参数
    dollar是美元的数量
    rate是汇率 默认为6.32
    返回值为人民币的数量
    '''
    return dollar*rate

help(exchange)就可以查看刚刚编写的内容了


类型注释(只不过是函数作者的提醒 并不会阻止)
 

def times(s:str = 'spider',n:int = 3)->str:该函数注释表示作者希望调用者传入到s参数中的类型是字符串类型
    return s*n                      传入到n参数是整数的类型 这个函数将返回一个字符串类型的返回值




def times(s:list[int] = 'spider',n:int = 3)->list:函数注释表示作者希望调用者传入到s参数中的类型是整数列表
    return s*n




def times(s:dict[str,int] = 'spider',n:int = 3)->list:函数注释表示作者希望调用者传入到s参数中的类型是字典,键为字符串类型,值为整数类型
    return list(s.keys())*n


内省
想知道一个函数的名字可以在程序运行的时候自省

times.__name__    前后两个下横线
'times'

times.__annotations__可以用了查看函数的类型注释    
以字典的方式打印出来{'s': dict[str, int], 'n': <class 'int'>, 'return': <class 'list'>}


exchange.__doc__  查看函数文档

高阶函数

高阶函数就是一个函数通过接受另一个函数来进行调用
如:map filter max min 等等

functools模块
内置函数和模块函数的地位不同
内置函数调用可直接写出来而模块函数要调用就需要导入模块
模块名.函数名才可使用这个函数
reduce()  函数的第一个参数是指定一个函数这个函数必须指定两个参数,第二个参数是可迭代对象   
                作用:就是把可迭代对象中的函数依次传递到第一个参数指定的函数中 最终返回累计的结果

def add(x,y):
    return x+y
functools.reduce(add,[1,2,3,4,5])
他相当于是做了add(add(add(add(1,2),3),4),5)


将reduce的第一个参数写成lambda表达式代码更加极客
 

functools.reduce(lambda x,y:x*y,range(1,10))

偏函数  

是指对指定的函数进行二次包装,
通常是将现有的函数部分参数预先给绑定了,
从而得到一个新的函数该函数就称之为偏函数
作用就是将一个函数的多个参数给拆分多次进行传递

square = functools.partial(pow,exp=2)
square = functools.partial(pow,exp=3)

@wraps装饰器

装饰器的副作用是

myfunc = time_marster(myfunc)
myfunc.__name__ 会返回call_func

解决方法
wraps装饰器

import functools
def time_marster(func):
    @functools.wraps(func)
    def call_func()


这时候去调用myfunc.__name__时就会返回myfunc而不会有副作用了

第十三章、永久存储

当程序运行起来是 大多数数据都是从硬盘转移到内存中

因为内存和CPU之间的数据传输速度>硬盘和CPU之间的数据传输速度
但是内存有一个天生的短板(不能断电)一旦断电或者重启里面的数据就会被抹去

open()方法

以open(file mode buffering encoding errors newline closefd opener) 打开一个文件

f = open('hello.txt','w',encoding='UTF-8')
f.write('hi')
f.close()文件每次打开都需要用close()关闭

 with语句

    尽管中间出错也会保持文件的完整性     不需要手动关闭

使用方法:
    

with open('123.txt','w') as f:
        f.write('I love you')

文件对象的方法和含义


f.close()             关闭文件对象

f.flush()            将文件对象中的缓存写入到文件中(不一定有效)

f.read(size=-1,/)        从文件对象中读取指定的字符 如果没有指定size参数 或参数为负数的时候读取剩余的所有字符

f.readable()            判断该文件是否支持读取(如果返回的值为False 则调用read()方法会导致OSError异常)

f.readline(size=-1,/)        从文件对象中读取一行字符串(包括换行符),如果指定了size参数,则表示读取size个字符

f.seek(offset,whence=0,/)    修改文件指针的位置 从whence参数指定的位置 (0代表文件起始位置 1代表当前位置 2代表文件末尾)
                偏移offset个字节返回值是新的索引位置

f.seekable()            判断文该文件是否支持修改文件指针的位置(如果返回值为False则调用seek(),tell()
                                    ,truncate()方法都会导致OSError异常)

f.tell()            返回当前文件指针在文件对象中的位置

f.truncate(pos=None,/)        将文件对象截取到pos为止,默认是截取到文件指针当前指定的位置

f.write(text,/)            将字符串写入文件对象中,并返回写入的字符数量(字符串的长度)

f.writable()            判断该文件对象是否支持写入(如果返回值为False则调用write()方法会导致OSError异常)

f.writelines(lines,/)        将一系列字符串写到文件对象中(不会自动添加换行符,所以通常是人为地加在每个字符串的末尾)

 路径处理

pahlib模块 从3.4开始发行
Path函数可用cwd()获取当前目录的路径
也可指定一个路径传递到Path中 会生成一个路径对象
需要拼接可用/进行拼接
 

from pathlib import Path
Path.cwd()
p = Path.cwd()
q = p/'Hello.txt'

判断

is_dir()    可以判断一个路径是否为一个文件夹        q.is_dir()
is_file()    可以判断一个路径是否为一个文件        q.is_file()
exists()    可以进行测试    路径            q.is_exists()
name        用于获取路径的最后一个部分        p.name
suffix        用于获取文件后缀                p.suffix
parent        获取其父级目录                p.parent
parents        获得其逻辑祖先构成的一个不可变序列        p.parents
parts        将路径的各个组件拆分成元组的形式        p.parts
stat        查询文件或文件夹的状态信息        p.stat()
stat().st_size    指定文件或文件夹的一个尺寸单位为字节    p.stat().st_size

 相对路径VS绝对路径
        绝对路径:是一个文件真正存在的路径 一个路径从根目录开始一级一级指向文件或文件夹 这个路径就称为绝对路径
            例如:C:\Users\Administrator\Desktop\Python key\草稿\no.13(永久储存)
        相对路径:以当前目录作为基准进行一级一级推导的一个路径
            ../Hello.txt

resolve()    可将相对路径转换成绝对路径方法

from pathlib import Path
Path.cwd()
p = Path.cwd()
q = p/'Hello.txt'
Path('../Hello.txt').resolve()
WindowsPath('C:/Users/Administrator/Desktop/Python key/草稿/Hello.txt')

 iterdir()    可获取当前路径下所有子文件和子文件夹

from pathlib import Path
Path.cwd()
p = Path.cwd()
q = p/'Hello.txt'
p.iterdir()

 如果想将当前路径下所有文件整理成一个列表可以这么做

[x for x in p.iterdir() if x.is_file()]

创建文件夹

mkdir()方法

mkdir(exist_ok = Flase) 默认值为Flase  表示已存在时报错

如果要避免报错就把exist_ok后面的Flase改成True

如果存在多个不存在的父级目录也会报错要使用parents参数设置为True

mkdir(parents = True)

Path内部还打包了一个open方法 除了不用传入路径参数 其他参数和open一样

f = q.open('w')

rename()    修改文件或文件夹的名字
replace()    可瞬移到某个文件夹里

删除操作

rmdir()        删除文件夹
unlink()    删除文件

查找操作

glob()        查找文件

pickle模块

pickle模块可以将Python对象序列化

打包:

import pickle
x,y,z = 1,2,3

s='Fishc'

l=['你好啊',1,2,3,4]

d={"one":1,'two':2}
with open('date.pkl','wb')as f:
    pickle.dump((x,y,z,s,l,d),f)

这个是打包操作

 解包:

import pickle
with open('date.pkl','rb') as f:
    x,y,z,s,l,d = pickle.load(f)
print(x,y,z,s,l,d,sep='\n')

第十四章、异常

何为异常

 在Python中你写的代码运行时跳红字那个就叫做异常

异常处理方法

try:
    检测范围
except [expression [as indentifier]:
    异常处理代码
except [expression [as indentifier]:
    异常处理代码*]
else:
    没有触发异常时执行的代码
finally:
    收尾工作执行的代码]

他的处理方法有很多

1、tyr-except语句捕获并处理异常

第一种:

try:
    1/0
except:                        #如果try语句没有出错except也就不会被执行
    print('出错了')

第二种:
try:
    1/0
except ZeroDivisionError as e: #可以加上一个可选as把异常的原因提取出来赋值给e
    print(e)


第三种(捕获单个异常):
try:
    520+'321'
except ZeroDivisionError:      #如果指定捕获异常 出现其他异常时一样会报错
    print('出错了除数不能为零')
第四种(捕获多个异常):
try:
    1/0
    520+'hello'
except (ZeroDivisionError,ValueError,TypeError):#用括号把可能存在的异常包裹起来
    pass                            #如果出现任意一个都会执行pass

单独处理每个异常

try:
    1/0
    520+'hello'
except ZeroDivisionError:
    print('除数不能为0')
except ValueError:
    print('值不正确')
except TypeError:
    print('类型不正确')

2、try-except-else 这里else只有在try语句正常执行完毕后才会被执行 如果出现异常则不会执行

try:
    2/0
except:
    print('发现异常')
else:
    print('没有任何异常')

3、try-except-finally    这里finally不管有没有异常都会被执行出来 (通常用于最后关闭文件的收尾工作)

try:
    123+'hello'
except:
    print('抓到异常')
finally:
    print('抓没抓到都会执行')

4、try和finally的组合    发生异常与否都会执行finally语句

try:
    while True:
        pass
finally:
    print('晚安')

5、异常的嵌套

try:
    try:
        520+'fishc'
    except:
        print('内部异常')
    else:
        print('内部没有发现异常')

    1/0				注意检测顺序
except:
    print('外部异常')
else:
    print('内外部没有发现任何异常')
finally:
    print('收尾!')

6、raise语句

raise语句通常用了自爆 也就是主动发起异常

raise 异常名(内容) from 异常名
 

raise ValueError('值不正确')

raise ValueError('值不正确') from ZeroDivisionError

这个时候会把ZeroDivisionError异常换为ValueError异常


raise ValueError('零异常被我捕获替换成值异常了') from ZeroDivisionError

这个时候返回
ZeroDivisionError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    raise ValueError('零异常被我捕获替换成值异常了') from ZeroDivisionError
ValueError: 零异常被我捕获替换成值异常了

7、assert语句

aassert语句和raise语句一致但是他只能发起AssertionError异常(通常用来进行内部调试)

s='adadad'
assert s=='hahahhahahaha'
返回下面的内容
Traceback (most recent call last):
  File "<pyshell#4>", line 1, in <module>
    assert s=='aadadad'
AssertionError

内置异常大合集

异常名称
BaseException:所有异常的基类

SystemExit:解释器请求退出

KeyboardInterrupt:用户中断执行(通常是输入^C)

Exception:常规错误的基类

StopIteration:迭代器没有更多的值

GeneratorExit:生成器(generator)收到系统退出信号

StandardError:所有内置标准异常的基类

ArithmeticError:所有数值计算错误的基类

FloatingPointError:浮点计算错误

OverflowError:数值运算结果太大无法表示

ZeroDivisionError:除(或取模)零 (所有数据类型)

AssertionError:断言语句失败

AttributeError:对象没有这个属性

BufferError:缓冲区操作时出错

EOFError:没有内建输入,到达EOF标记

ImportError:导入模块/对象失败

LookupError:无效数据查询的基类

IndexError:序列中没有此索引(index)

KeyError:映射中没有这个键

MemoryError:内存溢出错误(对于Python 解释器是致命的)

NameError:未声明/初始化对象

OSError:操作系统相关的错误

BlockingIOError:操作将阻塞对非阻塞流

ChildProcessError:子进程相关操作失败

ConnectionError:连接相关错误的基类

BrokenPipeError:管道断裂错误

ConnectionAbortedError:连接尝试被对方终止

ConnectionRefusedError:连接被拒绝

FileExistsError:文件已存在

FileNotFoundError:文件不存在

IsADirectoryError:对目录执行文件操作

NotADirectoryError:对非目录执行操作

PermissionError:权限错误

ProcessLookupError:进程查询失败

TimeoutError:操作超时

ReferenceError:弱引用试图访问已经垃圾回收了的对象

RuntimeError:一般的运行时错误

NotImplementedError:尚未实现的方法

SyntaxError:Python 语法错误

IndentationError:缩进错误

TabError:Tab 和空格混用

SystemError:一般的解释器系统错误

TypeError:不同类型间的操作不合适

ValueError:传入的参数值不符合要求

UnicodeError:Unicode 相关错误

UnicodeDecodeError:解码错误

UnicodeEncodeError:编码错误

UnicodeTranslateError:转换错误

Warning:警告的基类

DeprecationWarning:关于被弃用的特性的警告

PendingDeprecationWarning:关于特性将被弃用的警告

RuntimeWarning:可疑的运行时行为(runtime behavior)的警告

SyntaxWarning:可疑语法的警告

UserWarning:用户代码生成的警告

StopIteration:迭代器没有更多的值

第十五章、类和对象(面向对象)

类是什么?

你可以把他比作是一个人 我们每个人都有着相同的属性 两个眼睛 两个耳朵等

我们后天学会的走路跑步称为方法

创建类

用class这个关键字然后加上类名后面填上:就可以创建了

class C:               定义一个C类
    def get_self(self):他的方法就是获取自己本身
        print(self)
c=C()                  将C类给一个对象
c.get_self()           对象来调用这个类里面的方法

self是一个对实例对象本身的引用 

继承类

有时候每个类都要写同一个东西太麻烦了 我们可以用继承类的方法

继承的方法就是在创建的时候后面加上()括号里面是你要继承的父类

class A:#父类
    x = 520
    def hello(self):
        print('你好,我是A')
class B(A):#子类
    x = 250
    def hello(self):
        print('fuck you')

多重继承

一个类可以有多个父类 但是他的方法名如果冲突了就会采用括号里第一个父类的方法

class A:#父类
    x = 520
    def hello(self):
        print('你好,我是A')
class B:#父类
    x = 250
    def hello(self):
        print('fuck you')

class C(B,A):#子类
    pass

判断类

isinstance(b,A)用于检测b对象是否属于A类

issubclass(B,A)用于检测B类是否属于A类

组合

class Turtle:#乌龟
    def say(self):
        print('不积跬步,无以至千里!')
class Cat:#猫
    def say(self):
        print('喵喵喵')
class Dog:#狗
    def say(self):
        print('汪汪汪')
class Garden:#花园
    t = Turtle()
    c = Cat()
    d = Dog()
    def say(self):
        self.t.say()#如果不加self就会报错
        self.c.say()#实例对象和类的绑定
        self.d.say()

g=Garden()
g.__dict__可以查看当前对象有哪些值

通过类来定义对象的个人属性

class C:
    def set_x(self,v):
        self.x = v

这个时候你去调用
c=C()
c.set_x(150)
他这个时候你对象的x值就等于150
class C:
    x=100
    def set_x(self,v):
        x = v   前面不加self就谁也改变不了 等于说是在set_x里创建了一个局部变量x

c=C()
C.x = 250  这里修改x的值对象也会跟着变化 但是通过类来修改里面的属性所有对象都会受影响
c.__dict__  查看当前类或对象的属性和方法

小技巧

class C:
    pass
C.x = 250    类或对象他可以赋值创建一个或覆盖
C.y = 'spider'
C.z = [1,2,3]

构造函数
 

__init__创建类的示例的时候他会自动被调用

class C:
    def __init__(self,x,y):这个时候如果要实例化一个对象 就要给他赋上x和y的值
        self.x=x
        self.y=y
    def add(self):
        return self.x + self.y
    def mul(self):
        return self.x * self.y

重写

如果继承的属性或者方法不满意可以写一个同名的属性或函数进行重写

class D(C):
    def __init__(self,x,y,z):
        C.__init__(self,x,y) 可以直接调用C类里面的__init__方法使self.x = x self.y = y
        self.z = z
    def add(self):
        return C.add(self) + self.z
    def mul(self):
        return C.mul(self) * self.z

钻石继承

钻石继承的主要问题是方法解析顺序MRO,特别是当基类A中的某个方法在子类B1和B2中都被重写了时。在这种情况下,Python需要决定当在C的实例上调用该方法时应该使用哪个版本。

class A:
    def __init__(self):
        print('hello im A')
class B1(A):
    def __init__(self):
        A.__init__(self)
        print('hello im B1')
class B2(A):
    def __init__(self):
        A.__init__(self)
        print('hello im B2')
class C(B1,B2):
    def __init__(self):
        B1.__init__(self)
        B2.__init__(self)
        print('hello im C')
这个时候会返回
hello im A
hello im B1
hello im A
hello im B2
hello im C
他的顺序是(<class '__main__.C'>, <class '__main__.B1'>, <class '__main__.B2'>, <class '__main__.A'>, <class 'object'>)

__mro__属性可以查看解析顺序

解决方法

super()函数会自动按照MRO的顺序找到下一个要调用的父类

super()函数 他回去父类里自动搜索方法并且自动绑定self参数自动避免重复调用的问题

class A:
    def __init__(self):
        print('hello im A')
class B1(A):
    def __init__(self):
        super().__init__()
        print('hello im B1')
class B2(A):
    def __init__(self):
        super().__init__()
        print('hello im B2')
class C(B1,B2):
    def __init__(self):
        super().__init__()
        print('hello im C')

Mixin

Mixin通常表示为了添加某个功能后期添加上的

class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def say(self):
        print(f'我叫{self.name},今年{self.age}岁')

class FlyMixin:
    def fly(self):
        print('我会飞喽')

class B(A,FlyMixin):
    def special(self):
        print('我的技能是拱白菜')
b=B('大肠',5)
b.say()
b.special()
b.fly()

多态

他是指同一个运算法、函数或者对象在不同的场景下具有不同的效果
好比见我摇尾巴,见陌生人乱叫
多态是Python的特性 
len()函数也是多态的

示例一:

class Shape:
    def __init__(self,name):
        self.name = name
    def area(self):
        pass


class Square(Shape):
    def __init__(self,length):
        super().__init__('正方形')
        self.length = length
    def area(self):
        return self.length * self.length

    
class Circle(Shape):
    def __init__(self,radius):
        super().__init__('圆形')
        self.radius = radius
    def area(self):
        return 3.14 * self.radius * self.radius

class Triangle(Shape):
    def __init__(self,base,height):
        super().__init__('三角形')
        self.height = height
        self.base = base
    def area(self):
        return self.base * self.height / 2

示例二:

class Cat:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def intro(self):
        print(f'im a cat my name is {self.name} i\'m{self.age}years old')
    def say(self):
        print('Cat fuck you bitch')
class Dog:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def intro(self):
        print(f'im a dog my name is {self.name} i\'m{self.age}years old')
    def say(self):
        print('Dog fuck you bitch')
class Pig:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def intro(self):
        print(f'im a pig my name is {self.name} i\'m{self.age}years old')
    def say(self):
        print('Pig fuck you bitch')
c=Cat('团子',2)
d=Dog('乐乐',1)
p=Pig('大肠',5)

def animal(x):定义一个函数来自动调用对象
    x.intro()
    x.say()

示例三:

def animal(x): 他并不关心x传入的是什么 只要他里面有intro和say方法就不会报错
    x.intro()
    x.say()
class Bicycle:
    def intro(self):
        print('我曾经跨过山河大海,也穿过人山人海')
    def say(self):
        print('都有自行车了,要什么兰博鸡泥')
b=Bicycle()
animal(b)

私有变量

 指通过某种手段使得对象中的属性或方法无法被外部访问
所谓的私有变量就是把想设为私有变量的名字偷偷换了一个 但是用c.__dict__可以依然查看
名字改变是发生在类实例化对象之前 在这之后想添加一个私有变量就不行了

开发中遇到    _单个下横线开头的变量(仅供内部使用的变量)

单个下横线结尾的变量名_                                                                                                             

比如:不能用class作为变量名但是你非要用 觉得用了这个程序就无敌了 那这个时候就在class后面加个_你就可以用他作为变量名了

name mangling 名称修饰 在名字的前面加上两个下横线__

示例
 

class C:
    def __init__(self,x):
        self.__x = x
    def set_x(self,x):
        self.__x = x
    def get_x(self):
        print(self.__x)
c=C(520)
c.get_x()
c.set_x()

__slots__属性 他可以限制这个类只有哪些属性

好处:可以限制有几个属性,然后可观的节省内存空间
坏处:牺牲Python的灵活性,使用了__slots__属性就无法拥有动态添加属性的功能了

class C:
    __slots__ = ['x','y']
    def __init__(self,x):
        self.x=x
c=C()
c.x=250
c.y=520

c.z=456这个时候会报错 因为类限制了只有x和y两个属性

class D:
    __slots__ = ['x','y']
    def __init__(self,x,y,z):#z没有包含在__slots__里面所以无法添加
        self.x = x
        self.y = y
        self.z = z

继承了父类的__slots__属性是不会再子类中生效的
继承后__slots__属性依然存在 但不生效
同时也可以用__dict__属性了

class C:
    __slots__ = ['x','y']
    def __init__(self,x):
        self.x = x
class E(C):
    pass
e = E(250)

e.x
250

e.y=555
e.y
555

e.f = 666
e.f
666

魔法方法

前面用过的__init__也是一种魔法方法:       __init__初始化魔术方法

class Human:
    #属性
    eye = 2
    skin = 'yellow'
    
    #方法
    #魔术方法__init__
    def __init__(self,kidname,petname):#petname init的形参
        #print('__init__被执行')
        #为对象添加成员
        self.sex = '男'
        self.age = 1
        self.name = kidname
        self.petname = petname #self.petname 对象的成员
        
    def eat(self):
        print('吃饭方法')
    def run(self):
        print('跑步方法')
    def sleep(self):
        print('睡觉方法')
实例化一个人的对象
one = Human('刘佳怡')#实例化对象【1.制作一个对象 2.为对象初始化操作】
print(one.__dict__)#打印对象成员

__new__构造方法 构建 创造

class Human:
    #属性
    eye = 2
    skin = 'yellow'
    #魔法方法
    def __new__(cls,sex):#(重载object内部自带的__new__)
        print('new方法被触发')#用于查看他什么时候被触发的
        #自己控制对象的生成过程(女的生,男的不生)
        if sex == '女':
            #生成对象并返回
            return object.__new__(cls)#上帝之手 使用new方法时类会自动传递到cls里面
        else:
            #不生成对象
            return None
    def eat(self):
        print('吃饭方法')
        
    def run(self):
        print('跑步方法')
        
    def sleep(self):
        print('睡觉方法')

#实例化对象
one = Human('女') #实例化对象【1.制作一个对象(new) 2.初始化对象(init)】
print(one)

__del__析构方法

class Human:
    #属性
    eye = 2
    skin = 'yellow'
    
    #方法
    def eat(self):
        print('吃饭方法')
        
    def run(self):
        print('跑步方法')
        
    def sleep(self):
        print('睡觉方法')

    def __del__(self):
        print('del方法被触发')

one = Human()
two = one
del one    删除对象 系统回收对象
del方法被触发

运算魔法方法

这个比较简单我们直接一笔带过

#__add__方法 算数运算

class S(str):
    def __add__(self,other):
        return len(self) + len(other)
s1 = S('Spider')
s2 = S('Python')
print(s1 + s2)      #相当于s1.add(s2)
print(s1+'python')
print('python'+s1)

#__radd__方发 返算数运算
class S1(str):
    def __add__(self,other):
        return NotImplemented #NotImplemented对象表示未实现
                              #不理解就替换这行进去len(self)+2+len(other)+2
class S2(str):
    def __radd__(self,other): 
        return len(self) + len(other)
s1 = S1('Apple')
s2 = S2('Banana')
print(s1+s2)#成功调用是因为S1和S2是不同类的对象
            #S1里面必须不能实现__add__()方法
            #如果是s2+s2他就不是不同的类将会返回两个s2相加的字符串
            #否则会优先执行S1里的add方法


#__iadd__方法 增强赋值运算
class S1(str):
    def __iadd__(self,other):
        return len(self) + len(other)

class S2(str):
    def __radd__(self,other): 
        return len(self) + len(other)
s1 = S1('apple')
s2 = S2('banana')
s1 += s2  #这里相当于len(s1)+len(s2)这样做会把对象覆盖掉
print(s1)


位运算

按位与  3 & 2=2  
	2 -> 010
	3 -> 011
    2 & 3 -> 010
相同的位同时为1才是1

	3 & 4=0
	3-> 011
	4-> 100
    3 & 4-> 000
没有相同的位同时是1使用按位与运算后的结果是0



按位或	3|2=3
	2->010
	3->011
      3|2->011
所以他的结果是011转化为十进制就是3

	3|4=7
	3->011
	4->100
      3|4->111
所以他的结果为111转化为十进制就是7

按位非(补码)
	将每个二进制位进行取反
	~2
	-3
	~3
	-4

按位异或
	取不同的
	3^2
	2->010
	3->011
       3^2=001
	结果为1


	3^4
	3->011
	4->100
       3^4=111
	结果为7


左右移动运算法
移位是会丢失数据的

右移两位8>>2相当于8 // pow(2,2)地板除
左移两位8>>2相当于8 * pow(2,2)地板除

运算符左侧是运算对象(运算对象必须是整数) 运算法右侧是指定要移动的位数(移动的位数必须是正整数)
>>向右移动	
<<向左移动
bind(8)
'0b1000'
8>>2
1000-->0010
8>>3
1000-->0001

8<<2
1000-->100000

属性访问类

劫持属性
__index__劫持操作 __index__被对象被作为索引值使用的时候才会调用
class C:
    def __index__(self):
        print('被劫持了')
        return 3
#c=C()
#s='spider'
#s[c]
#被劫持了
#'d'



属性访问方法
hasattr()检测对象是否有某个属性
hasattr(c,'name')

getattr()获取对象的属性
getattr(c,'name')
getattr(c,'_C__age')访问隐藏变量

setattr()设置对象的属性
setattr(c,'_C__age',19)

delattr()删除某个对象的属性
delattr(c,'name')




属性访问的魔法方法

class C:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def __getattribute__(self,attrname):#获取属性之前拦截一下
        print('拿来吧你')
        return super().__getattribute__(attrname)

    def __getattr__(self,attrname):#只有当属性不存在时才会触发
        if attrname == 'Fishc':
            print('i love Fishc')
        else:
            raise AttributeError(attrname)


设置属性
class D:
    def __setattr__(self,name,value):#当赋值给属性的时候这个方法会自动调用以下代码
        self.__dict__[name] = value  #__dict__()里存放的就是这个对象的属性和键值对
#如果用  self.name = value会进入死循环
#用字典可以避开死循环
#supper方法可以这样写:super().__setattr(name,value)

#d.name = 'spider'
#d.name
#'spider'


删除属性
class D:
    def __setattr__(self,name,value):#赋值属性时执行的操作
        super().__setattr__(name,value)
        print('赋值完毕')
    def __delattr__(self,name):#删除属性
        try:#没有异常正常赋值
            del self.__dict__[name]			也可以替换成这句super().__delattr__(name)
            print(f'删除属性\'{name}\'成功')
        except:#如果出现异常则打印以下内容
            print('错误!不存在该属性')
d=D()
d.name = 'hello'
d.age = 18
del d.name

索引切片迭代协议

__index__被对象被作为索引值使用的时候才会调用
dir()查看一个对象的内置函数
#__getitem__(self,index)既能响应单个下标的索引操作,又能支持代表范围的切片索引方式

切片操作是slice()函数的语法糖
slice(start,stop,sep)

示例1
class C:
    def __getitem__(self,index):
        print(index)
        
class D:
    def __init__(self,date):
        self.date = date
    def __getitem__(self,index):#进行拦截索引或切片的操作'与获取相关的操作都会被拦截'
        print('我是__getitem__')
        return self.date[index]*2 #for语句会去访问__getitem__这个魔法方法
    def __setitem__(self,index,value):
        print('我是__setitem__')
        self.date[index] = value#raise ValueError可以恶搞一下 更深层了解这个方法

__iter__(self)和__next__(self)

代偿

#__contains__(self,item)实现成员关系的检测	运算符是in和not in

class C:
    def __init__(self,date):
        self.date = date
    def __contains__(self,item):
        print('__contains__ go work')
        return item in self.date
c=C([1,2,3,4,5])

#不用__contains__ 用__iter__和__next__代偿
class D:
    def __init__(self,date):
        print('__init__ go work')
        self.date = date
    def __iter__(self):
        print('__iter__ go work')
        self.i = 0
        return self
    def __next__(self):
        print('__next__ go work')
        if self.i == len(self.date):
            raise StopIteration
        item = self.date[self.i]
        self.i += 1
        return item

#不用__contains__ 用__getitem__代偿
class D:
    def __init__(self,date):
        print('__init__ go work')
        self.date = date
    def __getitem__(self,index):
        print('_-getitem go work')
        return self.date[index]


#布尔__bool__方法
class C:
    def __bool__(self):
        print('Bool')
        return True
#如果不用__bool__方法 用len方法 那他调用bool的时候则等于调用len
class D:
    def __init__(self,date):
        self.date = date
    def __len__(self):
        print('Len')
        return len(self.date)#非零返回True 空返回False

字符串比较魔法方法和让魔法失效


<   __lt__(self,other)
<=  __le__(self,other)
>   __gt__(self,other)
>=  __ge__(self,other)
==  __eq__(self,other)!=  __ne__(self,other)

__魔法名__ = None等于让魔法方法失效  __contains__ = None

class S(str):#如果没有重新定义这个方法 则会默认使用str的比较方法
    def __lt__(self,other):
        return len(self)<len(other)
    def __le__(self,other):
        return len(self)<=len(other)
    def __gt__(self,other):
        return len(self)>len(other)
    def __ge__(self,other):
        return len(self)>=len(other)
    __eq__ = None #不让这个魔法方法生效  
    __ne__ = None #不让这个魔法方法生效

__call__方法

python可以像调用一个函数一样调用一个对象
要定义一个__call__(self,[,args])的魔法方法

class C:
    def __call__(self,*args,**kw):#一个*代表位置参数,两个*代表关键字参数
        print(f'位置参数{args}\n,关键字参数{kw}')
c=C()
c(1,2,3,x=250,y=520)
位置参数(1,2,3)
关键字参数{'x':250,'y':520}

用__call__方法去计算x*y

class C:
    def __init__(self,x):
        self.x = x
    def __call__(self,y):
        return x*y
c=C(5)#设置x为5
c(4)#设置y为4
返回20

字符串相关的魔法方法

eval()#去引号后执行 ···eval()可以相当于repr()的反函数

__str__(self)和__repr__(self)

_str__(self):响应的是str内置函数的魔法方法 将参数转化为字符串(给人看的)
调用str语句时执行

__repr__(self):响应的是repr内置函数的魔法方法 将对象转化为程序可执行的字符串(给程序看的)
调用repr语句时执行

没有定义str的时候repr可以代偿
没有定义repr的时候str不可以代偿

示例:

class C:
    def __repr__(self):
        return 'I love You'
c=C()
str(c)
返回I love You
class D:
    def __str__(self):
        return 'I fuck You'
d=C()
#repr(d) 这个时候会报错
class E:
    def __str__(self):
        return 'I fuck Fishc'
#e=[E(),E(),E()]
#for each in e:
#    print(each)
#这个时候用str会执行不出来 但用repr就可以执行出来
class F:
    def __init__(self,data):
        self.data = data
    def __str__(self):#用于形式转换
        return f'data = {self.data}'#如果用print的话返回的就是这个形式data = 250

    def __repr__(self):#用于形式转换
        return f'F({self.data})'#如果直接访问这个对象 返回的就是这个形式F(500)

    def __add__(self,other):#用于运算+
        self.data += other
f=F(250)

print(f)
'data = 250'

f+250
f
'F(500)'

property

class property(fget=None,fset=None,fdel=None,doc=None)

#property方法实现
#优点: 
#1.简化遮遮掩掩的操作
class C:
    def __init__(self):
        self._x = 250
    def getx(self):
        return self._x
    def setx(self,value):
        self._x = value
    def delx(self):
        del self._x
    x = property(getx,setx,delx)
    
#__getattr__ __delattr__ __setattr__方法来实现
#缺点:
#1.非常复杂
class D:
    def __init__(self):
        self._x = 250
    def __getattr__(self,name):
        if name == 'x':
            return self._x
        else:
            return super().__getattr__(name)
    def __setattr__(self,name,value):
        if name == 'x':
            super().__setattr__('_x',value)#用self._x = value会出现无线递归 因为你赋值给一个量的时候他就调用这个方法
                                #方法里面又赋值 又会调用方法
        else:
            super().__setattr__(name,value)
    def __delattr__(self,name):
        if name == 'x':
            super().__delattr__('_x')
        else:
            super().__delattr__(name)


#如果将property函数作为装饰器来使用,会让创建只读属性的工作变为极为简单
class E:
    def __init__(self):
        self._x = 250
    @property
    def x(self):
        return self._x
#如果去掉这个装饰器的代码就是这样的
class E:
    def __init__(self):
        self._x = 250
    def x(self):
        return self._x
    x = property(x)#因为只赋值了property()的第一个参数 也就是实现用了获取的fget参数
                    #另外两个参数采用默认值None表示不支持写入和删除,所以才会出现只读属性


#定义了一种后要定义其他两种的方法

#此方法和第一种示例方法实现效果是一样了 只不过用了装饰器看起来比较乱

class F:
    def __init__(self):
        self._x = 250
    @property #相当于 x = property(x)
    def x(self):
        return self._x
    #property属性拥有getter、setter、deleter三种方法 这些是property返回的东西
    #返回的值给到了x
    @x.setter
    def x(self,value):
        self._x = value
    @x.deleter
    def x(self):
        del self._x

类方法

在类里定义的函数都被称之为方法,通常定义在类里边的方法类自己是无法调用他的,需要通过示例对象来操作 ----方法需要对象来绑定----
绑定类的方法

特点:绑定的是类而非实例对象
 

class C:
    def funA(self):
        print(self)
    @classmethod
    def funB(cls):
        print(cls)

class C:
    count = 0
    def __init__(self):
        C.count += 1
#因为get_count是类方法,所以就算不小心覆盖了也不会受影响
    @classmethod
    def get_count(cls):
        print(f'该类一共实例化了{cls.count}个对象')

静态方法(放在类里面的函数)

在类里面的函数叫方法 是因为方法需要跟对象进行绑定 但是函数没有绑定的操作
他可以让你做到在类里面做到一个不需要绑定的函数
示例:
 

class C:
    @staticmethod
    def funC():
        print('I love U')
#c=C()
#c.funC()
#I love U
#C.funC()
#I love U

使用静态方法也可以效仿类方法来做一个统计实例化对象数量的demo

class C:
    count = 0
    def __init__(self):
        C.count += 1
    @staticmethod
    def get_count():
        print(f'该类一共实例化了{cls.count}个对象')
#自动化统计实例化了几个对象
class C:
    count = 0
    @classmethod
    def add(cls):
            cls.count += 1
    def __init__(self):
            self.add()
    @classmethod
    def get_count(cls):
            print(f'一共实例化了{cls.count}个对象')
class D(C):
    count = 0
class E(C):
    count = 0
c1 = C()
d1,d2 = D(),D()
e1,e2,e3 = E(),E(),E()

描述符

现有描述符再有property函数 

只要实现了__get__、__set__、__delete__三个种哪个任何一个或多个方法的类都叫描述符

__get__(self,instance,owner=None)拦截对象属性的读取操作

__set__(self,instance,value)拦截对象属性的写入操作

__delete__(self,instance)拦截对象属性的删除操作

class D:
    def __get__(self,instance,owner):
        print(f'get~\nself->{self}\ninstance->{instance}\nowner->{owner}')
    def __set__(self,instance,value):
        print(f'set~\nself->{self}\ninstance->{instance}\nvalue->{value}')
    def __delete__(self,instance):
        print(f'delete~\nself->{self}\ninstance->{instance}')
class C:
    x = D()
c=C()
c.x = 250#设置他时返回
#set~
#self-><__main__.D object at 0x0000025CCAEE0980>
#instance-><__main__.C object at 0x0000025CCAEA6510>
#value->250

c.x访问他时返回
#get~
#self-><__main__.D object at 0x0000025CCAEE0980>
#instance-><__main__.C object at 0x0000025CCAEA6510>
#owner-><class '__main__.C'>

del c#删除他时返回
#delete~
#self-><__main__.D object at 0x0000025CCAEE0980>
#instance-><__main__.C object at 0x0000025CCB434470>


self参数队友的是描述符这个类的实例对象 也就是x属性的值

instance参数对应的是被描述符拦截的属性所在的类的实例对象

owner参数对应的是被描述符拦截的属性所在的类
#通过描述符去修改一个类里面的私有变量
class D:
    def __get__(self,instance,owner):
        return instance._x
    def __set__(self,instance,value):
        instance._x = value
    def __delete__(self,instance):
        del instance._x

        
class C:
    def __init__(self,x=250):
        self._x = x
    x = D()
c=C()
c.x
#250
c.__dict__
#{'_x': 520}
del c.x
c.__dict__
#{}

用描述符造出一个property函数

class Myproperty():
    def __init__(self,fget=None,fset=None,fdel=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
    def __get__(self,instance,owner):
        return self.fget(instance)
    def __set__(self,instance,value):
        self.fset(instance,value)
    def __delete__(self,instance):
        self.fdel(instance)
class C:
    def __init__(self):
        self._x = 250
    def getx(self):
        return self._x
    def setx(self,vlaue):
        self._x = vlaue
    def delx(self):
        del self._x
    x=Myproperty(getx,setx,delx)#实例化一个property的对象 把他生成的结果赋值给x 就可以通过x来管理私有的_x
c=C()
c.x
#250
c.x=520
c.__dict__
#{'_x': 520}
del c.x
c.__dict__
#{}

type()

type()函数根据参数的不同,有两种不同的用法:

第一种:

根据object参数的类型,返回值是一个type对象,通常与object.__class__所返回的对象相同

type(object)传递一个对象,返回该对象的类型

type(250)
#<class 'int'>
type('Hello')
#<class 'str'>
type(1.2)
#<class 'float'>

type('hello') is str #判断类型是否为字符串
#True

type(250)('520') 因为type(250)返回int 所以就相当于int('520')
#520

type('Hello')(3.14) 同上返回值将变成一个字符串
#'3.14'

type([])('hello')
#['h','e','l','l','o']

type(())([1,2,3,4,5])
#(1,2,3,4,5)

type({}).fromkeys('hello')
{'h':None,'e':None,'l':None,'l':None,'o':None}

我们自己定义的类也逃不出type的魔爪

class C:
    def __init__(self,x):
        self.x = x
c=C(250)
c
#<__main__.C object at 0x0000020F83A24380>

d=type(c)(520)#相当于 d=C(520)
d
#<__main__.C object at 0x0000020F83A24380>

d.x
#520

type是Python万物的起点

class C:
    pass

type(C)
#<class 'type'>
type(type)
#<class 'type'>

第二种:

根据传入的三个参数,返回一个新的type对象。

type(name,bases,dict,kwds)

name 指定将要创造的类的名字 (需是字符串)

bases 指定将要创造类的父类 (需是元组)

dict 指定将要创造的类的属性和方法 (需是字典)

kwds (可选)收集参数,当且仅当需要时,该收集参数会被传递给适当的元类机制((__init__subclass))

class C:
    pass
C = type('c',(),{})
c = C()
c.__class__
#<class '__main__.C'>#查看一个对象的类
C.__bases__
#(<class 'object'>)#因为没有继承任何父类 所以默认是object object是所有类的默认父类

D = type('D',(C,),{})#
D.__bases__
#<class '__main__.C'>
E = type('E',(),dict(x=250,y=520))#定义一个E类 他的属性x,y分别为250和520

def funC(self,name = 'spider')
    print(f'hello {name}')
F = type('F',(),dict(say_hi = funC))
f = F()
f.say_hi()
#hello spider
f.say_hi('蜘蛛侠')
#hello 蜘蛛侠

__init_subclass__() 作用:加强父类对子类的管理

class C:
    def __init_subclass__(cls):
        print('父爱如山')
        cls.x = 520

class D(C):
    x = 250
当子类D继承父类C后 其父类的__init_subclass__()方法就会被调用
#父爱如山
D.x
#520    #在子类中赋值的x属性是没有用的 他会被父类的__init_subclass__()替换掉

__init_subclass__()除了第一个参数需要传入类之外还可以传递其他参数

class C:
    def __init_subclass__(cls,value):
        print('父爱如山')
        cls.x = value

class D(C,value = 520):
    x = 250
#父爱如山
D.x
#520

D = type('D',(C,),dict(x=250),value = 520)#第四个直接添加父类必须的参数
#父爱如山
D.x
#520

如果需要多个也没问题
class C:
    def __init_subclass__(cls,value1,value2):
        print('父爱如山')
        cls.x = value1
        cls.y = value2
D = type('D',(C,),dict(x=250),value1=520,value2=666)
D.x
#520
D.y
#666

元类

什么是类?

类就是用来创建对象的模板

什么是元类?

元类就是创造类的模板(上升了一个级别)

为什么type能用来创造类?因为type本身就是一个元类

类之间是存在继承关系的,元类也一样所有的元类都继承自type

最简单的元类

class MetaC(type):
    pass

class C(mataclass = MetaC):
    pass
c=C()
type(c)
#<class '__main__.C'>
type(C)
#<class '__main__.MetaC'>
type(MetaC)
#<class 'type'>

元类讲解

class MetaC(type):
    def __new__(mcls,name,bases,attrs):
        print('__new__ in MetaC~')
        return super.__new__(mcls,name,bases,attrs)
    def __init__(mcls,name,bases,attrs):
        print('__init__ in MetaC')
class C(metaclass = MetaC):   #如果要设置他的元类在定义类时要加上metaclass=
    def __new__(cls):
        print('__new__ in C~')
        return super().__new__(cls)
    def __init__(self):
        print('__init__ in C~')

元类的应用

给所有的类添加一个属性

class MetaC(type):
    def __new__(mcls,name,bases,attrs):
        attrs['author'] = 'spider'
        return type.__new__(mcls,name,bases,attrs)
class C(metaclass = MetaC):
    pass
class D(metaclass = MetaC):
    pass
c=C()
d=D()
c.author
#spider
d.author
#spider
class MetaC(type):
    def __init__(mcls,name,bases,attrs):
        cls.attrs = 'spider'
        return type.__init__(cls,name,bases,attrs)
class C(metaclass = MetaC):
    pass
class D(metaclass = MetaC):
    pass

c=C()
d=D()

c.attrs
#spider
d.attrs
#spider

对类名的定义规范做限制

将他限制类名只能用大写开头

class MetaC(type):
    def __init__(cls,name,bases,attrs):
        if not name.istitle():
            raise ('类名必须是大写字母开头')
        type.__init__(cls,name,bases,attrs)

        
class mycls(metaclass = MetaC):
    pass

修改对象的属性值

用户传递参数进来的时候将他的字母全变为大写

class MetaC(type):
    def __call__(cls,*args,**kwargs):
        new_args = [each.upper() for each in args if isinstance(each,str)]
        return type.__call__(cls,*new_args,**kwargs)
class C(metaclass = MetaC):
    def __init__(self,name):
        self.name = name
c=C('spider')
c.name
#'SPIDER'

限制类实例化时的传参方式

 比如说可以要求类在实例化对象的时候只能通关键字参数来进行传参

 如果传递的是位置参数则报错

class MetaC(type):
    def __call__(cls,*args,**kwargfs):
        if args:
            raise TypeError('仅支持传入关键字参数')
        return type.__call__(cls,*args,**kwargs)
class C(metaclass = MetaC)
    def __init__(self,name)
c=C('spider')
#抛出异常
c=C(name = 'spider')
c.name
'spider'

禁止一个类被实例化

class MetaC(type):
    def __call__(cls,*args,**kwargs):
        raise TypeError('该类不允许直接实例化对象')


class C(metaclass = MetaC):
    def __init__(self,name):
        self.name = name
c=C()
#抛出异常

可以使用静态方法访问
class C(metaclass = MetaC):
    @staticmethod
    def static_ok():
        print('静态方法访问是允许的')
C.static_ok()
#静态方法访问是允许的
也可以使用类方法访问
class C(metaclass = MetaC):
    @classmethod
    def class_ok(cls):
        print('类方法直接访问是允许的')
C.class_ok()
#类方法直接访问是允许的

只允许实例化一个对象

class SimpleInstance(type):
    def __init__(cls,*args,**kwargs):
        cls.__instance = None
        type.__init__(cls,*args,**kwargs)
    def __call__(cls,*args,**kwargs):
        if cls.__instance is None:
            cls.__instance = type.__call__(cls,*args,**kwargs)
            return cls.__instance
        else:
            return cls.__instance
class C(metaclass = SimpleInstance):
    def __init__(self,name):
        self.name = name
#这时候无论实例化多少个C的对象他都是一样的

利用元类就可以阻止类被实例化

抽象基类

1.抽象基类不能被直接实例化 只能够被继承使用

2.子类必须实现抽象基类中定义的抽象方法 否则无法被实例化

比如要定义一个'水果'类

要定义抽象基类最稳妥的办法就是使用abc模块

模块abc-AbstractBaseClasses

from abc import ABCMeta,abstractmethod
class Fruit(metaclass = ABCMeta):
    def __init__(self,name):
        self.name = name
    @abstractmethod
    def good_for_health(self):
        pass
fruit = Fruit('水果')
#抛出异常
class Banana(Fruit):
    def good_for_health(self):
        print('吃香蕉变大香蕉')
banana = Banana('香蕉')
banana.good_for__health()
#吃香蕉变大香蕉

第十六章、模块和包

模块是一种代码的打包手段

他可以使一个或多个源代码文件可以被其他程序所重复使用

创建模块


创建一个hello.py的源文件
def say_hi():
    print('hi spider')
def say_hello():
    print('hello spider')

调用模块

import hello
hello.say_hi()
hello.say_hello()

导入模块

通常有三种方案可以导入模块

import 模块名称

from 模块名称 import 对象名称 *代表导入全部

import 模块名称 as 关联名称

import hello
hell.say_hi()
hell.say_hi()

from hello import say_hi,say_hello
say_hi()
say_hello()

import hello as he
he.say_hi()
he.say_hello()

命名冲突

比如我们要导入的模块里面有一个int()函数

def say_hi():
    print('hi spider')
def say_hello():
    print('hello spider')
def int(x):
    print(f'哈哈{x}')
-------------------------------------------------------------------
from hello import *
say_hi()
say_hello()
int('250')
#哈哈250

两个模块之间拥有相同名字对象并且都用from import导入

后面导入的模块会覆盖掉前面导入的相同方法

使用from import 要注意名字冲突的问题

hello.py
def say_hi():
    print('hi im hello.py')
def say_hello():
    print('hello im hello.py')
------------------------------------

hello1.py
def say_hi():
    print('hi im hello1.py')
def say_hello():
    print('hello im hello1.py')

from hello import *
from hello1 import *
say_hi()
#hi im hello1.py
say_hello()
#hello im hello1.py

if __name__ == '__main__'

模块在导入的过程中会从头到尾执行一次导入模块中的所有语句

加上if __name__ = '__main__'表示单独执行模块脚本的时候的测试语句

在Python3.3之前的版本必须要有一个__init__.py这么一个源文件 用于识别这个文件夹是包

在导入模块的时候使用点(.)号将包和模块进行分隔

import TC.tc
print(f'32摄氏度等于{TC.tc.c2f(32):.2f}')
print(f'99华氏度等于{TC.tc.f2c(32):.2f}')

__init__.py作为负责初始化工作的文件

他可以在里面定义属于包的全局变量

遏制from...import *的附加伤害

__all__属性

__all__=['say_hello','x']
#限制他如果用from ... import *只能导入这列表里面的东西
x = 250
s = 'spider'

def say_hello():
    print('hello spider')
def say_hi():
    print('hi spider')

__all__属性还可以作用于包

在构造文件里面使用定义__all__属性等同于上面的效果

总结

对于模块来说,若果没有定义__all__属性,那么from...import *的语法将导入模块中的所有东西

对于包来说,若果没有定义__all__,那么from...import *的语法将不会导入包里面的任何模块

与全世界的Pyhon程序员共享你的代码

如何将程序发布到PyPI上面

第一步进入官网、www.pypi.org

第二步注册账号登录

第三部按照指定的框架来部署代码

project/                                #项目的主目录

|----LICENSE                       #开源许可证

|----pyproject.tom1               #指定安装环境

|----README.md                 #项目的介绍

|----src/

|        ---------img_compress #源代码主目录

|                |---__init__.py      #包的初始化文件

|                |---compress.py    #源代码

|----tests/                                #测试文件夹(可以为空)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值