二、python学习-函数

类型判断

1.type()直接获取类型
2.isinstance
用法一:isinstance(值,类型) 返回真或假
用法二:isinstance(值,(类型1,类型2 ...)) 有一个类型满足 返回真

int float bool complex str list tuple set dict

1. 代码块

定义:以冒号作为开始,用缩进划分作用域
作用域:作用的范围

2. 单 双 多项分支

语法结构
单项:
if 判断表达式 :
    代码块
    
双项:
if 判断表达式 : 
    代码块 
else :
    代码块

多项:
if 判断表达式 : 
    代码块 
elif 判断表达式:
    代码块
elif 判断表达式:
    代码块
else 判断表达式:
    代码块

巢状分支:
if 判断表达式 : 
    if 判断表达式 : 
        代码块 
elif 判断表达式:
    if 判断表达式 : 
        代码块 
    else :
        代码块
else 判断表达式:
    代码块

3. 循环结构

3.1 while循环

语法结构:
while 判断表达式 :
    代码块

3.2 for循环

语法结构:
for ...  in 容器:
    代码块
   
range对象(配合for循环使用)
range(start,end,step)
start:  开始值
end:    结束值(最大值获取不到,获取到end-1)
step:   步长

3.3 pass,break,continue

  • pass : 通过当前逻辑
  • break: 循环结构中使用,结束当前层级循环
  • continue: 跳出当前循环

4. 字符串的相关用法

  1. 字符串的拼接
  2. 字符串的重复
  3. 字符串的跨行拼接
  4. 字符串的索引
  5. 字符串的切片: 语法=》字符串[::] 完整格式[开始索引:结束索引:间隔值]
    1. [开始索引:]从开始索引截取到字符串的最后
    2. [结束索引:]从开头截取到结束索引之前(结束索引-1)
    3. [开始索引:结束索引] 从开始索引截取到结束索引之前(结束索引-1)
    4. [开始索引:结束索引:间隔值] 从开始索引截取到结束索引之前按照指定的间隔
    5. [:] 或 [::] 截取所有字符串

4.1 相关函数

  • capitalize() 首字符大写
  • title() 每个单词首字母大写
  • upper() 所有字母大写
  • lower() 所有字母小写
  • swapcase() 大小写互换
  • len() 字符串长度
  • count() 统计字符号中某个元素的数量
  • find() 查找某个字符串第一次出现的索引位置
  • index() 与find功能相同 find找不到返回-1 index找不到数据直接报错
  • startswith 判断是否以某个字符或字符串开头
  • endSwith 判断是否以某个字符或字符串结尾

is系列

  • isupper() 判断大写

  • islower() 判断小写

  • isdecimal() 判断数字组成,必须纯数字

  • split() 按某字符划分成列表(默认字符是空格)

  • join() 按某字符讲列表拼接成字符串(默认容器都可以)

  • center() 填充字符串,原字符串居中(默认填充空格)

  • strip() 默认去掉首尾两边的空白符

  • replace() 替换字符串

4.2 format格式化字符串

{} 代表占位符
1.顺序传参
"{}是{}".format("a","b")
2.索引传参
"{1}是{0}".format("b","a")
3.关键字传参
"{a}是{b}".format(a="a",b="b")
4.容器类型数据(列表或元组)传参
下标:
    "{0[0]}是{1[0]}".format(["a","b"],("c","d"))
关键字:
    "{listvar[0]}是{tuplevar[0]}".format(listvar=["a","b"],tuplevar=("c","d"))
字典:字典在format中,键不需要加引号获取
    "{dictvar1[a]}是{dictvar2[c]}".format(dictvar1={"a"="aa","b"="bb"]},dictvar2={"c"="cc","d"="dd"})
format填充字符串
^原字符串居中
>原字符串居中
<原字符串局左

例子:(who:!<10)
who :   关键字
!  :  要填充的字符
<   :   填充的方向,原字符串居左
10  :  字符串的总长度
总长度10 = 原字符串长度+填充字符串的长度
进制转换等特殊字符的使用(:d :f :s :,)
1. :d 整形占位符(要求必须是整型)
"{:d}月{:d}号".format(3,8)      = 3月8号
"{:2d}月{:2d}号".format(3,8)    =  3月 8号
"{:<2d}月{:<2d}号".format(3,8)  = 3 月8 号

2. :f 浮点型占位符(要求必须是浮点型)
"{:f}元".format(9.9)        = 9.9元
:02f保留两位小数,存在四舍五入
"{:.2f}元".format(98.319)   = 98.32元

3. :s 字符串占位符(要求必须是字符串)
"{:s}".format("cascacsa")

4. :, 金钱占位符
"{:,}".format(123456789)    = 123,456,789

5.列表的相关操作

1.列表的的拼接(同元组)+
2.列表的重复(同元组)*
3.列表的切片(同元组) **语法=》列表[::] 完整格式[开始索引:结束索引:间隔值]**
    1. [开始索引:]从开始索引截取到列表的最后
    2. [结束索引:]从开头截取到结束索引之前(结束索引-1)
    3. [开始索引:结束索引] 从开始索引截取到结束索引之前(结束索引-1)
    4. [开始索引:结束索引:间隔值] 从开始索引截取到结束索引之前按照指定的间隔
    5. [:] 或 [::] 截取所有列表
4.列表的获取(同元组)
5.列表的修改(可切片)
    #利用切片进行修改(切一段,放进去所有值)
    #修改数据的要求是》可迭代数据(list set tuple dict range 迭代器)
    lst = [a,b,c,d,e,f,g]
    lst[1:3] = [bb,cc]
    lst[1:3] = [bb,cc,sa,ww]
    #带有步长的切片修改(切几个改几个)
    lst[::2] = [aa,cc,ee,gg]
6.列表的删除(可切片)
    #批量删除,
    lst = [a,b,c,d,e,f,g]
    del lst[1:4]  => [a,e,f,g]
    

5.1 列表相关函数

tuple 只有两个方法,count index

列表:lst = [a,ca,rr,cd]
#增
    1. append()想列表的末尾添加新的元素
    lst.append(b)
    
    2. insert()在指定索引之前插入元素
    lst.insert(0,c)
    
    3. extend()迭代追加所有元素,批量插入
    tup = (e,d,c)
    lst.extend(tup)
#删
    1. pop 通过制定索引删除元素,没有索引移除最后一个,返回删除后的列表
    res = lst.pop() => [a,ca,rr]
    res = lst.pop(1) => [a,rr,cd]
    
    2. remove() 通过指定的只删除,多个相同元素,默认删除第一个,无返回值
    lst.remove(a)
    
    3. clear()清空列表
    lst.clear()
#改查
    1. index()获取某个值在列表中的索引
    res = lst.index(a)//当值不存在时,报错
    
    2. count() 计算某个元素出现的次数
    
    3. sort 列表排序(默认从小到大排序)
    lst.sort()//小-》大
    lst.sort(reverse=true)//大-》小
    // 对字符进行排序,默认按照ASCLL字符编码进行排序,大小写字母ascll差值是32
    // 字母比较是一位一位进行比较,如果第一位相同,再去比较第二位
    // 编码升级 unicode => utf-8
    // 中文进行排序,中文使用三个字节存储到计算机底层,无规律可行,实际是按照二进制进行排序

    4. reverse()列表反转操作,水平反转
    lst.reverse() => [cd,rr,ca,a]

5.2 深拷贝 和 浅拷贝

a = 19
b = a
a = 20
print(b) => 19


lst1 = [1,2,3]
lst2 = lst1
lst1.pop(4)
print(lst2) => [1,2,3,4]

//浅拷贝 
#方法一
lst1 = [1,2,3]
lst2 = lst1.copy()//只拷贝一级,其他层级保留元数据
lst1.pop(4)
print(lst1) => [1,2,3,4]
print(lst2) => [1,2,3]

#方法二
import copy
lst1 = [1,2,3]
lst2 = copy.copy(lst1)
lst1.pop(4)
print(lst1) => [1,2,3,4]
print(lst2) => [1,2,3]

//深拷贝语法 针对多级容器,所有层级元素都单独拷贝一份,形成独立的副本
#方法一
lst1 = [1,2,3,[4,5]]
lst2 = copy.deepcopy(lst1)//只拷贝一级
lst1[-1].pop(6)
print(lst1) => [1,2,3,[4,5,6]]
print(lst2) => [1,2,3,[4,5]]

#总结
copy 比较 deepcopy 比较 copy更快
**浅拷贝:只拷贝第一层所有的元素,copy.copy()**
**深拷贝:为所有层级的元素都单独开启新的空间 copy.deepcopy*()*
(地址:不可以变数据都暂时指向,可变数据都是单独开辟空间)

6.字典相关函数

#增
dic = {}
dic["a"] = ["啊"]
dic["b"] = ["把"]
dic["c"] = ["出"]

#fromkeys() 使用一组键和默认值创建字典
dic = {}.fromkeys([a,b,c],None)//批量赋值容器类型为同一地址的元素

#删
#pop() 通过键去删除键值对(没有该键设置默认值,预防报错)
dic.pop("a")
dic.pop("dd","没有")

#popitem() 删除最后一对键值对
dic.popitem()

#clear() 清空字典

#改
#update() 批量更新,有键就更新,无键就添加
newdic = {"a":"啊啊","d":"的"}
dic.update(newdic) => a:啊啊 b:把 c:出 d:的

# 方法二dic.update("a":"啊啊","d":"的")  不推荐

#查
#get() 通过键取值,(没有键可以设置默认值,预防报错)
dic["aa"] => 报错
dic.get("aa") => None
dic.get("aa","") => ""

# 可迭代对象:容器类型数据,range对象。迭代器

#keys() 讲字典的键组成新的可迭代对象
dic.keys() => dict_keys(["a","b","c"])
dict_keys 可迭代对象,没有具体类型

#values() 将字典中的值组成新的可迭代对象
dic.values() => dict_values(["啊","把","出"])

#items() 讲字典中的键值对组成一个个元组,组成新的可迭代对象
res = dic.items () => dict_itemys([("a","啊"),("b","把"),("a","出")])
#变量的解包
for k,v in res:
    print(k,v)
    

7.集合的相关操作和函数

作用:用来交差并补集用,默认去除重复数据
补集只存在一个集合被另一个集合完全包涵的情况中

set1={a,b}
set2={b,c}
# intersection() 交集
set1.intersection(set2)
# 简写 &
set1 & set2

# difference() 差集
set1.difference(set2)
# 简写 -
set1 - set2

# union() 并集
set1.union(set2)
# 简写 |
set1 | set2

# symmetric_difference() 对称差集(补集包涵在在中)
set1.difference(set2)
# 简写 ^
set1 ^ set2

# issubset() 判断是够是子集
# 简写 < 

# issuperset() 判断是够是父集
# 简写 >

# isdisjoint() 判断量几个是否不相交 不:true 相交 false

7.1 集合相关的函数

# 增 add() 批量添加 update()
# 删 
clear()清空
pop()随机删除一个 
remove()删除指定的值 不存在报错
discard()删除指定的值 不存在不删除 推荐
# 改 update()
# 查

7.2 冰冻集合

# frozenset 可强转容器类型数据编程冰冻集合
特征:不能做任何添加 删除,只能交叉并补, 可遍历
空的冰冻集合:frozenset()

8.文件操作

# 文件写入步骤
a.打开文件--把冰箱打开
fp = open(文件名=r"e:\py\20210306\a.txt",mode=模式,encoding=字符编码集) 
    fp 文件的io对象(文件句柄)
    i   :   input 输入
    o   :   output 输出

    模式:w write写入 r read读取 a append追加
b.写入
fp.write("把大象塞进去")
c.关闭--把冰箱关闭
fp.close()

# 文件读取步骤
a.打开文件--把冰箱打开
fp = open(文件名=r"e:\py\20210306\a.txt",mode=模式,encoding=字符编码集) 
    fp 文件的io对象(文件句柄)
    i   :   input 输入
    o   :   output 输出

    模式:
    w write写入
        不存在创建,存在清空,并将文件指针放在文件的结尾
    r read读取 
        不存在报错,存在打开,并将文件指针放在文件的开头
    a append追加 
        不存在创建,存在打开,并且将文件指针放在文件的末尾
    xar异或模式
b.写入
res = fp.read() ->大象
c.关闭--把冰箱关闭
fp.close()

# 扩展功能(配合打开模式的辅助模式,自己不能单独使用)
+ puls 增强模式(可以让文件具有读写功能)
--> w w+ wb wb+
    r r+ rb rb+
    a a+ ab ab+
b bytes bytes模式(二进制字节流)用来传输或者存储的数据
--> b"111"要求:b开头的字符串,内容必须是ascii编码

# 字符串 字节流类型转换
#encode(字符串编码="utf-8") 编码 字符串->bytes
#decode(字符串编码="utf-8") 解码 bytes->字符串
#len()计算字节流长度


# 存储字节流(场景:图片、音频、视频等存储)
wb 与 rb 来存储二进制字节流
///字节流模式下,不需要指定编码集
fp = open("test.txt",mode="wb")
bytesstr = "阿克苏不参加".encode("utf-8")
fp.write(bytesstr)
fp.close()

fp = open("test.txt",mode="rb")
fp.read()
fp.close()

8.1 字符

字符:无论是神马语言,独立的一个文字就是字符
存储单位:
    Byte字节
    bit:位
    1B = 8b
    B:字节 ,1Byte = 8bit
字符大小:
    英文和数字都是一个字节,汉 韩 日文等采用多个字节存储
    GB系列编码:村吃一个汉字使用2个字节
    UTF系列:存储一个汉字使用3个字节
字符编码种类:(把编码看成一个密码集,每一个字符在计算机中都是二进制)
    英文原始编码:
    ASCII码-》最早的字符编码格式,仅支持英文以及特殊符号
    
    中文编码:
    GB2312:     5000常用汉字
    GB18830:    15888个汉字
    GBK:        所有汉字编码
    BIG5:       繁体中文编码
    
    万国码:
    unicode:   世界上所有的文字(文论神马字符都按照4个字节表示)
    UTF-8  :    可变长的unicode编码

8.2文件的扩展模式


1.r+模式,文件指针默认在文件开头
# r+ 先读后写
fp = open("ceshi.txt","r+","utf-8")
//先读
res = fp.read()
//后写
fp.write("123")//写完默认文件光标在末尾的位置
//先把文件光标移动到开头
fp.seek(0)
//再读
res = fp.read()
fp.close()

# r+ 先写后读
fp = open("ceshi.txt","r+","utf-8")
//先写 r模式默认把文件指针在文件开头位置
//先把文件光标移动到末尾
fp.seek(0,2)
fp.write("abc")//写完默认文件光标在末尾的位置]]
//后读
fp.seek(0)
res = fp.read()

2.w+模式 可读可写
fp = open("ceshi.txt","w+","utf-8")
//先写 w模式默认把文件指针在文件末尾位置
fp.write("abcascacc")//写完默认文件光标在末尾的位置]]
//后读
fp.seek(0)
res = fp.read()
fp.close()

3.a+模式 append模式强制把文件指针在文件末尾位置
#a模式 w模式默认都可创建文件
#a模式下:seek移动文件指针后插入内容,文件指针还是默认在文件末尾位置
fp = open("ceshi.txt","a+","utf-8")
fp.write("11122")
fp.seek(0)
res = fp.read()
fp.close()

8.3文件的主要功能

(utf-8:默认中文=3Byte 英文|符号=1Byte)
# 1.read(字符) 功能: 读取字节的个数(里边的参数代表字符的字数)
# 2.seek(字节数,方向 2结尾 1开头) 功能:调整指针的位置(里边参数代表从文件开头调整光标位置的字节数)
# 3.tell() 功能: 计算当前光标位置至最左边位置的字节总数
123xxx456
fp = open("ceshi.txt","r+","utf-8")
fp.read(6) => 123xxx
fp.seek(2) => 12光标所在3xxx456
fp.read(2) => 3x
fp.tell()  => 4个字节

123今天天气456
fp = open("ceshi.txt","r+","utf-8")
fp.seek(5) 
fp.read()=>报错,seek移动的是字节数,decode反解失败

# with语法(省略close操作)相当于执行了close
with open(...) as fp:
    fp.write("caca")
with open(...) as fp, open(...) as fp1:
    fp.write("caca")
    fp1.write("caca1")
    


# 4.刷新缓冲区 flush()手动方法
    当文件关闭时候自动刷新缓存区
    当程序运行结束的时候自动刷新缓存区
    当缓存区写满,自动刷新缓存区
    手动刷新缓存区
# close的意义
fp = open("ceshi.txt","a+","utf-8")
fp.write("caca")
while true:
    pass
fp.close()
fp.flush()//刷新缓存区

8.4 文件相关函数

1.readable()    判断文件对象是否可读
2.writable()    判断文件对象是否可写
3.readline(读取的字符个数)    读取一行文件内容
4.readlines()   将文件中的内容按照换行读取到列表中
"""
csacsa
ascasc
cascas
avavav
"""
lst_new = []
with open("ceshi.txt","r+","utf-8") as fp:
    lst = fp.readlines()
    for i in lst:
        i.strip()
        lst_new.append(i)
5.writelines()  将内容是字符串的可迭代行数据写到文件中
lst_new1 = []
with open("ceshi.txt","w+","utf-8") as fp:
    lst_new.insert(3,"cacasca")
    for i in lst_new:
        res = i + "\n"
        lst_new1.append(i)
    fp.writelines(lst_new1)
6.truncate()    把要截取的字符串提取出来,然后清空内容讲提取的字符串重新写入文件中(字节)
截取-》清空-》重写 单位字节

9.函数

9.1 函数格式特点

函数:功能
特点:
基本格式:
    定义
    def func():
        code..
    调用
    func()
函数命名:
    字母数字下划线,首字符不能为数字
    严格区分大小写,切不能使用关键字
    函数命名有意义,且不能使用中文
    
    驼峰命名法:
        1.大骆驼:每个单词首字符大写(面向对象中,定义calss)
        2.小驼峰:处理第一个单子小写,剩下每个单词首字符大写(函数,变量)

9.2 函数参数

函数参数:
    1.形参:形式上的参数,在函数的定义处
        普通,默认,普通收集,命名关键字,关键字收集
    2.实参:实际上的参数,在函数的调用处
        普通,关键字

默认形参 和 关键字实参区别:默认行参在函数的定义处,关键字实参在函数的调用处

参数的顺序

#形参顺序
    普通-》默认-》普通收集-》命名关键字-》关键字收集
#收集所有实参
def func(*args,**kwargs):
    pass

收集参数

收集参数: 
    1.普通收集参数:收集多余的没人要的普通实参,构成**元组**
    参数前面加上*,代表是普通收集参数
        def func(*args):
            pass
        args => arguments(参数)
        
        
    2.关键字收集参数:收集多余的没人要的关键字实参,构成一个**字典**
    参数前面加上**,代表关键字收集参数
        def func(**kwargs):
            pass
        kwargs = keyword arguments
        def func(a,b,**k)
        func(1,2,c=3,d=4)
关于*与**的使用方法:控制了参数的个数,解耦代码
在函数定义处,*和**用来接收数据,*打包成元组,**打包成字典
在函数调用处,*和**用来解包数据,*一般应用在列表或元组,**一般用在字典
func(1,2,c=3,d=4)
# *在调用处用法
lst=[1,2]
func(*lst,c=3,d=4)
# **在调用处用法
dic = {"c":3,"d":4}
func(1,2,**dic)

func(*lst,**dic)

命名关键字参数

def func(参数1,参数2,*,参数3)
    定义:在*后后面定义的参数是命名关键字参数
def func(*args,参数,**kwargs)
    在普通收集与关键字收集参数之间,也是命名关键字参数
例子:
1.def func(a,b,*,c):
    pass
func(1,2,c=3)

2.def func(*args,dd,**kwargs):
    pass
func(1,2,3,dd=111,a=1,b=2,c=3)

9.3 函数返回 return

return:函数可以自定义返回值,通过return,可以把这个值返回到函数的调用处
1.return+返回值,后面可以接6打标准数据类型外,还可以返回函数和类对象,默认返回None
2.在函数中执行return,终止函数,后面代码不执行

10.全局变量_局部变量

局部变量:在函数内部定义的变量就是局部变量
全局变量:在函数外部定义的全量或者在函数内部用global关键字定义的全局变量

作用域:作用的返回
    局部变量  在函数内部
    全局变量  横跨整个文件

global:
    函数外部有这个全局变量,在函数内部使用global,可以修改全局变量
    函数内部无这个全局变量,在函数内部使用global关键字,可以定义全局变量

在函数内部可以直接获取全局变量,无法直接修改,需要通过global
f=1
def func():
    f=2
    print(f)=>2
func()
print(f) => 1

10.1命名空间

命名空间:划分一块区域保存所有数据,以字典方式存储(变量 值形成映射关系)共三种:
1.内建命名空间:解释器启动时创建,直到解释器运行结束,生存周期最长
2.全局命名空间:文件运行时创建,直到解释器运行结束,周期较长
3.局部命名空间:函数调用时,里边的变量才创建,调用结束后释放,周期较短

命名空间 创建顺序:python解释器启动-》内建命名-》全局命名-》局部命名
命名空间 销毁顺序:函数调用结束-》局部-》全局-》内建

10.2变量名

1.函数名是个特殊的变量,可以当成变量赋值
    def func1():
        retuurn 111
    动态创建:
    func=func1
    func()
    动态销毁函数
    del func
    func()=>报错
2.函数名可以作为容器类型数据的元素
    def func2():
        pass
    def func3():
        pass
    def func4():
        pass
    lst = [func2,func3,func3]
    for i in lst:
        i()
3.函数名可以作为函数参数
    def myfunc(f):
        res =f()
    myfunc(func4)
4.函数名可作为函数的返回值
    def myfunc(f):
        return f
    f2 = myfunc(func4)=>打印出func4的内存地址


__doc__或者help查看文档
def func():
    ···
    功能
    参数
    返回值
    ···

10.3 locals globals

locals:
    如果在函数外,调用locals(),获取的打印之前的所有变量,返回字典,全局控件作用域
    如果在函数内,调用locals(),获取的调用之前的所有变量,返回字典,全局控件作用域
globals:
    如果在函数外,调用globals(),获取的打印之前的所有变量,返回字典,全局控件作用域
    如果在函数内,调用globals(),获取的调用之前的所有变量,返回字典,全局控件作用域

globals特殊用法:
    通过系统全局字典添加键值对,可以动态创建全局变量
    自动创建变量,批量创建全局变量
    dic = globals()
    #传递字符串,创建变量
    k = "guo"
    dic[k] = "测试"
    print(guo) ==> 测试
    

10.4 函数的嵌套

函数的嵌套:
    嵌套在函数的外部叫外函数
    嵌套在函数的内部叫内函数
def cuter():
    def inner():
        pass
1.内部函数可以在函数外部调用吗?不可以,作用域问题
2.调用外部函数后,内部函数可以在函数外部调用吗?不可以
3.内部函数可以在函数内部调用吗?可以
4.内部函数在函数内部调用时,是否有先后顺序?有,代码执行自上而下

python没有预加载,不会把函数预加载至内存中

LEGB原则(就近找变量原则)

B -- Builtin(python):python内置的命名空间  内建作用域
G -- Global(Module):函数内部所在的命名空间   全局作用域
L -- Local(function):当前函数内的作用域    局部作用域
依据就近原则,从下往上,从里向外,依次寻找

nonlocal关键字

global:用来修改全局变量
nolobal: 用来修改局部变量
遵循LEGB原则
1.用来修改当前作用域上一级的局部变量
例子:
    def outer():
        a=10
        def inner():
            nolocal a//提高作用域
            a=20//作用域在inner
            print(a)=>20
        inner()
        print(a)=>20
    outer()
2.如上级找不到,继续向上寻找
    
    def outer():
            a=10
            def inner():
                nolocal a//提高作用域
                a=20//作用域在inner
                print(a)=>20
            inner()
            print(a)=>20
    outer()
3.全部找不到,直接报错
    a=10
    def outer():
            def inner():
                nolocal a//提高作用域
                a=20//作用域在inner
                print(a)=>20
            inner()
    outer()
    print(a)=>报错,a是全局变量
4.不使用nonlocal,是否可以修改局部变量
    def  outer():
        lst = [1,2,42]
        def inner():
            lst[-1]=52
        inner()
    print(lst)
    outer()

10.5 闭包函数

定义:
    内函数使用了外函数的局部变量
    外函数将内函数返回出来的过程,叫做闭包
    里边的内函数叫闭包函数
1.闭包函数用法
def func():
    father = "王健林"
    def wjl_hobby()://闭包函数
        print("acsacsa{}".format(father))
    return wjl_hobby
res = func()
print(res)=>打印出函数地址
res()=>acsacsa王健林

2.升级
def func1():
    father = "a"
    jiejie = "b"
    meimei = "c"
    money = 1000
    def jiejie_hobby()://二级闭包函数
        nonlocal money
        money -= 700
        print("b%s" % (money))
    def meimei_hobby()://二级闭包函数
        nonlocal money
        money -= 200
        print("c%s" % (money))
    def big_master()://闭包函数,
        return [jiejie_hobby,meimei_hobby]
    return big_marter()
func = func1()
func()[0]()=>b300
func()[1]()=>c100

** 获取闭包函数使用的变量 __closure__, cell_contents**
tup = func.__closure__//判断是否闭包,返回为空不是闭包
**cell_contents:获取单元格对象里边的内容**
jiejie =tup[0].cell_contents
meimei =tup[0].cell_contents
jiejie()=>b300
meimei()=>c100

闭包特点意义

** 闭包的特点:内函数使用了外函数的局部变量,该局部变量与内函数发生绑定,延长该变量的**生命周期
#例子:
def outer(val):
    def inner(num):
        return num + val
    return inner
func = outer(5)
res = func(4) -> res=9
# 实参5 和 形参val  一一对应
# 因为内函数inner 和 val进行绑定,延长了val变量的生命周期,不释放

**闭包的意义:**
**闭包可以优先使用外函数的局部变量**
**局部变量在函数外部不能被直接使用**
**对局部变量实现了保护的作用,外部无法访问**
# 模拟鼠标点击
click_num = 0 
def click_func():
    global click_num
    click_num +=1
    print(click_num)
clock_func() 1
clock_func() 2
clock_func() 3
click_num = 100 #受到攻击
clock_func() 101
# 闭包模拟鼠标点击
def outer():
    click_num = 0
    def inner():
        nonlocal click_num
        click_num += 1
        print(click_num)
    return inner
clock_func = outer()
clock_func() 1
clock_func() 2
clock_func() 3
click_num = 100 #受到攻击
clock_func() 4

10.6匿名函数

只有返回值的函数,特点:简洁 高效 方便

** lambda表达式**

语法结构:
  lambda 参数:返回值
 
 种类:
 1.无参的lambda表达式
def func():
    pass
func()
改写 lambda:
func = lambda : pass
func()
2.有参的lambda表达式
def func(n):
    return type(n)
func(17)
func = lambda n : type(n)
func(17)
3.带有判断条件的lambda表达式
def func(n):
    if n%2 == 0:
        return 0
    eles:
        return 1
func(17)->1
三元运算符:真值 if 条件表达式 else 假值
func = lambda n : 0 if n%2==0 else 1
func(17)->1

10.7 迭代器

能被next调用,并且不断返回下一个值的对象,叫做迭代器(迭代器是对象)

概念:迭代器指的是迭代取值的工具,迭代是一个重复的过程,每次重复都是基于上一次的结果而继续,单纯的重复不是迭代
特点:不依赖索引。而是通过next指针迭代所有数据,一次只取一个,节省空间,迭代无限量数据

1.可迭代对象
## dir函数可以查看对象中所有的成员
## 如果成员中含有__iter__这个方法,就是可迭代对象
setvar = {"a",1,"b",2}
for i in setval:
    print(i)
2.迭代器
## for循环遍历数据的底层实现就是利用了迭代器,通过next方法进行调用,杏儿获取数据
## 可迭代对象 和迭代器之间的关系:从不可被直接获取==?可被直接获取的过程
## 如果是一个迭代器对象,不一定是一个迭代器
## 如果是一个迭代器,就一定是一个可迭代性对象
2.1 如何定义一个迭代器
## iter(可迭代对象)
## 可迭代对象.__iter__()

例子:
it = iter(setval)

2.2判断一个迭代器
## 如果内置成员中,含有__iter__ 和 __next__两个方法,就可以判断是一个迭代器
res = "__iter__"  in dir(it) and  "__next__" in dir(it)
res =>true
2.3 如何调用一个迭代器
## next(迭代器)
## 迭代器.__next__()
## 迭代器通过next方法调用时,是单项不可逆的过程
next(it)

2.4 重置迭代器
it = iter(setvar)
res = next(it)

2.5 使用iterator 和 iterable 来判断是否是迭代器
"iterator 迭代器类型 iterable可迭代对象"
from collections import iterator,iterable
setvar = {a,b,c,d}
res = isinstance(setvar,Iterator)=>false
res = isinstance(setvar,iterable)=>true

# 判断range的迭代属性
it = iter(range(10))
res = isinstance(it,Iterator)=>true
res = isinstance(it,iterable)=>true
    # 更多的调用方式
    1.通过next获取迭代器中的数据
    res = next(it)->0
    res = next(it)->1
    res = next(it)->2
    ...
    2.通过for循环,遍历迭代器
    for i in iter(range(10)):
        print(i)
    3.for 和 next配合调用迭代器
    it = iter(range(100000000))
    for i in range(10):
        print(next(it))

10.8 高阶函数

能够把函数当成参数传递的就是高阶函数
map

map(func,iterable)
功能:
    被iterable里边的数据拿出来,放到func函数进行处理,处理的结果丢到返回的迭代器中
参数:
    func自定义函数 或者 内置函数
    iterable 可迭代对象(容器类型数据 range 迭代器)
返回值:
    迭代器

例子1:
要求:["1","2","3"]=>[1,2,3]
form collections import Iterator,Iterable
lst = ["1","2","3"]
it = map(int,lst)
res = isinstance(it,iterator)=>true
for i in it:
    print(i)

# list强转迭代器
it = map(int,lst)
res = list(it) =>[1,2,3]

filter

filter(func,iterable)
功能:
    在自定义的函数中,过滤数据
    返回true,代表保留数据
    返回false,舍弃该数据
参数:
     func自定义函数 或者 内置函数
    iterable 可迭代对象(容器类型数据 range 迭代器)
返回值:
    迭代器

例子1:
要求:[1,2,3,4,5,6,7]=>要奇数
lst = [1,2,3,4,5,6,7]
it = filter(lambda n : false if n%2==0 else true,lst)
print(list(it))

reduce

reduce(func,iterable)
功能:
    一次性从iterable中拿出两个值,丢到func函数中进行处理,
    把运算结果再和iterable的第三个值继续丢到func中做运算
    ...依次类推
    最后返回计算的结果
参数:
    func自定义函数 或者 内置函数
    iterable 可迭代对象(容器类型数据 range 迭代器)
返回值:
    最后计算的结果
引用:from functools import reduce

例子:
要求[5,4,8,8] =>5488
from functools import reduce
lst = [5,4,8,8]
reduce(lambda x,y:int(str(x)+str(y)),lst)
reduce(lambda x,y:int(str(x)+str(y)),lst)   

例子2:
要求:"789"=>789
strval = "789"

sorted

排序范围:元组,列表,集合,字符串,字典
sorted(iterable,reverse=true,key=函数)
功能:
    排序
参数:
    iterable 可迭代对象(容器类型数据 range 迭代器)
    reverse  代表是否倒叙,true倒叙 false正序
    key      自定义函数或内置函数
返回值:
    排序后的结果

例子:
lst = [100,200,13,-6,0]
lst_new = sorted(lst,false)
#按照绝对值排序 abs内置函数
lst_new = sorted(lst,key=abs)
#按照自定义函数进行排序
lst = [19,27,45,48]
按照余数大小排列:
def func(n):
    return n % 10
sorted(lst,key = func)=>[5,7,8,9]

总结:
    sort 基于原有的列表进行排序,只限定列表类型
    sort 所有的容器类型都能排序,返回一个全新的列表(推荐)

10.9 生成器函数

yield 类型于 return
共同点:执行到这句话都会把值返回出去
不同点:yield每次返回时,会记住上次离开时执行的位置,下次调用生成器,会从上次执行的位置往下走,而return会直接终止函数,每次重头调用

# 1.基本语法:
def mygen():
    print(1)
    yield 1
    
    print(2)
    yield 2
    
    print(3)
    yield 3
# 初始化生成器函数,返回生成器对象,简称生成器
from collections import Iterator
gen = mygen()//gen生成器对象 mygen生成器函数
ptint(isinstrance(gen,Iterator))=>true//生成器也是迭代器的一种
res  = next(gen)
print(res)==>1
res  = next(gen)
print(res)==>2
res  = next(gen)
print(res)==>3
res  = next(gen)
print(res)==>error

10.10 集合推导式

通过一行循环判断,遍历出一系列数据的方式就是推导式
推导式在使用时,只能用for循环和判断,判断只能是单向循环

语法:val for val in Iterable(把想要的值写for的左侧)
里边是一行循环判断,根据套在推导式外层的符号判断具体是神马类型的推导式
种类:
    [val for val in Iterable]   列表推导式
    {val for val in Iterable}   集合推导式
    {a:b for a,b in Iterable}   字典推导式

例子:
lst = [i for i in range(1,51)]

1.普通推导式
# [1,2,3]=>[2,8,24]
lst = [ i * 2 ** i for i in lst]
lst = [ i << i for i in lst]
2.带有判断条件的推导式
lst = [1,2,3,4,5,6,7,8]
#求偶数
lst =[ i for i in lst if i % 2 ==0]
3.多循环推导式
lst1 = [1,2,3]
lst2 = ["a","b","c"]
#谁爱谁
lst = [ i+"爱"+j for i in lst1 for j in lst2]
4.带有判断条件的多循环推导式
#谁爱谁,判断索引相同才拼接
lst = [ i+"爱"+j for i in lst1 for j in lst2 if lst1.index(i) == lst2.index(j)]

字典推导器

1.enumerate
enumerate(iterable,[start=0])
功能:枚举,将索引号和iterable中的值,一个一个拿出来配对组成元组放入迭代器中
参数:
    iterable:可迭代性数据
    start:可以选择开始的索引号,默认从0开始
返回值:迭代器

lst = ["a","b","c"]
it = enumerate(lst,start=1)
dict(it)=>{1:a,2:b,3:c}
# 通过推导器配合enumerate实现
dic = {k:v for k,v in enumerate(lst,start=1)}

zip

zip(iterable,...,...)
功能:将多个iterable中的值,一个一个拿出来配对组成元组放入迭代器中
参数:iterable
返回:迭代器
lst1 = [a,b,c]
lst2 = [1,2,3,4]
it = zip(lst1,lst2)
list(it)=>=>[(a,1),(b,2),(c,3)]
# 使用zip配合推导式实现
dic = {k:v for k,v in zip(lst1,lst2)}

10.11生成器

生成器本质是迭代器,允许自定义逻辑的迭代器
迭代器和生成器的区别:迭代器本身是内置的,重写不了,生成器是用户自定义的,,可以重写迭代逻辑

# 生成器可以用两种方式创建:
    1.生成器表达式(里边是推导式,外表用圆括号)
    2.生产器函数(用def定义,里边含有yield)
# 1.生成器表达式
gen = (i*2 for i in range(1,5))
# 2.生产器函数
# 初始化生成器函数->生成器对象-
def mygen():
    for i in range(1,101):
        yield "%s" % (i)
gen = mygen()//生成器对象 = 生成器对象

# 3.send
# send可以发送数据,发送给上一个yield
# 与next区别:next 只能取值,send能取值还能发送值
# send注意点:第一个send不能给yield传值,只能none,最后yield 接收不到send的发送至
def mygen()
    print("开始")
    res = yield 111
    print(res)
    
    res = yield 222
    print(res)
    
    res = yield 333
    print(res)
    
    print("结束")
gen = mygen()
# 第一个send不能给yield传值,只能none
val = gen.send(None)
print(val)=>开始 111

val = gen.send(444)
print(val)=> 开始 111 444 222

val = gen.send(555)
print(val)=> 开始 111 444 222 555 333

val = gen.send(666)
print(val)=> 开始 111 444 222 555 666 end 报错,没有


# 4. yield from :将一个可迭代对象变成一个迭代器返回
def mygen():
    lst = [a,b,c]
    yield from lst
gen = mygen()
print(next(gen))=>a
print(next(gen))=>b
print(next(gen))=>c

# 案例:斐波那契数列 1 1 2 3 5 8 13 21 34 55....
def mygen(maxlength):
    a = 0 
    b = 1
    
    i = 0
    while i < maxlength:
        yield b
        a,b = b, a+b
        i +=1
gen = mygen(50)
for i in range(10):
    print(next(gen))

10.12 递归函数

递归函数,自己调用自己函数时递归函数

递归:去的过程,就是不听的开辟栈帧空间的过程,在回的时候,就是不断的释放栈帧空间

写递归函数,必须给出跳出的条件,层数过多不推荐使用

递归函数用每层空间都是独立的个体,独立的副本,资源不共享,可以通过return来完成值的传递

函数在运行时候,需要内存开辟空间(栈帧空间),调用结束释放空间

# 递归函数有回的过程,有两种情况可以出发:
# 1.当最后一层函数全部执行结束的时候,回到上层函数空间的调用处
# 2.遇到return返回值,直接返回上层空间的调用处

# 递归最大层数1000层,具体按照机器差异不同

尾递归(自己调用自己,并且非表达式)(把值放到参数中运算)

无论调用多少次函数,都只占用一份空间
只需要考虑最后一层空间的结果是多少,就不用额外考虑会的结果
在 cpython解释器中不支持尾递归,个别解释器支持

递归算法


posted @ 2021-04-16 10:35  蜗牛2你的菜  阅读(187)  评论(0)    收藏  举报