zoukankan      html  css  js  c++  java
  • 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))
    爱折腾的小测试
  • 相关阅读:
    Java入门——数组和方法
    Java入门——选择与循环语句
    Java入门——面向对象基础
    十天学会Oracle数据库(Day2)
    Java入门——理解面向对象:UML设计
    十天学会Oracle数据库(Day1)
    Codeforces Round #482 (Div. 2) :B
    Codeforces Round #482 (Div. 2) :C
    Codeforces Round #490 (Div. 3) :F. Cards and Joy(组合背包)
    POJ-2155:Matrix(二维树状数祖)
  • 原文地址:https://www.cnblogs.com/newsss/p/14583959.html
Copyright © 2011-2022 走看看