首先,博主是自学的Python,肯定会有错误emmmm希望大家不要喷我。。。如果有错误或者哪里我没有写清楚的,欢迎大家留言指出,在这里先感谢大家啦。现在我们进入正题!!!

一、数据类型

一、数值类型

Q1:Python里面怎么做简单的加减乘除?
Q2:怎样方便的把计算结果保存下来,方便下次计算?
Q3:Python中小数是怎么计算的呢?小数和整数的混合运算计算结果是怎样的呢?
Q4:Python中总共有多少数值类型?

数值类型一共有四种:
  浮点型;float;
  整型:int; 
  复数型:complex; 
  布尔型:bool

变量命名规则:变量名开头不能是数字,不能是纯关键字(例如:list,tuple等)

1.常用运算符


+(加) -(减) *(乘) /(除) %(取余数) // (默认向下取整) **(次方)

向下取整:不管小数点后面的数字,直接取前面的
向上取整:不管小数点后面的数字,直接进一位
要想向上取整可以导入math模块

import math #导入
b = math.ceil(5/2) #向上取整
print(b)

2.decimal的运算

python计算是不精确的,要想精确计算需导入decimal

mport decimal #导入
c = decimal.Decimal('2.2') #精确数计算
d = decimal.Decimal('2')
print(c-d)

3.布尔型的计算

布尔类型不是用来计算,是用来判断,首字母必须大写

4.复数

e = 1+1j 

这里j前的1必须写

二、序列类型

Q1:在Python中如果我想表示字母怎么办呢?
Q2:在Python中有东西既可以放字符串又可以放数值吗?
Q3:字符串和元组不可变,那如果一定要改变呢?
Q4:不同的序列类型可以相互转化吗?
Q5:列表和元组有什么区别呢?

1.字符串:

Q1:字符串也可以像其他数据类型一样进行增删改吗?
Q2:如果可以的话,那是要用什么方法呢?
放字母单引号和双引号没有实质区别

a = 'abc' #字符串(string)
print(a)

1. 字符串的增删改查

#增
# 字符串拼接  +
a = 'hello'
b = 'world'
print(a+b)

#删
st3 = 'asdasdasdwqezc'
print(st3.replace('q','uuu')) #有内容时表示替换
print(st3.replace('q',''))  #为空格时表示删除

#改
st2 = '  asdasd  asdwqezc  '
print(st2.upper())  # 转化为大写
print(st2.lower())  # 转化为小写
print(st2.lstrip()) #去掉左边的空格
print(st2.rstrip()) #去掉右边的空格
print(st2.strip()) #去掉全部空格
print(st2.capitalize()) #首字符大写
print(st2.title()) #每个单词首字母大写
print(st2.split('s')) #切割,以s切割

#查
st = 'asdasdasdwqezc'
print(st.count('a')) # count 计数
print(st.index('s',3)) #查询元素索引,3表示从索引为3的开始查找
print(st.find('a',9)) #查询元素索引,可返回负数值
print('123'.isdigit()) #判断全部为数字
print(st.isalpha()) #判断全部为字符
print(st.endswith('a')) #判断最后一个字符是什么
print(st.startswith('a')) #判断最开始的字符是什么
print(st.islower()) #判断字符串内所有内容是否为小写
print(st.isupper()) #判断字符串内所有内容是否为大写

2.字符串的转义

字符前面加上 \ ,字符就不再表示字符本身的意思,表示ASCII码中不能显示字符,常见有下:

\n    换行
\t    水平制表符
\b    退格
\r    回车,当前位置移到本行开头
\\    代表反斜杠 \
\’   代表一个单引号,同样的"等符号也可以这么输出
\0    代表一个空字符
\a    系统提示音

在python中如果要去掉字符串的转义,只需要在字符串前面加上r’asd\aqwe’(在后面文件那一章的时候大家会看到详细用法)

print('asd\nqwe') #换行
print('asd\tqwe') #水平制表符(相当于加空格)
print('asd\bqwe') #退格(删除前面一个)
print('asdqzxc\rwe') #回车
print(r'asd\aqwe') #去掉字符串的转义

3.字符串编码

Q1:上面我们知道了了在python内部要对字符串进行是为了输出和传输,那python中字符串的可以直接在网络上传输吗?
Q2:如果不可以的话,python内部是怎么做的呢?

a = '张三'.encode(encoding='UTF-8') #编码
b = '张三'.encode(encoding='gbk')
print(a)
print(b)
print(a.decode())
print(b.decode(encoding='gbk'))
字符串编码的作用

Python统一了编码,这样Python在内部处理的时候不会因编码不同而出现程序不能正常执行的问题。
Python会自动根据系统环境选择编码,但是经常在文件传输的过程中,
会遇到各种不同的编码,这个时候就需要我们去处理编码问题。

4.字符串的拼接

st = 'hello'
st1 = 'world'
st2 = 'zs'
st3 = '20191216'
#1.拼接
#(1).使用 +
print(st+st1+st2)

#(2).格式化字符串 : ' %s %s %s '%(str1,str2,str3)
a = '%s %s %s'%(st,st1,st2)
print(a)
b = '%s年%s月%s日'%(st3[0:4],st3[4:6],st3[6:8])
print(b)

#(3).使用join : ’’.join([str1, str2, str3])
c = ' '.join([st,st1,st2]) #''中写什么就拼出什么,不止字符串()元组和[]列表都可以
print(c)

# (4).使用 format
#     ' {} {} {} '.format(obj1,obj2,obj3)
#     ' {0} {1} {2} '.format(obj1,obj2,obj3)
#     ' {1} {0} {2} '.format(obj1,obj2,obj3)
#     ' {n0} {n1} {n2} '.format(n1=obj1,n0=obj2,n2=obj3)
d = '{}{}{}'.format(st,st1,st2)
e = '{1}{0}{2}'.format(st,st1,st2) #数字表示索引
f = '第一句{} 第二句{} 第三句{}'.format(st,st1,st2)
g = '{n1} {n2} {n3}'.format(n1='a',n2='b',n3='c')
print(d)
print(e)
print(f)
print(g)

5.字符串格式化

print('%d'%123)  #%数字 只留整数部分
print('%f'%123)  #%浮点数
print('%6.3f'%10.2)  #%总共6位,小数点后面3位
print('%-16.3f'%10.2)  #%左对齐
print('%s'%'asd')  #%字符串                  掌握
print('%r'%'asd')  #%字符串(有引号)          掌握
print('%5s'%'123')  #%格式化长度
print('%c'%65)  #%ASCLL字符
print('%o'%9)  #%8进制
print('%x'%17)  #%16进制
#format
print('{:.2f}'.format(12.456)) #2表示保留小数点后两位
print('{a:.4f}'.format(a = 12.456))
print('{:.3%}'.format(0.228)) #百分比格式,3表示保留小数点后面3位
print('{:o}'.format(9)) #o为8进制,x为16进制,b为2进制
print('{a:<10}'.format(a = 12.333)) #左对齐,长度为10
print('{a:c<10}'.format(a = 12.333)) #< 左对齐,长度为10,用c替换
print('{a:c>10}'.format(a = 12.333)) #> 右对齐,长度为10
print('{a:c^10}'.format(a = 12.333)) #^中间对齐,长度为10

2.列表

什么都可以放
Q1:前面我们知道了怎么对列表的取值,那有什么方法对列表进行操作呢?
Q2:列表除了增删改查还有没有其他的方法?

li = [1,2,3,True,'a','b'] #列表(list)
print(li)

1.列表的增删改查

#增
    # append 追加
    # insert 插入
    # extend 添加序列(迭代)
a = [1,2,3,4,5]
a.append('a') #追加
print(a)
a.insert(2,'b') #插入,2是索引,'b'是插入的值
print(a)
a.extend([6,7,8]) #添加序列类型(只能是序列类型 元组,列表,字符串)
a.extend((9,'c'))
a.extend('def')
print(a)
#删:
    # pop 删除对应索引
    # remove 删除对应元素
    # clear 删除所有
a.pop(0) #删除对应索引,如果括号里面没有值默认删除最后一位
del a[0:2] #同上,但是可以删除多个。可以索引,可以切片
print(a)
a.remove('f') #删除对应元素,若有相同的默认删除第一个
print(a)

#改:
li[0] = ' list '
a[0] = 1
print(a)

# 查:
print(a.index(4)) #查询索引位置.相同的默认第一个
print(a.count(6)) #查找出现次数

2.其他方法


#     copy 复制
#     reverse 逆序
#     sort 正序
b = a.copy() #复制
c = [1,9,8,6,7,2,3,5,4]
c.reverse() #逆序
print(c)
c.sort() #只能同种类型间进行排序
print(c)
c.reverse()
print(c)

3.元组

Q1:元组有哪些方法呢?
什么都可以放

tu = (1,True,'啦啦啦',(1,2),[4,5]) #元组(tuple)
print(tu)

1.元组的方法

(元组不可直接变,如果需要改变,转化成列表即可,元组中只有 count 和 index 方法,方便查找元组中的数据)

# 查:
tu = (1,1,2,3,4,4,4,5,6,'a','b')
print(tu.index('a')) #查询元素索引
print(tu.count(1)) #计数

2.强制转换,查看内存地址

tu1 = list(tu) #强制转换为列表
print(type(tu1))
print(id(tu1)) #查看内存地址

4(*).bytes二进制序列类型

Q1:Python中的序列类型还有吗?
bytes和bytearray

a = bytes(3) #3表示二进制对象的长度,以0填充字节对象
print(a)
print(a[0]) #可以用切片索引取值,故也是序列类型
b = bytearray(3) #指定长度的零填充字节对象
print(b)
print(bytearray(b'abc'))  #二进制字符串对象

5.序列类型的取值(索引取值,切片)

li = [1,2,3,True,'a','b'] 
print(li[1]) #取里面的值,索引下标从0开始
print(li[0:2]) #取一段的值,切片(左闭右开)
print(li[0:6:2]) #间隔取值,2表示步长(即从1开始走2步)
print(li[6:0:-2]) #倒序取值,
 print(li[-1])  #从后往前取值

三、散列类型

1.字典:

Q1:在Python中有键值对这样的数据类型吗?

键值对,成对形式出现

唯一性:键不能重复,值能重复,
有序性:通过键找到对应的值,
可变性:键是不可变的,但字典是可变对象。

1.两种定义方式(直接定义或者使用dic函数)

di = {'name':'李四','sex':'男'} #直接定义
print(di)
print(type(di))
print(di['name']) #通过键可以找到值

di1 = dict(a=1,b=2,c=3,d=4,e=5) #通过dict函数
print(di1)

2.修改和删除

di['name'] = '张三' #有键值对就修改,没有就增加
print(di)
di['age'] = 18
print(di)

3.字典的增删改查

#增
di2 = di.copy() #直接增加一个新的字典
print(di2)
print(di.setdefault('name')) #有则查找,无则增
di.setdefault('身高','170')
print(di)
#删
di1.pop('a') #指定删除
print(di1)
di1.popitem() #随机删除
print(di1)
di1.clear() #全部清空
print(di1)
#改
di.update({'name':'王五'}) #有则改,无则增
print(di)
di.update({'体重':108})
print(di)
#查
print(di1.get('a')) #根据键找到值,同di['a']
print(di1.keys()) #查找全部键
print(di1.values()) #查找全部的值
print(di1.items()) #查找所有键值对的形式,然后放在列表里面

2.集合:

Q1:上面学习的列表中可以插入重复的元素吗?

唯一性:自动过滤重复的元素;
无序性:不能用索引取值;
可变性:set集合是可以改的

1.两种定义方法(直接定义;类型转化)

s1 = {1,2,3,4,5,6} #直接定义
print(type(s1))
li = [1,1,2,2,2,3,3,7,7,8,8,8]
s2 = set(li)  #强制类型转换
print(s2)

2.三种运算(交,并,差)

print(s1 & s2) #交集
print(s1 | s2) #并集
print(s1 - s2) #差集

3.集合的增删改查

#增
s1.add('a')#增加数字,中文都可以,但是不能加多个。根据ASCLL码表排序
print(s1)
#删
print(s1.pop()) #只能依次删除,不能通过下标删除。即不能填索引和特定值
print(s1)
s1.remove('a') #可以删除特定的值
print(s1)

#改
s1.update({1,'q'}) #更改集合,可以添加多个
print(s1)

#查
print(s1.isdisjoint(s2)) #有交集返回F
s3 = {1,2,3}
print(s3.issubset(s1)) #是否包含于(被包含)。s3是否全部在s1里面
print(s2.issuperset(s3)) #是否包含。s3是否全部在s2里面

3.数据类型中的可变和不可变

数值类型,序列类型,散列类型统称为数据类型
不可变的有:tuple(元组),string(字符串)
可变的有:list(列表),dictionary(字典),set(集合)

四、深浅复制

Q1:列表里面可以放列表吗?
深浅复制只有在列表嵌套列表的情况下讨论
浅复制第一层不会受到原来列表的影响,内层会被影响,深复制都不会受影响

1.浅复制

a = [1,2]
b = [3,4]
c = [a,b] #嵌套列表,只能在列表
a[0] = 111

li = c.copy() #与c中元素一样  也可写成copy.copy(c)
print(a)
print(c)
print(li)
print(id(c[0]))
print(id(li[0]))
import copy
c[0][0] = 123
print(c)
print(li) #浅复制的li变了
print(a) #但是a不变

2.深复制(相当于创建了一个新的内容)

import copy
li = copy.deepcopy(c)
a[0] = 789
print(a)
print(c)
print(li) #改变了a[0]但是深复制后的li保持原来不变
print(id(li[0])) #深复制ip与原来不同
print(id(a))
print(id(c[0]))

五、逻辑运算符

Q1:如何判断两个对象相同呢?
Q2:如何表示多个相同的条件呢?
Q3:Python中又有哪些运算符?

1.查看对象类型

print(isinstance(123,int)) #object.对象类型   还有type(object)

2.比较运算符

== 等于 ,!= 不等于,>= , <=,> ,<
如果有多个条件:
判断语句1 and 判断语句2 (两边都为真)
判断语句1 or 判断语句2 (两边至少有一边为真)
not 判断语句1

print(not 1==2 and 2==2 or 1==2) #从后往前(从右往左)看or为真,and为假,not就为真。优先级not > and > or

3.运算符的优先级

** (幂运算)
+、- (一元运算符(正负号))
%、/、* 、+、-(算术运算符)
<、>、<=、>===、!= (比较运算符)
=、/=、-=、+=、*=、%=、**=、//= (赋值运算符)
not > and > or (逻辑运算符)

a = [1,2,3]
b = [1,2,3]
print(a is b)  #(身份运算符) is , is not,根据ID(内存地址)判断
print(a[0] is b[0])

print(1 in a) #(成员运算符) in , not in

六、练习

  1. 定义一个列表,列表中有四种 数值类型,用多种方法取到第二个值
    定义一个元组,用多种方法取到最后一个值。
  2. 有一个时间形式是(20190311),要求从这个格式中得到年、月、日。
  3. 有一个列表[1,5,3,7],请用把下标为3的值改成2,再用列表的方法将列表改成[1,2,3,4,5]。

二、控制流程

一定要注意缩进!!!一定要注意缩进!!!一定要注意缩进!!!(重要的事情说三遍!!!)

一、条件判断

Q1:py文件中的代码是按照怎样的顺序执行的呢?
Q2:代码的执行顺序可以改变吗?如果可以要怎么改变呢?

1.语法结构:

if  判断语句1:

执行语句1
elif  判断语句2:
执行语句2
…
else:
执行语句

或者

age = 18:
if  age <= 18:
print( '未成年')
else:
print('已成年')

当多重判断时用elif,只有一个判断时用else
下面给大家举个例子

a = input("输入你的成绩:") #接收到的都是字符串类型
a = int(a) #要转化为整型,才能和数字比较
if a<60:
    print("不及格")
elif a>=60 and a<70:
    print("及格")
elif a>=70 and a<80:
    print("良好")
elif a>=80 and a<=90:
    print("优秀")
else:
    print("完美")

二、三目运算

Q1:有这样一个判断,如果值大于5返回True,否则返回False,代码该么写?
Q2:有更加简单点的方式吗?

一般只做简单的运算

a = 3
print(True) if a>5 else print(False)
#意思就是:如果a>5就输出True否则就输出False
#等同于
a = 3
if a>5:
    print(True)
else:
    print(False)

三、条件循环

1.语法规则:

Q1:对于刚才值大于5的三目运算,如果是判断一个列表中数字该怎么做呢?

while 判断语句:
循环体
改变变量

 while  判断语句:
 循环体
 改变变量
i = 0
while i<10: #三要素。一:循环的判断条件
    print(i) #二:循环的循环体
    if i == 5:
        break #终止、跳出循环
    i += 1  #i = i+1。三:结束循环的语句(改变变量)

2.break 和 else的用法

Q1:在上面的基础上增加条件,如果出现数字5就终止循环?

1.break的用法:

break可以在没有终止条件的情况下结束循环

li = [1,  5,  6,  9,  3,  2]
i = 0
while  i < len(li):
    if  li[i] == 5:
        break
    print((True) if li[i] > 5 else  False)
    i += 1
print(len(li))

2.else的用法:

else只有在循环被终止条件终止的情况下才会执行

i  =  0
while i < len(li):
    print((True) if li[i] > 5 else False)
else:
    print('判断结束') #这个输出是死循环

循环可以被终止:

   1. 判断语句可以返回  False

   2. 通过break终止循环 

else的执行条件:

   只有在循环不是被break终止的情况下才会执行else中的内容

四、迭代循环

Q1:对于刚才列表的例子,有没有更加便捷的方法取出列表中的元素呢?

1.for迭代

for 后面需要接上可迭代对象,for会依次取出可迭代对象中的元素
语法规则:

 for  i  in  obj:
 循环体
li = [1,2,5,6,8,9]
for i in li:
    print(i) #循环体

2.range和continue

Q1:要求打印出1-20内的整数?
Q2:在上面的基础上增加条件,如果是5的倍数就跳过,不打印出来?

range的用法:

for  i  in  range(21):
    print(i)

continue的用法:
continue和break类似,但是continue不会终止循环,而是结束本次循环,跳到下次循环

for  i  in  range(21):
    if  i % 5 == 0:
            continue
    print(i)
else:
    print('输出结束')
for i in range(1,21,1): #从1开始循环,循环20次,间隔为1
    if i%5 == 0: #除去5的倍数
        continue #跳出本次循环,继续下一次
    print("这是第"+str(i)+"圈")
else:
    print("循环结束")

五、练习

打印9*9乘法表

三、函数

一、函数基础

Q1:前面我们是不是在用过type()、id(),那这是什么呢?
Q2:那函数是怎么定义,怎么使用的呢?

1.函数名命名规则

字母、数字和下划线组成,和变量命名规则一致

2.函数定义

def  函数名(参数):
    pass
    return    表达式

return 后面可以返回任意表达式,但不能是赋值语句
pass在这里表示什么都没有,不执行任何操作
下面是一个例子供大家参考:

def a(x,y):     #括号里可以写参数,可以是一个也可以多个
    pass       
    return 20,y 
b = a(123,456)  #return要用一个变量名(这个例子中变量名为b)接收
print(b) #输出结果为(20,456)

如果return的x是一个固定的值,那么不管b=a(x)中x输入多少,打印出来都是这个固定值,return多少就打印出来多少

3.函数调用

函数名(参数)
def a(x): #括号里面可以写参数
    print(x) #里面不写会报错

a(3) 

4.print 和 return的区别

return是函数的返回值,返回值可以赋值给变量,而print只是打印出来

二、函数参数

Q1:前面我们学会了函数定义,是不是有个参数,那函数参数是什么呢?

1.必备参数

在函数调用的时候,必备参数必须要传入

def func(x): #位置参数
    print(x)

func(3)

2.默认参数

默认参数要位于必备参数列表的后面。在函数调用的时候,默认参数可以不传入值,不传入值时,会使用默认参数

def func1(a,b = 12):  #设定b默认为12
    print(a,b)

func1(5)  #后面的可传可不传,不传就是默认参数,传就是传多少是多少
#输出结果为(5,12)

3.不定长参数

不知道自己传多少个参数的时候用。在函数调用的时候,不定长参数可以不传入,也可以传入任意长度。其中定义时,元组形式可以放到参数最前面,字典形式只能放到最后面

def func2(*args,**kwargs): #关键字参数:*args,**kwargs
    print(args)          #传除字典以外的其他
    print(kwargs)        #传字典

func2(1,2,[3,4],(5,6),a=1,b=2,c=3)   #可以传多个

4.定义参数和参数的调用

在python中参数 无类型,参数可以接受 任意对象,只有函数中代码才会对参数类型有限制

1.定义参数

必备参数
默认参数
不定长参数

2.参数的调用

位置参数(传的必备参数就是位置参数)
关键字参数(*args和*kwargs)

三、内置函数

1.内置对象查看

Q1:Python中有哪些内置函数呢?

print(dir(__builtins__))       #查看所有内置函数的方法

2.常见函数

li = [1,5,2,3,6,5,8,9,7]
print(len(li))                             #len:求元素长度
print(max(li))                            #max:求最大值(只能数字)
print(min(li))                            #min:求最小值(同上)
print(sorted(li))                         #sorted:排序
print(list(reversed(li)) )                #reversed:反向(但是不会排序),(reversed(li))返回的是对象,要用列表接收。
print(sum(li))                            #sum:求和

3.进制转换函数

print(bin(3))                   #转为二进制
print(oct(9))                   #转为八进制
print(hex(19))                  #转为十六进制
print(ord("a"))                 #字符转ASCII码
print(chr(65))                  #ASCII码转字符

4.高级内置函数

#1.enumerate:返回一个可以枚举的对象(通过下标的索引和对应的元素)
li = ['a','b','c','d']
print(list(enumerate(li))) #(enumerate(li))返回的是对象,所以要用数据类型来接收
#输出结果为   [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]


#2.eval:取出字符串中的内容;将字符串str当成有效的表达式来求指并返回计算结果
a = '1+2+3+4'  #只能是输入数字才可以进行加减
print(a)
print(eval(a))

#3.exec:执行字符串编译过的字符串
j = 1
i = 2
exec('a = j+i')
print(a)

#4.filter:过滤器
def func(x):
    return x>10

li = [1,5,6,16,89,235,468]
a = filter(func,li)
print(list(a))

#5.map():对于参数iterable(可迭代)中的每个元素都应用fuction函数,并将结果作为列表返回
def func(a):
    return a*10

li = [1,2,3,8,9,16,56,89]
print(list(map(func,li)))
#输出结果为:  [10, 20, 30, 80, 90, 160, 560, 890]


#6.zip:将对象逐一配对
li1 = [1,2,3]
li2 = ['a','b','c']
a = zip(li2,li1)
print(dict(a))
#输出结果为:  {'a': 1, 'b': 2, 'c': 3}

四、匿名函数

Q1:上面的filter函数,可以过滤出列表中大于3的数据,但是使用都需要提前定义一个函数,有没有更加简便的方式呢?
语法规则:

lambda   参数 : 表达式 
不用def定义
f = lambda a:a*10 
print(f(2))

print(list(filter(lambda x:x>3,[1,2,3,4,5,6,7,8,9]))) #过滤器

类似于filter、map等函数里面,可以使用匿名函数来处理

五、函数作用域

Q1:在函数里面也有可以定义变量,那函数里面的变量名如果和函数外面的变量名重名,会相互影响吗?

1.函数内部

函数内部的变量,作用域只在函数内部:
1.函数内部不可以直接更改函数外部的变量
2.函数内部能够访问函数外部变量
3.函数里面不能修改函数外部变量
4.函数里面和函数外部变量名相同

def func():
    name = 'tf' #局部变量只能在函数里面使用,不能在外面用
    return name

a = func()
print(a) #不能直接print(name)

2.global

修改全局变量。函数内部如果需要改变全局变量,就需要使用global修饰变量

a = 100      #全局变量(写在函数外部)
def func1():
    global a
    a = 200
    print(a)

func1()
print(a)

3.nonlocal

修改局部变量(用在局部作用域里面)。使用nonlocal就可以在里层函数内部修改外部函数变量

def func1():
    x = 123
    def func2():
        nonlocal x #内层要使用外层的时候先定义局部变量
        x = x+100
        return x
    return func2()
    print(x)
a = func1()
print(a)

在函数嵌套函数的情况下,同样也有函数作用域的问题,但是python3中提供了方便,只需要使用nonlocal就可以在里层函数内部修改外部函数变量

六、闭包

Q1:函数里面可以再定义函数,那函数里面定义的函数可以在外面调用吗?
Q2:如果可以的话,要怎么做呢?

函数里面嵌套函数,外层函数返回里层函数,这种情况称之为闭包。
闭包是概念,不是某种函数类型,和递归的概念类似,就是种特殊的函数调用
闭包可以得到外层函数的局部变量,是函数内部和函数外部沟通的桥梁

1.内嵌函数

def func():
    print("这是func在调用")
    def func1():
        print("这是func1在调用")
    func1()

func()

2.闭包

def func():
    def func1():
        return 'a'
    def func2():
        return 'b'
    def func3():
        return 'c'
    return func2   #返回的是函数体不是调用,加()表示调用

a = func()()      #func()相当于return返回的值,要调用就再加()
print(a)

七、递归和回调函数

Q1:函数里面可以自身调用自身吗?

1.递归

函数自身调用自身,但是使用时类似于条件循环一样。
使用递归时,常常可以让代码更加简洁。
递归会占用比较多的内存,当递归次数比较多时,性能就会降低,因此不建议多使用递归。要有递归的终止条件(次数不能太多否则会卡死)

def func(n):
    if n==1:  #递归函数的终止条件
        return 1
    return func(n-1)*n

a = func(3)
print(a)

2.回调

回调函数: 自身是一个函数,只是被传入到另一个函数当中,供其调用
回调函数不一定会被调用,是否调用由被传入函数的内部逻辑决定

def func(n,m):
    if m == 2:
        n() #表示函数的调用
    else:
        print("aaa")

def a():
    print("我是a")

def b():
    print("我是b")

func(a,2)
#输入的值若为2就输出另一个函数的值,如果不是就输出自身函数的值

八、练习

1.定义一个函数,可以对传入的数据进行排序,通过一个参数来决定是正向排序还是反向排序。
2.定义一个函数,传入一个字典和一个元组,将字典的值(key不变)和元组的值交换,返回交换后的字典和元祖。

四、类

一、类定义

Q1:之前我们在数据类型里面知道了列表的方法,那是怎么做的可以让列表里面放下这么多方法呢?

1.命名规则

驼峰命名:首字母大写

例如:Person
或者ZhongGuo

2.类的定义和实例

1.类的定义:

 class 类名:
 pass     

类是一个独立存放变量(属性/方法)的空间

2.实例名 = 类名()

实例也是一个独立存放变量的空间
下面给大家一个例子来理解:

class Person: #驼峰命名,首字母大写
    var1 = '我是直接封装在类中的方法'
print(Person.var1)

Person.var2 = '我是后来封装在类的方法'
print(Person.var2)

zs = Person() #实例化(可以直接使用类里面的方法),zs就是Person的一个实例
print(zs.var1) #调用属性
print(zs.var2) #调用属性


ls = Person()
zs.name = '张三'
print(zs.name) #正常调用
print(Person.name) #报AttruibuteError,在类中找不到这个属性
print(ls.name) #报同样错误,类和实例中都找不到
#首先就会调用自身,如果没有自己赋值就会从类里面找(即实例中找不到就会转到类中查找)

运算符“.”表示调用类的属性或方法

3.类和实例的关系

***类是一类事物的抽象,不是真是存在的。描绘了该类事物的共性,例如:“人”、“动物”、“家具”。
实例是某类事物的具体个体,是该类事物的具体表现,它是真实存在的。例如:“张三”是具体的某个“人”,“李四”也是具体的某个“人”。***

3.属性和私有属性

一个“实例”的“特征”,就是“属性”。变量在类中称为属性,但是类中的属性不仅仅只包含变量,函数等其他的对象也可以作为类的属性
在python中有两种私有属性,分别是在属性前加 一个下换线(_) 和 两个下划线(__)一个下滑线外部可以直接访问,二个下划线外部不可以直接访问

class Person:
    name = '张三'
    running = '跑步'
    _age = 18  # 私有属性
    __sex = '男' #私有属性
# 属性不需要+self,方法里要使用类里面的属性的时候才需要用self.
    def eat(self):
        print(self.name + "正在吃东西")
    def run(self,a): #也可以定义变量名
        print("我正在"+self.running,a)

zs = Person()

print(zs._age) #(_)可以直接访问
print(zs.__sex) #不可以直接访问
print(dir(zs)) #用dir才能找到这个私有属性
print(zs._Person__sex) #才能调用(__)
#在 Python 中, _  和  __  的使用 更多的是一种规范/约定,没有真正限制的目的,定义在类中的私有属性也可以被子类继承

二、方法

Q:类里面除了放属性之后,还可以放些什么呢?
“方法”就是封装在类里的一种特殊的函数

1.实例方法

“实例方法”表示的是“实例”的行为,和函数的传参一样,只是会先传一个自身的实例self。下面给大家一个例子

class Person: #驼峰命名,首字母大写
    name = '张三'  #属性(一个实例的特征:有眼睛鼻子等)
    def eat(self): #方法(行为:吃饭 讲话等),不是函数,叫方法
        print(self.name+"正在吃东西") #self表示实例本身,有name这个是属性

zs = Person()
print(zs.name)
zs.eat()

2.“实例方法” 的调用过程与 self

通常,将默认会传入的那个参数命名为self,用来表示调用这个方法的实例对象本身。方法总是定义在类中的,但是却叫“实例方法”,因为它表示该类所有实例所共有的行为。
用上面的例子说明就是:吃是定义在类中,正在吃东西是该类所有实例的共有行为。

三、初始化,析构

Q:在刚才实例化之后才添加 实例属性,那有没有办法在实例化的时候就添加实例属性呢?

1.初始化

在Python中有很多以双下划线开头且以双下划线结尾的固定方法。
他们会在特定的时机被触发执行。_ _ init _ _ 就是其中之一,它会在实例化之后自动被调用,以完成实例的初始化。

class Person:

    def __init__(self,name,age,sex):
        self.name = name #将外部传进来的name赋值给实例本身的name
        self.age = age
        self.sex = sex

zs = Person('张三',18,'男') #实例化一个对象,需要传进去参数
print(zs.name)
print(zs.age)
print(zs.sex)

2.析构

基于变量计数的对象销毁机制
当没有一个变量指向某个对象的时候,Python会自动销毁这个对象,以便回收内存空间。
del 关键字,可以删除一个变量的指向。"_ _ del _ _"就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数。提示开发者,对象被销毁了,方便调试。进行一些必要的清理工作。

class Person():

    def __init__(self,name): #初始化
        self.name = name

    def __del__(self):  #析构方法(销毁方法)
        print(self.name,'被销毁了')
zs = Person('张三')
del zs #打印出被销毁

四、继承

Q1:前面我们学习过类的初始化方法,如果定义一个空的类它是不是也可以实例呀?这是为什么呢?

1.继承

当两段代码有大量重复的内容,就可以抽象出一个更抽象的类放公共代码。继承的意义就是重用代码,方便代码的管理和修改。
下面就是一个例子:

class GrandFather():
    def play(self):
        print("我是爷爷")

class Father(GrandFather):
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def play2(self):
        print("我是爸爸")

class Son(Father): #继承。父类里面有的方法子类里面都可以去调用
    def js(self):
        print("我叫%s,我今年%s"%(self.name,self.age)) #%字符串拼接

s = Son('张三',18) #子类可以用父类,但是父类不能用子类的
s.js()
s.play() #如果找不到,转到其父类中查找。如果再找不到,转到其父类的父类(即间接基类)中查找。
print(GrandFather.__bases__)  #查看直接父类如果只加()默认是继承顶级基类object

2.多继承

Q1:刚才讲到了继承,一个类可以继承一个类,继承之后可以使用父类的方法和属性,那一个类可以继承多个类吗?
Q2:如果可以继承多个类的话,那如果两个父类中有一样的方法的情况下,子类继承哪一个呢?
一个类继承多个类
object是所有类的父类

class Grandfather():
    def func(self):
        print("我是爷爷")
    def run(self):
        print("我运动跑步")

class Father(Grandfather):
    def func(self):
        print("我是爸爸")
    def money(self):
        print("我赚钱养家")

class Mother(Grandfather):
    def func(self):
        print("我是妈妈")
    def work(self):
        print("我洗衣做饭")

class Son(Father,Mother): #如果继承多个基类,先从第一个找
    def func(self):
        Father.func(self)  #当子类重写父类方法之后,子类再次调用父类。(或者super().func())
        print("我自己")  #当子类继承父类之后,如果子类不想使用父类的方法,可以通过重写来覆盖父类的方法

s = Son()
s.func()
s.work()
s.run()
print(Father.mro()) #可以通过调用类的__mro__属性或者mro方法来查看类的继承关系
print(Father.__mro__)

1.多继承方法

Q1:重写父类方法之后,如果又需要使用父类的方法呢?

  • 方法一:

    class C(A, B):
    	def play(self):
    
     A.play(self)
     print('这是C')
    
  • 方法二:

    class C(A, B):
    def play(self):
    
    super().play()
    print('这是C')
    

2.super()的用法

super 函数可以调用父类的方法,在父类中也可以使用super函数,使用super的好处在于即使父类改变了,那么也不需要更改类中的代码
super用法如下所示:

class Base:
    def play(self):
        print('这是Base')
        
class A(Base):
    def play(self):
        super().play()
        print('这是A')
        
class B(Base):
    def play(self):
        super().play()
        print('这是B')
        
class C(A, B):
    def play(self):
        super().play()
         print('这是C')

五、魔法方法(魔术方法)

Q:说到字符串拼接的时候,字符串可以直接相加,那我们自定义的类可以实现吗?

在类中,很多事情其实调用的魔术方法来实现的,通过合理的利用魔术方法,可以让我们更加方便的展示我们的数据。

1.运算方法

运算符方法(了解即可)

__add__(self,other)		# x+y
__sub__(self,other)		# x-y
__mul__(self,other)		# x*y
__mod__(self,other)		# x%y
__iadd__(self,other)	# x+=y
__isub__(self,other)	# x-=y
__radd__(self,other)	# y+x
__rsub__(self,other)	# y-x
__imul__(self,other)	# x*=y
__imod__(self,other)	# x%=y

Q:自定义的类如何实现字符串拼接?
A:用魔法方法__add__
下面是一个例子:

class Rectangle:

    def __init__(self,length,width):
        self.length = length            
        self.width  = width  

    def area(self):        
        areas = self.length * self.width        
        return areas

    def __add__(self, other):        
        add_length = self.length + other.length        
        add_width  = self.width + other.width        
        return add_length,add_width

a = Rectangle(3, 4)
b = Rectangle(5, 6)
print(a + b)
#输出(5,7)

2.str和repr原理

str和repr方法在处理对象的时候,分别调用的是对象的__str__和__repr__方法print打印对象,调用str函数,如果对象没有定义 __ str __ 方法,则调用 __repr__方法处理。
在交互模式下(IDLE或者CMD中),直接输出对象,显示 _ _ repr _ _ 的返回值

class A():
    def __init__(self,name): #初始化方法
        self.name = name

    def __str__(self): #有str时先使用str方法
        return "222"

    def __repr__(self): #当没有str时,就使用repr方法
        return self.name #只能返回字符串

a = A('张三')
print(a) #当没有str和repr时,返回的是一个实例对象。需要给外面传值的时候就用两种方法之一

3._ _ call _ _方法

Q:类的实例可以向函数一样被调用吗?
A:正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 _ _ call _ _ 方法

class A():
    def __init__(self,name): #初始化方法
        self.name = name


    def __call__(self, *args, **kwargs): #可以传不定长参数
        return '1234'
        
a = A('张三')
print(a()) #调用call方法,就可以像函数一样被调用

4.类中的一些查询相关信息的方法(了解既可)

1、class 查看类名

格式:  实例.__class__

2、dict 查看全部属性,返回属性和属性值键值对形式

格式:实例.__dict__

3、doc 查看对象文档,即类中(用三个引号引起来的部分)

格式:类名.__dict__

4、bases 查看父类

格式:类名.__base__

5.mro 查看多继承的情况下,子类调用父类方法时,搜索顺序

格式:子类名.__mro__
实例.__class__.__mro__

六、__new__方法

Q1:我们创建实例是通过什么方法创建的呢?
Q2:类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
new 方法合理利用可以带来方便,常应用在类的单例模式。

1.__new__方法

四个点理解__new__方法

1、__new__方法是在类创建实例的时候自动调用的。
2、实例是通过类里面的__new__方法是在类 创建出来的。
3、先调用__new__方法创建实例,再调用 __init__方法初始化实例。
4、__new__方法,后面括号里的cls代表的是类本身
class Base:
    def __init__(self):
        print("我正在初始化")

    def __new__(cls): 
        print('cls',cls) #cls代表类本身
        print("我正在使用new方法")
        return object.__new__(cls)  #返回实例对象。如果有父类就用父类,没有就用object。(一定要写)

#实例的时候会先调用__new__方法,然后才调用初始化方法
a = Base()

new方法是在类实例的时候就调用,初始化在实例完之后再调用
在上面的例子中,我们可以看到创建实例的时候,自动调用了__new__,方法和__init__方法,并且是先调用的__new__再调用的__init__方法,打印 cls 的时候显示的这个Base类

2.单例模式

使用同一个实例,就不用占用另外的内存空间,最后实例化出来的实例指向同一个内存地址。
利用这个 new 可以很方便的实现类的单例模式

class Base:
    def __new__(cls):
        if not hasattr(cls,'instance'):  #有就查询,没有就增加
            cls.instance = super().__new__(cls) #给类里面的属性赋值。把调用父类的new方法返回给instance这个属性
        return cls.instance  #返回都是同一个

    def __init__(self):
        print("我正在初始化")

a = Base()
b = Base()
print(id(a),id(b))

七、定制属性访问

Q1:如何判断一个实例里面有某个属性呢?
Q2:怎样删除实例属性呢?
Q3:同样的怎样删除变量呢?

属性的增删改查

class Base:
    a = '123'

    def __getattr__(self, item):
        print("未找到该属性")

b = Base()
#增加
b.name = 'tf'
setattr(b,'bbb',222)  # 有bbb属性就改,没有就增
b.__setattr__('ccc',333)
print(getattr(b,'name'))
print(getattr(b,'bbb'))

#删除
delattr(b,'ccc')
b.__delattr__('bbb')
del b #析构


#修改
setattr(b,'bbb',6)
b.__setattr__('ccc',5) #设置属性

#查询
print(hasattr(b,'a')) #返回bool值。判断是否存在属性,如果属性存在则进行下一步操作
print(getattr(b,'a')) 	# 返回属性值
print(b.__getattribute__('a')) # 返回属性值(魔法方法)

八、描述符

Q1:如果在一个类中实例化另一个类,对这个属性进行访问的时候怎么做的?

描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问。这些方法有 get(), set(), 和__delete__()。如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符。

class A:
    def __get__(self, instance, owner):
        print("我正在调用get方法")

    def __set__(self, instance, value):
        print("我正在调用set方法")

    def __delete__(self, instance):
        print("我正在调用delete方法")

class B:
    a = A()
    def __del__(self): #执行完A中所有方法后会使用析构,释放空间
        print("我会在最后执行")
b = B()
b.a  #对于属性进行访问
b.a = 1 #修改就调用set
del b.a #删除就调用delete

描述符大家了解即可魔术方法的作用其实是让开发人员能够更加灵活的控制类的表现形式

九、装饰器

Q1:闭包中可以传入一个函数吗?
装饰器本质是函数,能够实现在不修改原来的函数的基础上添加功能。

1.基本装饰器

def func(f1):
    def func1():
        print("我是功能1")
        print("我是功能2")
        f1()
    def func2():
        print("我是功能111")
        print("我是功能222")
        f1()
    return func2

@func #装饰器就是在闭包的基础上
def f1():
    print("我是最基础的函数")

f1()

2.python自带的三个内置装饰器

class Base():
    age = 18
    def __init__(self,name,age):
        self.name = name

    def eat(self):
        print("正在吃东西")

    @property #相当于访问属性
    def run(self):
        print("正在跑步")

    @staticmethod #设置静态方法,与class类断开连接
    def work():  #用静态装饰器后,可以像使用函数一样使用类方法。(self在调用时就睡报错)
        print("正在写作业")

    @classmethod #类方法,cls代表类本身
    def show(cls):
        print(cls.age)

a = Base("张三",18)
a.work()
a.show()
a.eat()
a.run  #加了装饰器后可以不用加()

3.类修饰器

类也可以做装饰器,但是需要定义__call__ 方法

class Test_Class:
      def __init__(self, func):
      self.func = func
    
    def __call__(self):
      print('类')
      return self.func
@Test_Class
def fun_test():
    print('这是个测试函数')

4.装饰器参考(查看函数运行时间)

import time
def new_time(func):
    def run_fun(*args,**kwargs):
            t0 = time.time() #获取当前时间
            back = func(*args,**kwargs) #原函数的返回值
            runtime = time.time()-t0 #得到函数运行的时间
            print('函数运行的时间: %s'%runtime)
            return back #返回原函数的返回值
	    return run_fun

十、练习

1.定义个矩形类,有长和宽两个实例属性,还有一个计算面积的方法
2.在1的基础上,定义正方形类(继承矩形类)。实现类的实例可调用,调用时打印边长;同时,直接打印类实例时能够打印出实例的面积
3.测试type和isinstance两个函数,那个速度更加的快

五、文件

保存内存中数据都是易丢失的,只有保存在硬盘中才能持久的存储,保存在硬盘中的基本方法就是把数据写入文件中。

一、文件基本操作

Q1: 如何打开/关闭一个文件 ?
Q2: 如何读取/写入文件内容 ?
Q3: 如何以二进制来处理文件 ?

1.打开关闭文件

这里就要用到字符串转义的相关知识了

file = open(r'test.py','r',encoding='utf-8')  #打开文件(r前面防止转义,后面表只读。encoding表示读取格式)
print(file.read())
print(file.readline()) #只读取第一行。
a = file.readlines()  #读取全部添加到列表里面
print(a[0]) #可以索引取值
file.close()  #关闭文件,调用给定文件对象的close方法
#绝对路径:从根目录到文件
#相对路径:在同一文件夹时,就只需要文件名字
print(file.read())

一定要记得close!!!
下面是文件打开的一些模式:

其他模式:

rb   rb+     wb     wb+    ab    ab+ 
加个b的作用:以二进制的格式打开文件,进行上述操作 。

2.读取写入文件

读取/写入文件:

下面是代码演示:

file = open(r'test.py','w',encoding='utf-8')  #w表示写入
file.write('print(456)') #w覆盖之前内容写入新的内容
file.writelines(['hello','world']) #写入多个元素,拼接成字符串,覆盖之前的

file = open(r'test.py','r',encoding='utf-8')
print(file.read())
file = open(r'test.py','a',encoding='utf-8')
file.write('\nprint(789)')
file.flush() #保存
file.close() #保存后关闭
file = open(r'test.py','r',encoding='utf-8')
print(file.read())
print(file.tell()) #获取光标位置
file.seek(0) #把光标调整至文件开头

3.文件模式(默认)与二进制模式

文本模式:以str字符串形式写入,读取出来的也是str字符串

二进制模式:以bytes字符串形式写入,读取出来的也是bytes字符串

file = open(r'test.py','ab+')
file.write(b'12')
file.seek(0)
print(file.read())
file.close()

二、StringIO与BytesIO(内存模拟文件)

Q1:如何在内存中模拟一个文件 ?
Q2:它的操作和真的文件有差别嘛 ?
Q3:它的应用场景是 ?

import io
myio = io.StringIO()  #创建一个临时文件
myio.write('hello')
print(myio.getvalue())
myio.close()

bio = io.BytesIO() #创建一个二进制的临时文件
bio.write(b'hello')
print(bio.getvalue())

注:内存假文件一旦关闭,数据消失

三、上下文管理

Q1:既然文件一定要及时关闭,是否能够让Python自动执行这个关闭过程 ?
Q2:能否同时管理多个文件的自动关闭 ?
上下文管理的重点就是:

with … as …
# open相当于上文
# close相当于下文
with open('file_path','r+') as f1:  #上下文管理器
with open('file_path','r+') as f2   #可以多个文件
    file.write('print(222)')
    # 对f进行一系列操作
    # 也可以执行别的操作

# 跳出with语句快的时候自动执行f.close()

四、常见问题处理

Q1:如果我想指定编码来处理文件该怎么办 ?
Q2:能否能对文件或目录做一些基本的操作?

1.文件访问编码

1.open(file_path, mode='r', encoding=None)
2.open(file_path, mode='r', encoding=None, errors=None)
import os
print(os.path.join('python','jichuban'))
print(os.getcwd())

2.os模块

目录及文件操作:

3.os.path模块

路径操作:

五、练习

1.写一个简单的复制文件代码。
2.写一个用来遍历某目录所有内容的函数。

六、异常

一、异常(本身就是类)

Q1:什么是异常? python中有哪些异常?
Q2:如何通过程序的报错来找到有问题的代码?

1.常见异常举例



2.异常结构

Python的异常结构(基于继承)
在 Python 中所有的异常都是继承自 BaseException.直接分为四大类:

1.SystemExit:Python退出异常
2.KeyboardInterrupt: 键盘打断(Ctrl+C)
3.GeneratorExit: 生成器退出(下一节有)
4.Exception: 普通异常(只会使用这部分的异常)

二、异常处理

Q1:异常通常会带来怎样的问题 ?
Q2:我们如何能防止这个问题,从而利用异常 ?
Q3:具体的该怎么做 ?

1.基本处理

try … except …
try:   #把所有可能出现的代码,放到里面去
    print(132)
    print(a)
    print(456)
except:  #下面是写捕获到异常的处理方案
    pass

try 后面必须跟上 except

2.捕获具体的异常

except 后面可以写上捕获具体的异常类型,还可以通过as 把捕获的异常信息 储存到后面的变量里面

try:
    print(132)
    print(a)
    print(456)
except NameError as info:  #info只是变量名,可以随便命名
    print("这是你的错误原因")
    print(info)

3.捕获多种异常

这里就只告诉大家写法,下来自己练习

1.可以多写几个except
2.在except后面用括号把多种类型括起来

语法错误捕捉不了
如果是不确定异常类型:

try:
	pass
except Exception
	pass

1.关于 Exception 及其 子类 的解释

1.代码中会出现的异常都是 Exception 的子类, 因此在 except 中只需要在最后加上 Exception 即可
2.在捕获异常的过程中,会从上倒下依次对比异常,找到之后就不会再往后查找

2.关键字下的代码

1.try 下面放可能出错的代码
2. except try下面的代码出错后,会执行except下面的代码
3. else try下面代码没有错误, 执行else下面的代码
4. finally 不管try下面的代码有没有出错,始终都会执行

4.自定义异常类型

格式:

raise 异常类型
class ZdyError(Exception): #自定义异常必须继承于Exception
    pass

def func(name):
    if name == '张三':
        print("名字正确")
    else:
        raise ZdyError("名字错误")  #主动抛出 自定义异常

try:
    func("aaa")
except ZdyError as e:
    print(e)

三、断言

Q1:如何能在代码中强制要求一个条件满足 ?
Q2: 是否有专门的语法来完成 ?

断言语句是将调试断言插入程序的一种便捷方式assert 的语法规则是:

表达式返回 True  不报错,
表达式返回 False  报错  报 AssertionError
assert 1==1  #当后面判断的条件为T时不报错,继续执行代码
print(123)

断言在后期调试代码时会用到

四、练习

1.自己构造一个报错的场景,并进行一个报错分析(报错的类型,报错的原因,报错的代码,和报错的行)
2.结合异常处理,确保打开文件后的正常关闭(用open直接打开一个文件,然后write进行写入,假设在写入的时候可能会报错,写段代码确保 报错的情况下依然可以把文件关闭掉)

七、迭代器和生成器

一、推导表达式

推导表达式相对于for循环来处理数据,要更加的方便,列表推导表达式使用更加的广泛

Q:得到一个元素为1到9的列表,可以怎么做?

1.列表推导

列表推导式+条件判断:

li = [x for x in range(1,11) if x>2]  #生成1~10大于2的列表
print(li)

列表推导+三目运算:

#生成1~9 如果是3的倍数就*100 否则*10的列表
li = [i*100 if i%3 == 0 else i*10 for i in range (1,10)]
print(li)

2.集合推导

#生成1~9的整数 集合
se = {i for i in range(1,10)}
print(se)

3.字典推导

li = ['a','b','c']
dic = {i:j for i,j in enumerate(li)} #枚举:把每个元素的下标和元素相匹配。也可以用zip
print(dic)

二、迭代器

Q1:列表推导是往列表中一个一个地放入数据,那如果一个一个地取出数据呢?
Q2:for循环的运行机制是什么?
Q3:可迭代对象与迭代器的区别 ?

1.迭代

即:依次从数据结构中拿东西出来
迭代规则:

for 迭代变量 in 可迭代对象。

每一次循环都会自动让“迭代变量”指向“下一个元素” 。

#可迭代对象(有iter方法)

li = [1,2,3,4,5,6,7,8,9]
#for循环
for i in li:
    print(i)

#while循环
index = 0
while index<len(li):
    print(li[index])
    index += 1

2.迭代器

1.生成迭代器的方法:

1.iterator = iter(li)

2.iterator = li.__iter__()

2.迭代器协议:

迭代器对象本身需要支持以下两种方法,它们一起构成迭代器协议:

iterator.__iter__()

iterator.__next__()

3.取值

next(iterator)

iterator.__next__()

注意:如果迭代器值取完之后,会返回 StopIteration 错误

4.从可迭代对象生成一个迭代器

迭代器=iter(可迭代对象)
下个值=next(迭代器)

a = iter([1,2,3,4,5,6])  #iter表示可迭代

li = [1,2,3,4,5,6]  #魔法方法调用
a = li.__iter__()
print(next(a))
print(next(a))
print(next(a))
print(a.__next__())

3.for循环实现原理

li = [1,2,3,4,5]
li1 = iter(li)  #将可迭代对象转换成迭代器
while True:  #死循环(默认为真)
    try:
        var = next(li1) #一个一个的去取值
        print(var)
    except StopIteration:  #没有值可以取了就跳出循环
        break

4(*).自定义迭代器

即:重写iter方法(也可重写next)

class Mylist:
    def __iter__(self):
        return iter([1,2,3,4,5]) #返回的必须是一个迭代器(自己实现)

a = Mylist()  #实例化对象就是可迭代对象

for i in a:
    print(i)

三、生成器

1.生成器的方法

方法 一:列表推导式的 [ ] 改成 ( )

a = (i for i in range(1,11))
print(next(a))
print(next(a))
print(next(a))

方法二:在函数里面加上yield

def func():
    yield 1
    print(123)
    yield 2
    print(456)

a = func()
print(a)
print(next(a))
print(next(a)) #重新激活下次next

2.yield运行规则

yield 一个对象:

1.返回这个对象;
2.暂停这个函数;
3.等待下次next重新激活。

yield 表达式只能在函数中使用 ,yield 表达式可以使函数成为一个生成器,yield 可以返回表达式结果,并且暂定函数执行,直到next激活下一个yield,简单点理解生成器就是一个迭代器。
Python使用生成器对延迟操作提供了支持。所谓延迟操作,是指在需要的时候才产生结果,而不是立即产生结果,从而节省大量的空间,这也是生成器的主要好处。

3.生成器函数

def func(n,m):
    count = 0
    while True:
        if count<m:
            count+=1
            yield n #暂停以及恢复代码。每执行一次就返回一次
        else:
            break
aaa = func('存在',20)
print(aaa)
for i in aaa:
    print(i)

四、模块

Q1:什么是模块 ?
Q2:为什么需要导入别的模块 ?
Q3:导入的过程大致是怎样的 ?

1.模块概念

在python中,模块就是一个py文件,可以使用下面两种方法导入

import datetime
from datetime import datetime  (as this_datetime)

注意:datetiame是一个常用的时间处理模块

在同一目录下,可直接使用上面两种方法去导入;
在不同目录下,需要使用 sys.path 添加路径

sys.path.append('path')

在python3中导入后,会在当前路径下生成一个 pycache 文件夹

2.导入过程

import time #导入时间模块
print(123)
time.sleep(3)
print(456)

from datetime import datetime #导入一部分模块
print(datetime.now())

import test #同一目录下

import sys
print(sys.path)

五、包和包管理器

1.包概念

把很多模块放到一个文件夹里面,就可以形成一个包

2.包管理

当把很多模块放在文件中时,为了方便引用包中的模块,引入了包管理

3.__ init__.py模块

在包管理中,加入此模块,则包名可以直接通过属性访问的方式,访问此模块内的对象,此模块不加上可能不会报错,但是规范是要加上,文件内容可以为空。

4.相对路径导入

在包管理中,可分别来导入同层和上一层的模块以通过 . (一个点) 和 … (两个点)。

1.引入作用

在包中,如果包中模块要导入同一包中的其他模块,就必须使用此方法导入

2.使用方法

from  .module(..module)  import obj   (as  new_name)

3.引入影响

当一个模块中出现此导入方式,则该模块不能被直接运行,只能被导入。

六、练习

在一个模块中定义一个生成器,这个生成器可以生成斐波拉契数列,再另一个模块中使用这个生成器,得到斐波拉契数列。
斐波那契数列:数列中每一个数的值都等于前两个数相加的值[1, 1, 2, 3, 5, 8, 13, 21, 34, 55…]

八、正则

一、正则表达式概念

Q1:什么是正则表达式 ?
Q2:正则表达式主要解决什么问题 ?
Q3:在python中我们如何使用正则?

1.正则所面向的问题

1、判断一个字符串是否匹配给定的格式:判断用户注册帐号是否满足格式
2、从一个字符串中按指定格式提取信息:抓取页面中的链接

1.判断用户提交的邮箱的格式是否正确

一个或多个字母或数字@一个或多个字母或数字

import re
st = '123@163'
st1 = re.findall(r'^[a-zA-Z0-9]+@[a-zA-Z0-9]+\$',st)
print(st1)  #能匹配到就能输出列表。匹配失败返回空列表

2.抓取页面中特定部分数据

二、re模块

在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用一个模块来操作,名字为re

1.findall方法

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表

import re
st = '张三正在吃东西,吃得多'
st1 = re.findall('吃',st) #匹配所有,如果匹配不存在返回空列表
print(st1)

2.match方法

注意:match只能匹配到一个
可以通过group()提取匹配到的内容
可以通过span()提取匹配到的字符下标取值区间
这个同findall类似留给大家自己练习!

3.search方法

注意:search也只能匹配到一个,找到符合规则的就返回,不会一直往后找

#re.search 扫描整个字符串,匹配成功 返回的是一个匹配对象(这个对象包含了我们匹配的信息)
st = '张三正在吃东西,吃得多'
st3 = re.search('吃',st) #扫描字符串
print(st3)

4.替换(sub)

st = '张三正在吃东西,吃得多'
st4 = re.sub('张三','李四',st)  #替换所有
print(st4)

5.re.match与re.search的区别

re.match只匹配字符串的开始位置找,如果字符串开始不符合正则表达式,则匹配失败,
re.search:匹配整个字符串,如果一直找不到则,返回是空的,没有结果

三、元字符

即:本身具有特殊含义的字符。每一个符号本身具有特别的含义

Q1:什么是元字符 ?
Q2:常用元字符有哪些 ?
Q3:怎样才能匹配这些字符本身 ?

1.单字符匹配


下面几个例子供大家理解:

st = '张三正1在吃东西2,吃得多3'
st1 = re.findall('吃.',st)   # . 匹配任意一个字符(除了\n)
print(st1)
st2 = re.findall(r'[1]',st)   #匹配列举的字符(数字和字母都可以)
print(st2)

2.数量元字符

st = 'abbbbc'
st1 = re.findall(r'ab*c',st)
print(st1)
st2 = re.findall(r'ab+c',st) #b必须要出现至少一次才能匹配到
print(st2)
st3 = re.findall(r'ab+c',st)   #b必须要出现0次和1次才能匹配到
print(st3)
st4 = re.findall(r'ab{4}c',st)   #b必须要出现4次才能匹配到。也可以写范围{2,6}
print(st4)

3.边界元字符

st = 'abbbbc abbc abea'
st1 = re.findall(r'ea$',st) #匹配字符串结尾
print(st1)
st2 = re.findall(r'ea\b',st) #匹配一个单词的边界(空格)
print(st2)

4.分组匹配

st = 'hello123 hello321 world world123 world321 python python1 python321'
st1 = re.findall(r'hello|world',st)  #匹配左右任意一个表达式
print(st1)
st2 = re.findall(r'he(llo)',st)  #将括号中字符作为一个分组
print(st2)

5.贪婪与非贪婪

正则 默认都是用贪婪模式 去匹配数据的,就是尽可能多的匹配符合要求的数据,在非贪婪模式下, 始终找最短匹配

st = 'aaaaaaaaaaaaaaa'
st1 = re.findall(r'a{2,4}',st)
print(st1)
st2 = re.findall(r'a{2,4}?',st)  #加?变成非贪婪模式,找最短的匹配
print(st2)

以上代码我没有将输出结果返回出来,需要大家自己动手实际操作一下,这样才能深刻理解。Python的基础我能想到的差不多就这些了,写出来仅仅是为了记录,后期还会有Django和爬虫的相关内容。如对大家有帮助的话,不甚荣幸。欢迎大家留言纠正错误和交流,接收一切批评和建议(恶意抬杠请转战工地)。再次感谢CSDN平台!!!

更多推荐

Python基础以及常见问题的处理方式(附所有详细代码,欢迎留言交流和补充)