zoukankan      html  css  js  c++  java
  • python闭包(装饰器)参数传递及实现单列模式

    被装饰器装饰的函数名即使没有被调用(因为有@xxx,会触发运行装饰器),(装饰器工厂函数)定义装饰器的代码已经运行了(最内部的那个函数并没有运行)(把被装饰的原函数引用赋值给了装饰器内部的那个函数名),当下边通过该函数名调用时,会调用到装饰器内部的那个函数()

    装饰器:在不修改函数源代码的基础上,添加函数功能

    一个简单的装饰器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def log_time(func):  # 此函数的作用时接受被修饰的函数的引用test,然后被内部函数使用
        def make_decorater():
            print('现在开始装饰')
            func()
            print('现在结束装饰')
        return make_decorater  # log_time()被调用后,运行此函数返回make_decorater()函数的引用make_decorater
     
    @log_time  # 此行代码等同于,test=log_time(test)=make_decorater
    def test():
        print('我是被装饰的函数')
    test()  # test()=make_decorater()
    1
    2
    3
    4
    5
    6
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    现在开始装饰
    我是被装饰的函数
    现在结束装饰
     
    Process finished with exit code 0

     当被装饰的函数有形参时

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def log_time(func):
        def make_decorater(*args,**kwargs):  # 接受调用语句的实参,在下面传递给被装饰函数(原函数)
            print('现在开始装饰')
            test_func = func(*args,**kwargs)  # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回
            print('现在结束装饰')
            return test_func  # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。
        return make_decorater
     
     
    @log_time
    def test(num):
        print('我是被装饰的函数')
        return num+1
     
    = test(2)  # test(2)=make_decorater(2)
    print(a)
    1
    2
    3
    4
    5
    6
    7
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    现在开始装饰
    我是被装饰的函数
    现在结束装饰
    3
     
    Process finished with exit code 0

    当@装饰器后有参数时

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    def get_parameter(*args,**kwargs):  # 工厂函数,用来接受@get_parameter('index.html/')的'index.html/'
        def log_time(func):
            def make_decorater():
                print(args,kwargs)
                print('现在开始装饰')
                func()
                print('现在结束装饰')
            return make_decorater
        return log_time
     
    @get_parameter('index.html/')
    def test():
        print('我是被装饰的函数')
        # return num+1
     
    test()  # test()=make_decorater()
    1
    2
    3
    4
    5
    6
    7
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    ('index.html/',) {}
    现在开始装饰
    我是被装饰的函数
    现在结束装饰
     
    Process finished with exit code 0

     两个装饰器同时修饰一个函数(重点看执行顺序)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    def log_time1(func):
        def make_decorater(*args,**kwargs): 
            print('1现在开始装饰')
            test_func = func(*args,**kwargs) 
            print('1现在结束装饰'
            return test_func 
        return make_decorater
     
    def log_time2(func):
        def make_decorater(*args,**kwargs):  # 接受调用语句的实参,在下面传递给被装饰函数(原函数)
            print('2现在开始装饰')
            test_func = func(*args,**kwargs)  # 如果在这里return,则下面的代码无法执行,所以引用并在下面返回
            print('2现在结束装饰')
            return test_func  # 因为被装饰函数里有return,所以需要给调用语句(test(2))一个返回,又因为test_func = func(*args,**kwargs)已经调用了被装饰函数,这里就不用带()调用了,区别在于运行顺序的不同。
        return make_decorater
     
    @log_time1
    @log_time2
    def test(num):
        print('我是被装饰的函数')
        return num+1
     
    = test(2)  # test(2)=make_decorater(2)
    print(a)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/装饰器.py
    1现在开始装饰
    2现在开始装饰
    我是被装饰的函数
    2现在结束装饰
    1现在结束装饰
    3
     
    Process finished with exit code 0

    注意看执行结果(print,只有执行就会输出到屏幕)(return将数据返回给接受的变量或引用)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    def makeBold(fn):
        def wrapped1():
            print('1')
            = "<b>" + fn() + "</b>"  # 此行fn()调用了wrapped(),所以wrapped()执行了print输出到屏幕,然后fn()接受到了wrapped() return返回的结果"<i>" + fn() + "</i>",所以需要等待wrapped()<br>        print('1end')  # 只有b = "<b>" + fn() + "</b>"执行完毕才会执行这一行,只有wrapped()函数 return返回后,上一行代码才执行<br>      return b
        return wrapped1
     
    def makeItalic(fn):
        def wrapped():
            print('2')
            = return "<i>" + fn() + "</i>"  # 此行fn()调用了test3(),所以test3()执行了,然后fn()接受到了test3()中returnd返回的结果"hello world-3",所以需要等待test3<br>        print('2end')  # 当test3()返回后,上一行代码执行完毕,在屏幕上输出此行<br>        return a
        return wrapped
     
    @makeBold
    @makeItalic
    def test3():
        return "hello world-3"  # return 给了wrapped,wrapped又return给了wrapped;
     
    = test3()  # 此行test3() = wrapped1(),test3()调用了函数所以装饰器才执行。a接受了装饰器return的结果
    print(a)
    1
    2
    3
    4
    5
    6
    D:pycharm_project装饰器venvScriptspython.exe D:/pycharm_project/装饰器/venv/text.py
    1
    2<br>2end<br>1end
    <b><i>hello world-3</i></b>
     
    Process finished with exit code 0

    Python中单例模式的实现方法有多种,但在这些方法中属装饰器版本用的广,因为装饰器是基于面向切面编程思想来实现的,具有很高的解耦性和灵活性。

    单例模式定义:具有该模式的类只能生成一个实例对象。

    先将代码写上

      #创建实现单例模式的装饰器

    1  def singleton (cls, *args, **kwargs):

    2    instances = {}

    3    def get_instance (*args, **kwargs):

    4      if cls not in instances:

    5        instances[cls] = cls(*args, **kwargs)

    6      return instances[cls]

    7    return get_instance

    代码分析:第1行,创建外层函数singleton,可以传入类

         第2行,创建一个instances字典用来保存单例

           第3行,创建一个内层函数来获得单例

           第4,5,6行, 判断instances字典中是否含有单例,如果没有就创建单例并保存到instances字典中,然后返回该单例

           第7行, 返回内层函数get_instance

      #创建一个带有装饰器的类

      @singleton

      class Student:

        def __init__(self, name, age):

          self.name = name

          self.age = age

    在Python中认为“一切皆对象”,类(元类除外)、函数都可以看作是对象,既然是对象就可以作为参数在函数中传递,我们现在来调用Student类来创建实例,看看实现过程。

    #创建student实例

    student = Student(jiang, 25)

    @singleton相当于Student = singleton(Student),在创建实例对象时会先将 Student 作为参数传入到 singleton 函数中,函数在执行过程中不会执行 get_instance 函数(函数只有调用才会执行),直接返回get_instance函数名。

    此时可以看作Student = get_instance,创建实例时相当于student = get_instance(jiang, 25),调用get_instance 函数,先判断实例是否在字典中,如果在直接从字典中获取并返回,如果不在执行 instances [cls] = Student(jiang, 25),然后返回该实例对象并赋值非student变量,即student = instances[cls]。

  • 相关阅读:
    计算机网络基础 汇总
    指针与数组
    卡特兰数
    Leetcode Sort Colors
    Leetcode Group Shifted Strings
    Leetcode Summary Ranges
    Leetcode Count Primes
    Leetcode Reverse Words in a String II
    Leetcode Reverse Words in a String
    Leetcode Rotate Array
  • 原文地址:https://www.cnblogs.com/fcc-123/p/11842108.html
Copyright © 2011-2022 走看看