TypeScript基础入门之装饰器(三)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript基础入门之装饰器(三)相关的知识,希望对你有一定的参考价值。

参考技术A 继续上篇文章[ TypeScript基础入门之装饰器(二) ]

Accessor Decorator在访问器声明之前声明。 访问器装饰器应用于访问器的属性描述符,可用于观察,修改或替换访问者的定义。 访问器装饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。

访问器装饰器的表达式将在运行时作为函数调用,具有以下三个参数:

如果访问器装饰器返回一个值,它将用作该成员的属性描述符。

以下是应用于Point类成员的访问器装饰器( @configurable )的示例:

我们可以使用以下函数声明定义@configurable装饰器:

Property Decorator在属性声明之前声明。 属性修饰器不能在声明文件中使用,也不能在任何其他环境上下文中使用(例如在声明类中)。

属性装饰器的表达式将在运行时作为函数调用,具有以下两个参数:

我们可以使用此信息来记录有关属性的元数据,如以下示例所示:

然后我们可以使用以下函数声明定义@format装饰器和getFormat函数:

这里的 @format ("Hello,%s")装饰器是一个装饰工厂。 当调用 @format ("Hello,%s")时,它会使用reflect-metadata库中的Reflect.metadata函数为该属性添加元数据条目。 调用getFormat时,它会读取格式的元数据值。

注意此示例需要reflect-metadata库。 有关reflect-metadata库的更多信息,请参阅元数据。

参数装饰器在参数声明之前声明。 参数装饰器应用于类构造函数或方法声明的函数。 参数装饰器不能用于声明文件,重载或任何其他环境上下文(例如声明类中)。

参数装饰器的表达式将在运行时作为函数调用,具有以下三个参数:

将忽略参数装饰器的返回值。

以下是应用于Greeter类成员参数的参数装饰器( @required )的示例:

然后我们可以使用以下函数声明定义@required和@validate装饰器:

@required装饰器添加一个元数据条目,根据需要标记参数。 然后,@validate装饰器将现有的greet方法包装在一个函数中,该函数在调用原始方法之前验证参数。

一些示例使用reflect-metadata库,它为实验元数据API添加了polyfill。 该库尚未成为ECMAScript(JavaScript)标准的一部分。 但是,一旦装饰器被正式采用为ECMAScript标准的一部分,这些扩展将被提议采用。

您可以通过npm安装此库:

TypeScript包含实验支持,用于为具有装饰器的声明发出某些类型的元数据。 要启用此实验性支持,必须在命令行或tsconfig.json中设置emitDecoratorMetadata编译器选

命令行:

tsconfig.json:

启用后,只要导入了reflect-metadata库,就会在运行时公开其他设计时类型信息。

我们可以在以下示例中看到这一点:

TypeScript编译器将使用@ Reflect.metadata装饰器注入设计时类型信息。 你可以认为它相当于以下TypeScript:

Python入门之函数的装饰器

本章目录:

    装饰器:

 

        一、为什么要用装饰器

 

        二、什么是装饰器

 

        三、无参装饰器

 

        四、装饰器语法糖

 

        五、认证装饰器实现

 

        六、叠加多个装饰器

 

        七、带参装饰器   

===========================================================

 

一、开放封闭原则

 

  引子--为什么要用装饰器

  软件一旦上线后,对修改源代码是封闭的,对功能扩展是开放的。

  也就是说我们必须找到一种解决方案:

    能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能

    

    总结,原则如下:

      1、不修改源代码

      2、不修改调用方式

 

    目的:

      在原则1&2的基础上扩展新功能

 

二、什么是装饰器

 

  装饰器(Decorator)是一种特殊的函数,用来给函数添上新功能的函数。

  主要用于抽离大量函数中与函数本身无关的雷同代码并继续重用。

  装饰器又可分为带参数和不带参数。

 

  完整含义:

  装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能

 

  装饰器与被装饰对象均可以是任意可调用的对象

 

  装饰器>>>函数

  被装饰的对象>>>函数

 

三、装饰器实现之无参装饰器

 

  装饰器的实现不能脱离,不能修改源代码,不能修改源调用方式的原则。下面我们将按照实现装饰器的思路,一步一步实现装饰器。

  为下面的程序增加运行计时功能。

import time

def index():
    
   time.sleep()
   print(\'This is Index Page!\')    

 

  方案1:

import time

def index():
    start_time=time.time()
    time.sleep(3)
    print(\'welcome to index page\')
    stop_time=time.time()
    print(\'run time is %s\' %(stop_time-start_time))

index()
# 该方案虽然达到了计时功能,但是修改了源代码,违背了装饰器两大原则

 

   方案2:

import time   #引入时间包,方便调用time()方法


def index():
    time.sleep(2)
    print(\'This is Index Page.\')


start_time = time.time()
index()
stop_time = time.time()
print(\'The running time is %s\' % (stop_time - start_time)
# 该方案虽然达到了计时功能,但是只是针对的增加代码,如果别的程序也要计时,还要重写一次,无法复用。

 

  方案3:

import time


def index():
    time.sleep(2)
    print(\'This is Index Page\')


def wrapper():
  start_time = time.time()
  index()
  stop_time = time.time()   
  print(\'The running time is %s\' % (stop_time - start_time)) 
# 该方案虽然达到了计时功能,但是要显示计时,还要去调用wrapper(),更改了原函数的调用方式

 

  方案4:

import time


def index():
    time.sleep(2)
    print(\'This is Index Page\')


def wrapper(func):    #func = index
    
    start_time = time.time()
    func();      #index
    stop_time = time.time()
    print(\'The running time is %s\' % (stop_time, start_time))


wrapper(index)
# 该方案虽然达到了计时功能,但是要显示计时,不仅要调用wrapper(), 而且需要把原函数index作为参数导入,更改了原函数的调用方式

 

  方案5(步入正轨之无参装饰器):

import time


def index():
    time.sleep()
    print(\'This is Index Page\')


def outter(func):     # func = 最初始的index
                      # func = index    巧用闭包,传递参数,
                      # 外部函数带的参数,就是准备给内部函数里用的,这里是闭包功能
    def wrapper(): 
        start_time = time.time()
        func()
        stop_time = time.time()
        print(\'The running time is %s\')
    return wrapper

index = outter(index)   #初始index函数经过处理已经被变更为outter(index),被\'\'装饰\'\'了

index()
# 该方法能显示运行时长, 是把最初始的index函数通过闭包的特点,经过处理后重新把新的函数内存地址,赋值给了index,后面的index函数已经不是最初的index,它经过被\'\'装饰\'\'了

 

  方案6(方案5的升级版):

    1. 无参装饰器,引入带参函数的时候出现了错误。

# 不同于index()函数,这次我们引入一个新函数,带参数call_you(name)
import time


def call_you(name):
    time.sleep(2)
    print(\'I call you %s\' %name)

def outter(func):
    
    def wrapper(name):
        start_time = time.time()
        res = func(name)
        stop_time = time.time()
        print(\'The running time is %s\' % (stop_time - start_time)
        return res

    return wrapper

index = outter(index)
home = outter(home)  #home带参,但是index不带参,这里运行会报错

 

  方案7(解决方案6的问题):

# 运用可变长度参数处理这个问题
# 可变长度参数模版,注意参数是*args  **kwargs

def outter(func):

    def inner(*args, **kwargs):
        res = func(*args, ** kwargs)
        return res

    return inner
import time


def call_you(name):
    time.sleep(2)
    print(\'I call you %s\' %name)


def outter(func):

        def wrapper(*args, **kwargs):
            start_time = time.time()
            res = func(*args, **kwargs)
            stop_time = time.time()
            print(\'The running time is %s\' %(stop_time - start_time))
            return res
        return wrapper

call_you
= outter(call_you) call_you(\'Puppy\')

 

四、装饰器语法糖

  语法糖意指那些没有给计算机添加新功能,只是对人类来说更加“甜蜜”的语法,能够增加程序的可读性,减少代码出错的机会。

# 注意语法糖的放置位置,放在要用的函数的顶部,要用@开头

 

 

五、认证装饰器实现

 

  1. 加入认证模块的简单实现:

 

  2. 加入认证模块后登陆进行验证:

 

 

六、叠加多个装饰器
# 注意多个装饰器的顺序,按照顺序执行

 

  1. 认证装饰器

  

  2. 计时装饰器

  

  3. 叠加多个装饰器(注意先后顺序)

 

七、带参装饰器
 
带参数,可以让装饰器有更大的灵活性。上面写的无参装饰器唯一的参数就是执行对应的业务函数。装饰器的语法允许我们在调用的时候,提供其他参数。新增的参数为装饰器的编写和使用提供了更大的灵活性
 
 
上面的use_logging是允许带参数的装饰器。它实际上是对原有装饰器的 一个函数封装,并返回一个装饰器。我们可以将它理解为一个含有参数的闭包。
当我们调用的时候,Python能够发现这一层封装,并把参数传递到装饰器的环境中。

 

以上是关于TypeScript基础入门之装饰器(三)的主要内容,如果未能解决你的问题,请参考以下文章

Python入门之函数的装饰器

Python 基础入门 5_2 function 函数

Python之路,第十二篇:Python入门与基础12

《C#零基础入门之百识百例》(四十六)类的索引 -- 数组索引器

《C#零基础入门之百识百例》(九十一)预处理器指令 -- 代码示例

《C#零基础入门之百识百例》(九十一)预处理器指令 -- 代码示例