一。递归
递归概念:在函数中调用函数本身
举例(方法一不使用递归,方法二使用递归。):
"""遍历目录:输出文件夹下的所有文件;需要了解python中的栈"""
import os
# 方法一:使用os.walk 完成
def print_all_files(file_path):
"""
文件操作
:param file_path: 路径
:return: 返回file_path目录下的所有文件信息
"""
for root, dirs, files in os.walk(file_path):
"""root =>目录的根路径 ;dirs =>根目录下的文件夹 ; files =>文件夹下文件信息"""
for filename in files:
# print(root,files)
print(os.path.join(root, filename))
# 方法二:使用递归 ;递归:在函数中调用函数本身
def print_all_files2(file_path):
"""
思路:1。获得file_path下的所有文件及文件夹;使用os.scandir(file_path)方法【python3.5中新增的方法,比os.listdir(file_path)效率更高,速度更快】
2.进行判断如果是文件直接返回,如果是文件夹继续递归调用 print_all_files2(文件夹) 方法
"""
for item in os.scandir(file_path):
# item可以是文件或者文件夹
if item.is_file():
print(item.path) #输出文件夹下的所有文件
elif item.is_dir():
# item.path 返回的是根目录下的所有文件夹
print_all_files2(item.path)
else:
print("出故障了")
# 递归:函数里面调用自身若干次如下:
def recoder(n):
print(f"这是第{n}层打印")
if n <= 1:
return None #结束递归,不结束就会无限递归
else:
n -= 1 #每递归一次,把层数-1
#调用自身
recoder(n)
if __name__ == '__main__':
p = r"E:pythons_opens_devs"
print_all_files2(p)
recoder(10)
二。回调函数
概念:(回调模式)如果一个函数的参数是函数类型,那么我们可以把这个参数叫做回调函数
# 举栗:
# 比较两个数字的大小,并用不同风格输出。例如:比较 1 和 2 大小并输入 最小值,输出案例:1和2比较,最小的是1
def get_min(a, b, fuc):
# fuc是回调函数的引用
result = a if a < b else b
fuc(a, b, result) #回调
f() #普通调用
def call_back_print_en(a, b, _min):
print(f"compare {a} and {b},min = {_min}")
def f():
pass
if __name__ == '__main__':
get_min(1, 2, call_back_print_en)
三。闭包
概念:通过函数中定义函数的方法,获得函数里面的局部变量
""""
闭包也是一个函数
需求:检测任意函数的参数不运行函数
"""
import logging
# 例子1:
def f1(a, b):
pass
def f2(x, y):
pass
# 用闭包实现
def logger(func):
def log_func(*args):
print(f"{args}返回")
logging.basicConfig(filename="demo.log", level=logging.INFO)
logging.info(f"{func.__name__} is running, arguments is {args}")
# 返回log_func 不加括号,这里是闭包
return log_func # 把log_func函数的引用 传给 logger的调用者
# f1_logger = logger(f1)
# f2_logger = logger(f2)
#
# f1_logger(1,2)
# f2_logger(10,20)
# 例子2:
def outer_function(n):
num = n
def inner_function():
# 修改变量 num
# nonlocal 一般用在嵌套函数中
nonlocal num # global(全局) local(局部) nonlocal(不在本局部,但不是全局:即在其他局部,也就是他的上一级)
num -= 1
print(num)
# 不加括号,返回inner_function()函数的函数名(即引用)
return inner_function
# 一般情况,函数结束,函数里面所有局部变量都会被销毁
# 问:函数调用结束后,我怎么才能获得函数里面的局部变量?
# 回答:使用闭包(在函数里面再定义一个函数,把局部变量暴露给外部)
my_func = outer_function(3)
my_func()
# 例子3:写一个方法,实现 记录某个函数被调用的次数
#闭包实现:某个函数 当做内层函数,外部的函数加一个C变量用来统计内层函数调用的次数
def outer():
c = 0 #用来记录inner调用的次数
def some_funtion():
nonlocal c
c += 1
print(c)
return some_funtion
count_some_fution = outer()
count_some_fution() #1
count_some_fution() #2
四。装饰器
1)装饰器是什么?
举栗:手机与手机保护套的关系;没做美甲前与做完美甲后的关系。 都是装饰某人或某物
2)装饰器的实现原理:
from types import FunctionType
#装饰器的写法1,不带参数的函数方法:
def add_itali(func: FunctionType):
"""接收一个函数,返回一个经过修饰的新函数"""
def new_func():
return "<i>" + func() + "</i>"
return new_func
def text():
return "hello"
调用:
if __name__ == '__main__':
#运行过程:先将方法text方法当成参数传进装饰器函数中,然后再调用装饰器的函数方法
new_function = add_itali(text)
new_text = new_function()
print(new_text)
3)装饰器的使用:
在需要使用装饰器的函数方法上使用:@func (func为装饰器函数方法)
from types import FunctionType
def add_itali(func: FunctionType):
"""接收一个函数,返回一个经过修饰的新函数"""
def new_func():
return "<i>" + func() + "</i>"
return new_func
def add_bold(func: FunctionType):
def new_func():
s = func()
return "<b>" + s + "</b>"
return new_func
#@add_itali #@符号叫做“语法糖”
@add_bold
def text():
return "hello"
if __name__ == '__main__':
print(text())
4)怎么为类(未带参数的类)添加装饰器
def some_func(cls):
print("这是类方法")
return cls
def add_bold(cls):
def new_func():
s = cls().a
return "<b>" + s + "</b>"
return new_func
#@some_func
@add_bold
class A(object): #给类添加装饰器
a = "hello"
pass
if __name__ == '__main__':
print(A())
5)怎么使用类装饰某个函数方法
注意:类方法与函数方法区别,函数方法把函数当作参数传入并调用是可以,类就不行,因为类方法中缺少了__call__ 内置方法
(1)__call__:看对象能不能加括号
举例:list
nums = [1,2,3]
print(nums, hasattr(nums, '__call__')) #[1, 2, 3] False
如果加括号执行是不行的,换过来讲 函数、类 能不能执行,也需要看有没有'__call__'属性
nums() #报错:TypeError: 'list' object is not callable
(2)@类方法 等同于(类方法参考举栗部分):
a = A(f)
a(1,2)
(3)方法f中的 return 返回结果 不等于 A类中的返回:
比如:f 函数中返回 x + b ; 类中的__call__方法中返回 none 那么最终返回的就是 none
举栗:
class A(object):
def __init__(self, func): # 返回一个对象:__init__方法首先会初始化对象,并把对象返回。
self.func = func
print('~~~~~~')
def __call__(self, *args, **kwargs): # __call__当对一个对象加()进行调用的时候,此方法会自动执行
print(f"{self.func.__name__}函数运行前")
obj = self.func(*args, **kwargs)
print(f"{self.func.__name__}函数运行后")
return obj
@A # 类,f会传给类,然后返回一个A的实例
def f(x, b):
print("这里是运行方法")
return x + b
if __name__ == '__main__':
'''
不加装饰器的写法,等同于@A
a = A(f)
print(type(a))
# a(1, 2) # 若类方法中不加__call__内置方法则会报错:TypeError: 'A' object is not callable
'''
print(f(1, 2))
6)实现带参数的装饰器:
"""
用途:
写一个用来记录日志的装饰器
@log(filename='info.log')
def add(a,b):
'''
@log(filename='error.log')
def mods(item):
'''
"""
print("hello")
def log(filename: str):
print(filename)
def inner(func):
print(f"{func.__name__}")
#执行add函数
def wrapper(*args, **kwargs):
print(args)
func(*args, **kwargs)
return wrapper
return inner
@log(filename='xxx.log')
def add(a, b):
return a + b
if __name__ == '__main__':
print(add(1, 2))