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]。

  • 相关阅读:
    1026 Table Tennis (30)
    1029 Median
    1025 PAT Ranking (25)
    1017 Queueing at Bank (25)
    1014 Waiting in Line (30)
    1057 Stack (30)
    1010 Radix (25)
    1008 Elevator (20)
    字母大小写转换
    Nmap的基础知识
  • 原文地址:https://www.cnblogs.com/fcc-123/p/11842108.html
Copyright © 2011-2022 走看看