pythond_递归、回调函数、闭包、装饰器

一。递归

递归概念:在函数中调用函数本身

举例(方法一不使用递归,方法二使用递归。):

"""遍历目录:输出文件夹下的所有文件;需要了解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))

 

posted @ 2021-03-26 20:10  1142783691  阅读(161)  评论(0编辑  收藏  举报