import functools
"""核心思想,函数就是参数,把函数当作参数传进去处理,使得函数增加新的功能再使用,不就是修饰一下"""defouter(func):@functools.wraps(func)# 使用原函数信息,否则返回装饰器信息definner(*args,**kwargs):# 多参数传递'''inter注释,#不显示'''print('before')
res = func(*args,**kwargs)# 多参数传递print('after')return res
return inner
# 等价于,func=outer(func),outer返回inner --> 执行inner --> 中间实际执行func1原函数和添加功能 --> 返回原函数返回值@outerdeffunc1(a1, a2):# func1注释'''三引号注释func.__doc__可以显示'''print('我func函数')
value =(1,2,3,4)return value
# @outer # func=outer(func)deffunc2():print('我func函数')
value =(1,2,3,4)return value
@outer# func=outer(func)deffunc3():print('我func函数')
value =(1,2,3,4)return value
if __name__ =='__main__':
func1(5, a2=8)print(func1.__name__)# 函数名,装饰器添加@functools.wraps(func) # 使用原函数信息,否则返回装饰器信息print(func1.__doc__)# 函数注释print(func2.__name__)print(func2.__doc__)print(func3.__name__)print(func3.__doc__)pass
before
我func函数
after
func1
三引号注释func.__doc__可以显示
func2
None
func3
None
1.1.2.装饰器中的闭包理解
defa0():"""必报的简单理解"""defg_m_f(n):defm(x):return n * x
return m
double = g_m_f(2)(4)# m(4) -> 2*4
triple = g_m_f(3)# mprint(double)print(triple(3))# m(3) -> 3*3defa1():"""函数当作参数传递"""deffunc():print('我func函数')
value =(1,2,3,4)return value
defouter(origin):definter():print('before')
res = origin()print('after')return res
return inter
func = outer(func)
result = func()print(result)defa2():"""用装饰器代替上面"""defouter(origin):definter():print('before')
res = origin()print('after')return res
return inter
@outer# func=outer(func)deffunc():print('我func函数')
value =(1,2,3,4)return value
result = func()print(result)if __name__ =='__main__':
a0()# a1(),a2(),效果是相同的,说明装饰器<=>原函数=装饰器(原函数)
a1()
a2()
8
9
before
我func函数
after
(1, 2, 3, 4)
before
我func函数
after
(1, 2, 3, 4)
defhello():""""yield每次返回一个,然后函数停止执行,并且记录位置和数据,下次调用接着执行"""print('step1')yield1print('step2')yield2print('step3')yield3print('step4')yield4
g = hello()
res =next(g)print(res)
res =next(g)print(res)
res =next(g)print(res)
res =next(g)print(res)# print(hello())# for res in g:# print(res)
step1
1
step2
2
step3
3
step4
4
1.2.2.生成器基本用法next
# 常规实现
num =0
x =0
y =0
points =[]while num <5:
y = x *2+1
points.append((x, y))
x = y
num +=1print(points)print('-'*15,'生成器')# 迭代器的使用classPoints(object):def__init__(self):# 初始化一个空的点列表,以及初始的x值、k值和b值
self.point_list =[]
self.x =0
self.k =2
self.b =1def__iter__(self):# 使Points类成为一个迭代器。返回当前实例(self)return self
def__next__(self):# 迭代器一定可以next# 定义了如何从迭代器中取出下一个元素。这里的计算公式temp_y = self.k * self.x + self.b用于生成新的y值,然后将(x, y)对添加到点列表中,并更新x的值为新的y值# temp_y = 2 * self.x + 1
temp_y = self.k * self.x + self.b
self.point_list.append((self.x, temp_y))
self.x = temp_y
return self.point_list
defchange_k_b(self, k, b):# 允许修改k和b的值
self.k = k
self.b = b
# 代码创建了一个Points的实例points,并通过iter(points)得到一个指向该实例的迭代器points_iter。使用next(points_iter)从迭代器中取出下一个元素
points = Points()
points_iter =iter(points)# 创建迭代器对象print(next(points_iter))print(next(points_iter))print(next(points_iter))print(next(points_iter))print(next(points_iter))print(next(points))# 直接在points对象上调用next()print(next(points))print(next(points))print(next(points))print(next(points))
points.change_k_b(3,2)print(next(points))
'''
如果想让生成器继续向下运行,可以用next或send
同:继续向下运行;遇不见yield产生异常
异:next只会继续运行,什么也不传入,send还可以传入数据,代替yield语句
'''defgenerator_test():whileTrue:print('--1--')
num =yield100print('--2--','num=', num)
g = generator_test()# print(next (g))# print(next (g))# print(next (g))print(g.send(None))# send()一般不在开头使用,之前用next(),首次使用传入noneprint(g.send(11))print(g.send(22))print(g.send(33))# 写个生成器defcreate_point():
x =0whileTrue:
tem = x
y =2* x +1
x = y
# return yyield tem, y
defcreate_point1():
x =0whileTrue:
y =2* x +1# return yyield x, y
x = y
defcreate_point2():
x =0
k =2
b =1whileTrue:
y = k * x + b
tem =yield x, y
if tem:
k, b = tem
x = y
# 创建一个生成器对象
point = create_point()print(next(point))print(next(point))print(next(point))print(next(point))
point1 = create_point1()print(next(point1))print(next(point1))print(next(point1))print(next(point1))print('上两生成器一样','='*100)
point2 = create_point2()print(next(point2))print(next(point2))print(point2.send((3,2)))# 传入参数,改变生成器内部参数print(next(point2))print(next(point2))print(point2.send((1,0)))print(next(point2))print(next(point2))
'''
可以for循环的,一定是iterable
next()的,一定是iterator
dict,str,list,tuple等是iterable,不是iterator,可以iter()出iterator
'''print('自定义迭代器--------------')classMyList(object):def__init__(self):
self.container =[]
self.current =0defadd(self, item):
self.container.append(item)def__iter__(self):# 1.只有加这个方法,才可迭代# 2.iter()自动调用执行后返回一个迭代器return self # 返回迭代器def__next__(self):# 1.标记类所创建的对象一定是迭代器(有__iter__和__next__才是迭代器)# 2.next()自动调用执行,返回数据if self.current <len(self.container):
num = self.container[self.current]
self.current +=1return num
else:# self.current = 0 # 解决第二次for循环没数据raise StopIteration # 抛出异常,不用为了符合for循环终止条件,不用Noneif __name__ =='__main__':
mylist = MyList()
mylist.add(11)
mylist.add(12)
mylist.add(13)
mylist_iter =iter(mylist),# 迭代器使用会记录位置,好像下面只能使用一次# list ,tuple可以接收可迭代对象
mylist_list =list(mylist_iter)print(mylist_list)for i in mylist_iter:print(i)print('-'*9)# for i in mylist_iter:# print(i)
mylist_list =list(mylist_iter)print(mylist_list)
自定义迭代器--------------
[<__main__.MyList object at 0x000001B175807DF0>]
<__main__.MyList object at 0x000001B175807DF0>
---------
[<__main__.MyList object at 0x000001B175807DF0>]
1.4.闭包
1.4.1.类中call
# 面向对象classPerson(object):def__init__(self, name):
self.name = name
defsay(self, content):print(f'({self.name}):{content}')print('(%s):%s'%(self.name, content))def__call__(self, x):# 实例对象(),p()自动调用call方法,否则'Person' object is not callableprint(x)
p1 = Person('jack')
p2 = Person('bob')
p1.say('111')
p2.say('222')
p1('-------------------------__call__方法展示')# 闭包print('-'*20,'闭包')# 实例对象(),p()自动调用call方法,否则'Person' object is not callabledefwho(name):"""
闭包:
1.必须函数嵌套,外部函数返回内部函数地址
2.内部函数使用外部函数参数
3.内部函数可能执行或者修饰传入的函数
"""defcon(content):print('(%s):%s'%(name, content))return con
# 创建闭包对象,相互独立,每个闭包占用内存
p3 = who('j')# 等价于con,name='j'
p4 = who('b')
p3('111')# con('111'),name='j'
p4('222')print(p3)# del p3# 释放内存
p3('333')# con('333'),name='j'
num =[1,2,3,4]print(num)defc(n):# 函数直接修改传入的变量,原数据也改for i inrange(30,41):
n.append(i)return n
s = c(num)print(s)print(num)defd():# 可以直接修改函数外变量s,不用声明
m = s.append('ddd')return s
print(d())print(s)defouter(m=0):definner():nonlocal m # 闭包内部函数不用nonlocal声明外部函数变量,不能修改,报错
m +=1return m
return inner
# 创建闭包对象
con = outer(5)# 等价于inner,m=5print(con())# inner(),m=5print(con())# inner(),m=6print(con())# inner(),m=7'''
对象:可以有n个属性+n个方法
闭包:可以有n个变量+n(一般1个)个函数
'''print('-'*60)defg(k, b):defg1(x):
y1 = k * x + b
return y1
defg2(x):
y2 =2* k * x + b
return y2
return g1, g2
t = g(2,3)print(t[0](2))print(t[1](3))
'''
函数,匿名函数,闭包,对象,当作实参的区别
'''deftest(x):passdefa():pass
test(a)# 传递函数a的引用到test中,传递功能没有数据defb(x):return x *2
test(b)# 传递匿名函数b的引用到test中,传递功能没有数据defperson(name):defsay(content):print(name, content)return say
c = person('张三')
test(c)# 传递say方法,和name数据到testclassPerson(object):def__init__(self, name):
self.name = name
d = person('张三')
test(d)# 传递对象的实例d的引用到test中,传递功能,和name属性数据
1.5.深浅拷贝
1.5.1.copy的运用|id内存|可变不可变类型的理解
import copy
'''
总结:
1.=,是引用复制,指向地址相同,is相同type和内容一定相同即==成立,反之不一定
2.copy.copy()
2.1,顶层是不可变数据类型,就是引用复制
2.2,顶层数据类型可变,就是浅拷贝,只拷贝最顶层
3.copy.deepcopy(),一定是递归拷贝,全部复制
'''
a =[1,2,3]
b =[1,2,3]
c = b # 引用的复制<==>浅拷贝,地址相同
d = copy.copy(b)# b,d地址不同
e =[a, b]
f = copy.copy(e)# 浅拷贝,只拷贝最(外)顶层,ef地址不同,但所用ab相同
g = copy.deepcopy(e)# 全部拷贝一份,ge不同,ab和原来也不同# b.append(6) # q浅拷贝跟着变,深拷贝不变print(a,id(a))print(b,id(b))print(c,id(c))print(d,id(d))print(e,id(e),id(e[0]),id(e[1]))print(f,id(f),id(f[0]),id(f[1]))print(g,id(g),id(g[0]),id(g[1]))print(a == b)# True,仅判断数据是否相同print(a is b)# False,判断地址是否相同print(c == b)print(c is b)print(d == b)print(d is b)print('------其他拷贝方式-----'*10)# 切片
h = e[:]# <=>h=copy.copy(b)print(h, e)
b.append(7)# 改变b,he都变print(h, e)print(id(b))# 字典
i ={'name':'jack','age':18,'cars':[100,200,300]}# 这种方式创建字典可读性强,等价于j={},集合也是{}
j =dict(name='jack', age=18, cars=[100,200,300],)print(i, j, sep='\n')
k =dict.copy(j)# 浅拷贝
j['cars'].append(400)print(j, k,id(j),id(k),id(j['age']),id(k['age']), sep='\n')print('-----------深浅拷贝总结'*10)# 1.copy.copy()只检测最外层数据,最外层是可变数据类型时,是浅拷贝,不可变的直接指向地址,拷都不拷
l =[4,5,6]
m =(7,8,9)# 元组不可变是结构不可变,即引用地址的不可变,一级元素的地址不能变,二级元素地址可以变
l1 = copy.copy(l)
m1 = copy.copy(m)print(id(l),id(l1),id(l[0]),id(l[1]),id(l1[0]),id(l1[1]))print(id(m),id(m1),id(m[0]),id(m[1]),id(m1[0]),id(m1[1]))# m[0]=1 #不可更改
l[0]=99print(l,id(l),id(l[0]))# 整形为不可变数据类型,所以id(l[0])变了,id(l)没变"""拓展,Python的字符串驻留机制,字符串中出现了非标识符允许的字符的时候才不采取驻留有[0-9] [a-z] [A-Z]和"_"(下划线),节省内存指向统一地址,
所谓可变数据类型其实更改后内存地址不变而已,可变的理解为,更改数据,原地址内存释放,重新分配内存地址创建新的对象"""
z1 ='nice'
z2 ='nice'
z3 ='nice'print(id(z1),id(z2),id(z3))# id相同
# 递归,函数内部调用自己# 注意递归返回值的接收,递归的退出条件import os
deftest_os():print(os.listdir(r'E:\s\t'))# 文件夹下的目录print(os.path.isdir(r'E:\s\t\a'))# 判断是否是目录print(os.path.exists(r'E:\s\t\a'))# 路径是否存在defget_file(path):print(f'当前判断的文件夹是{path}')
file_list:list=[]if os.path.exists(path):for i in os.listdir(path):
new_path = path +'\\'+ i
if os.path.isdir(new_path):# 递归关键
file_list += get_file(new_path)else:
file_list.append(new_path)else:print(f'你是输入的路径{path}不存在')return file_list
if __name__ =='__main__':print(get_file(r'E:\s\t\a'))