一、闭包函数
闭包:闭是封闭(函数内部函数),包是包含(该内部函数对外部作用域而非全局作用域的变量的引用)。闭包指的是:函数内部函数对外部作用域而非全局作用域的引用。
def outter(x): x = 1 def inner(): print(x) return inner f = outter(2) f() # 1 f() # 1 f() # 1 # 查看闭包的元素 print(f.__closure__[0].cell_contents) # 1
闭包的意义:返回的函数对象,不仅仅是一个函数对象,在该函数外还包裹了一层作用域,这使得,该函数无论在何处调用,优先使用自己外层包裹的作用域。
1、应用领域:
延迟计算(原来我们是传参,现在我们是包起来)、爬虫领域。
import requests def outter(url): def get(): response = requests.get(url) print(f"done: {url}") return get baidu = outter('https://www.baidu.com') python = outter('https://www.python.org') baidu() baidu() python() python()
二、装饰器
装饰器指的是为被装饰器对象添加额外功能。因此定义装饰器就是定义一个函数,只不过该函数的功能是用来为其他函数添加额外的功能。装饰器的实现必须遵循两大原则:
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
装饰器其实就是在遵循以上两个原则的前提下为被装饰对象添加新功能。
不改变函数体代码,并且不改变函数调用方式,它本质就是一个函数。
def f1(x): def f2(): print(x) # 10 return f2 f2 = f1() f2() # f2()
1、无参装饰器
1、装饰器模板
def deco(func): def wrapper(*args,**kwargs): res = func(*args,**kwargs) return res return wrapper
2、举例:
import time def index(): print('welcome to index') time.sleep(1) def time_count(func): # func = 最原始的index def wrapper(): start = time.time() func() end = time.time() print(f"{func} time is {start - end}") # <function index at 0x102977730> time is -1.0038220882415771 return wrapper index = time_count(index) # index为被装饰函数index的内存地址,即index = wrapper index() # wrapper()
3、被装饰函数有返回值:
如果原始的被装饰函数index()有返回值的时候,wrapper()函数的返回值应该和index()的返回值相同,也就是说,我们需要同步原始的index()和wrapper()方法的返回值。
import time def index(): print('welcome to index') time.sleep(1) return 123 def time_count(func): # func = 最原始的index def wrapper(): start = time.time() res1 = func() end = time.time() print(f"{func} time is {start - end}") # <function index at 0x102977620> time is -1.0050289630889893 return res1 return wrapper index = time_count(index) res = index() print(f"res: {res}") # res: 123
4、被装饰函数需要传参:
如果原始的被装饰函数index()方法需要传参,那么我们之前的装饰器是无法实现该功能的,由于有wrapper()=index(),所以给wrapper()方法传参即可。
import time def index(): print('welcome to index') time.sleep(1) return 123 def home(name): print(f"welcome {name} to home page") time.sleep(1) return name def time_count(func): def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f"{func} time is {start-end}") # <function home at 0x102977378> time is -1.0039079189300537 return res
return wrapper home = time_count(home) res = home('egon') print(f"res: {res}") #res: egon
5、装饰器语法糖:
在被装饰函数正上方,并且是单独一行写上@装饰器名
import time def time_count(func): # func = 最原始的index def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) end = time.time() print(f"{func} time is {start-end}") #<function home at 0x102977620> time is -1.0005171298980713 return res
return wrapper @time_count # home = time_count(home) def home(name): print(f"welcome {name} to home page") #welcome egon to home page time.sleep(1) return name @time_count # index = time_count(index) def index(): print('welcome to index') time.sleep(1) return 123 res = home('egon') print(f"res: {res}") #res: egon
2、 有参装饰器
1、注意无参装饰器只套两层。
import time current_user = {'username': None} def login(func): # func = 最原始的index def wrapper(*args, **kwargs): if current_user['username']: res1 = func(*args, **kwargs) return res1 user = input('username: ').strip() pwd = input('password: ').strip() if user == 'nick' and pwd == '123': print('login successful') current_user['username'] = user res1 = func(*args, **kwargs) return res1 else: print('user or password error') return wrapper @login def home(name): print(f"welcome {name} to home page") time.sleep(1) @login def index(): print('welcome to index') time.sleep(1) res = index()
username: nick
password: 123
login successful
welcome to index
2、我们首先看看三层闭包怎么运用。
def f1(y): def f2(): x = 1 def f3(): print(f"x: {x}") # x: 1 print(f"y: {y}") # x: 1 return f3 return f2 f2 = f1(2) f3 = f2() f3()
3、应用:有参三层装饰器:
import time current_user = {'username': None} def auth(engine='file'): def login(func): def wrapper(*args, **kwargs): if current_user['username']: res = func(*args, **kwargs) return res user = input('username: ').strip() pwd = input('password: ').strip() if engine == 'file': print('base of file') if user == 'nick' and pwd == '123': print('login successful') current_user['username'] = user res = func(*args, **kwargs) return res else: print('user or password error') elif engine == 'mysql': print('base of mysql, please base of file') return wrapper return login @auth(engine='mysql') def home(name): print(f"welcome {name} to home page") time.sleep(1) @auth(engine='file') def index(): print('welcome to index') time.sleep(1) res = index()
username: nick
password: 123
base of file
login successful
welcome to index
三、迭代器
1、可迭代的对象
Python内置str、list、tuple、dict、set、file都是可迭代对象。
内置有__iter__
方法的都叫可迭代的对象。
x = 1.__iter__ # SyntaxError: invalid syntax # 以下都是可迭代的对象 name = 'nick'.__iter__ lis = [1, 2].__iter__ tup = (1, 2).__iter__ dic = {'name': 'nick'}.__iter__ s1 = {'a', 'b'}.__iter__ f = open('49w.txt', 'w', encoding='utf-8') f.__iter__ f.close()
2、迭代器对象:
执行可迭代对象的__iter__
方法,拿到的返回值就是迭代器对象。只有字符串和列表都是依赖索引取值的,而其他的可迭代对象都是无法依赖索引取值的,只能使用迭代器对象。
- 内置
__next__
方法,执行该方法会拿到迭代器对象中的一个值 - 内置有
__iter__
方法,执行该方法会拿到迭代器本身 - 文件本身就是迭代器对象。
s = 'hello' iter_s = s.__iter__() while True: try: print(iter_s.__next__()) except StopIteration: break
3、for迭代器循环
for循环称为迭代器循环,in后必须是可迭代的对象。
lis = [1, 2, 3] for i in lis: print(i) print(range(10)) # range(0, 10) for i in range(10): print(i)
四、三元表达式
语法:条件成立时的返回值 if 条件 else 条件不成立时的返回值
x = 10 y = 20 print(x if x > y else y) # 20
五、列表推导式
语法:
[expression for item1 in iterable1 if condition1 for item2 in iterable2 if condition2 ... for itemN in iterableN if conditionN ]
举例:
print([i for i in range(10)]) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print([i ** 2 for i in range(10)]) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] name_list = ['nick', 'sean', 'jason', 'tank'] for n in [name if name == 'nick' else name + '_a' for name in name_list] : print(n) # 'nick', 'sean_a', 'jason_a', 'tank_a'
六、字典生成式
print( {i: i**2 for i in range(10)} )
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}
zip()方法
keys = ['name', 'age', 'gender'] values = ['nick', 19, 'male'] res = zip(keys, values) print(res) # <zip object at 0x0000000002233540> info_dict = {k: v for k, v in res} print(info_dict) # {'name': 'nick', 'age': 19, 'gender': 'male'}
通过解压缩函数生成一个字典返回:
info_dict = {'name': 'nick', 'age': 19, 'gender': 'male'} print(info_dict.keys()) # dict_keys(['name', 'age', 'gender']) print(info_dict.values()) # dict_values(['nick', 19, 'male']) res = zip(info_dict.keys(), info_dict.values()) print(res) # <zip object at 0x00000000026939C0> info_dict = {k: v for k, v in res} print(info_dict) # {'name': 'nick', 'age': 19, 'gender': 'male'}
七、生成器
1、yield
生成器的本质就是迭代器
def func(): print(1) yield # 在函数中但凡出现yield关键字,再调用函数,就不会继续执行函数体代码,而是会返回一个值。 print(2) g = func() print(g) # <generator object func at 0x00000000026617B0>
- 提供一种自定义迭代器的方式
- yield可以暂停住函数,并提供当前的返回值
yield和return:
- 相同点:两者都是在函数内部使用,都可以返回值,并且返回值没有类型和个数的限制
- 不同点:return只能返回一次之;yield可以返回多次值
2、自定义range()方法
def my_range(start, stop, step=1): while start < stop: yield start start += 1 g = my_range(0, 3) print(f"list(g): {list(g)}")
复杂版本:
def range(*args, **kwargs): if not kwargs: if len(args) == 1: count = 0 while count < args[0]: yield count count += 1 if len(args) == 2: start, stop = args while start < stop: yield start start += 1 if len(args) == 3: start, stop, step = args while start < stop: yield start start += step else: step = 1 if len(args) == 1: start = args[0] if len(args) == 2: start, stop = args for k, v in kwargs.items(): if k not in ['start', 'step', 'stop']: raise ('参数名错误') if k == 'start': start = v elif k == 'stop': stop = v elif k == 'step': step = v while start < stop: yield start start += step for i in range(3): print(i) # 0,1,2 for i in range(99, 101): print(i) # 99,100 for i in range(1, 10, 3): print(i) # 1,4,7 for i in range(1, step=2, stop=5): print(i) # 1,3 for i in range(1, 10, step=2): print(i) # 1,3,5,7,9
3、生成器表达式
把列表推导式的[]换成()就是生成器表达式 。
优点:省内存,一次只产生一个值在内存中
t = (i for i in range(10)) print(t) # <generator object <genexpr> at 0x00000000026907B0> print(next(t)) # 0 print(next(t)) # 1
举例:
with open('32.txt', 'r', encoding='utf8') as f: nums = [len(line) for line in f] # 列表推导式相当于直接给你一筐蛋 print(max(nums)) # 2 with open('32.txt', 'r', encoding='utf8') as f: nums = (len(line) for line in f) # 生成器表达式相当于给你一只老母鸡。 print(max(nums)) # ValueError: I/O operation on closed file.
八、函数递归
递归的精髓在于通过不断地重复逼近一个最终的结果。
age(1)=26,age(n)=age(n-1)+2 ,求age(5)的值:
''' ... age(5) = age(4) + 2 age(4) = age(3) + 2 age(3) = age(2) + 2 age(2) = age(1) + 2 age(1) = 26 age(n) = age(n-1) +2 age(1) = 26 # n=1 ''' def age(n): if n == 1: return 26 res = age(n-1) + 2 return res print(f"age(5): {age(5)}")
递归的本质就是干重复的活。
lis = [1, [2, [3, [4, [5, [6, ]]]]]] def tell(lis): for i in lis: if type(i) is list: tell(i) else: print(i) tell(lis)
二分法的思想实现查找数字。
from random import randint nums = [randint(1, 100) for i in range(100)] nums = sorted(nums) def search(search_num, nums): print(nums) mid_index = len(nums) // 2 if not nums: print('not exists') return if search_num > nums[mid_index]: # in the right nums = nums[mid_index + 1:] search(search_num, nums) elif search_num < nums[mid_index]: # in the left nums = nums[:mid_index] search(search_num, nums) else: print('find it') search(7, nums)