22

适合初学者的Python装饰器的简易教程

 4 years ago
source link: http://developer.51cto.com/art/202005/616204.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

装饰器是Python编程语言中相当高级的一部分。就像大多数事情一样,一旦你掌握了它们的工作原理并使用了几次,它们就会变得非常简单明了,但是作为一个初学者,它们可能会有点让人望而生畏,很难理解。只有理解了它所解决的问题,你才能真正理解它。例如,我可以直接声明装饰器的定义:

decorator是一个函数,它将另一个函数作为参数并返回它的修改版本,以某种方式增强了它的功能。

如果您已经了解了decorator是什么,那么这个定义就非常清楚了,但是如果您不了解,那么可能就不太了解了。重要的是,这个定义本身并不能告诉您什么时候使用修饰符,或者没有修饰符Python会变得多么糟糕。

fMFfMzm.jpg!web

举例

我们将从一个假设的场景开始,并观察如果不使用decorator可能出现的问题。在你上班的第一天,你的老板找到你,让你写一个函数,这个函数将一个字符串转换成一个回文:一个向前和向后读取相同内容的字符串。

你可以这样写:

def make_palindrome(string): 
  """Makes a palindromic mirror of a string.""" 
   
    return string + string[::-1] 

到目前为止一切顺利。一小时后,老板要求更多的函数:一个credits函数在任何字符串的末尾添加一个字符串,一个函数将字符串转换到另一个字符串中,还有一个函数在字符串中插入逗号。

你开始加入新的函数:

def add_credits(string): 
    """Adds the company's credits to the end of any string.""" 
   
    return f"{string} (string created by Pro String Inc.)" 
 
   
def snake_to_camel(string): 
    """Converts a string in snake_case to camelCase.""" 
   
    words = string.split("_") 
    if len(words) > 1: 
          words = [words[0]] + [word.title() for word in words[1:]] 
    return "".join(words) 
   
   
def insert_commas(string, spacing=3): 
  """Inserts commas between every n characters.""" 
   
  sections = [string[i: i + spacing] for i in range(0, len(string), spacing)] 
  return ",".join(sections) 

但问题出现了。老板看你的代码,并提醒你函数必须能够接受整数作为输入,并且它们应该被转换成字符串。他建议在每个函数的开头加上一行,检查输入是否为整数,如果是整数则进行转换。

这会让你士气低落——你必须把每个功能都检查一遍,然后在开始的时候加上一些类似这样的东西:

if isinstance(string, int):    strstring = str(string) 

当我们有四个需要修改的函数时,这是可以的,但是如果我们有十个呢?让所有的功能都以相同的两行开始违背了神圣的“不要重复自己”的法律准则。

难道没有一种方法可以只修改所有这些函数而不添加额外代码吗?要了解如何做到这一点,让我们回过头来看看Python函数。尽管Python函数有特殊的语法,但它只是一个对象,就像字符串或列表一样。您可以检查它们的属性,将它们分配给新的变量,并且——至关重要的是——将它们作为参数传递给另一个函数。

例如,您可以使一个函数接受另一个函数,并检查它是否有任何关键字参数:

def func_has_kwargs(func):    return len(func.__defaults__) > 0 

不要担心__defaults__如果你还没见过,这里的关键是,函数是另一个函数作为参数,检查是否有任何关键字参数(即如果__default__产权的长度大于0),否则,返回True,如果是这样,则返回False。

现在回到我们的问题之中。我们有三个精心设计的字符串操作函数,我们需要修改它们,使它们也接受整数。我们需要的是一个新函数——它将把我们现有的函数作为输入,并创建一个修改后的函数来检查整数。我们需要一个装饰函数:

e6Rjiaa.jpg!web

让我们仔细看看这里发生了什么。accept_integers是我们的装饰函数——它接受一个函数作为输入,返回另一个函数作为输出。在它的主体中,它创建了一个新函数,该函数应该完成输入函数所做的所有事情,但是在开始时需要一个额外的步骤。如果您查看这个函数的主体,您可以看到它检查给定的字符串是否为整数,如果是整数则转换它,然后将这个字符串传递给原始函数。这里缺少一个步骤——我们需要实际使用这个装饰器:

ayQJF37.jpg!web

标准形式

最后,值得指出的是,虽然上面的语法是完全有效的,但是Python以@符号的形式提供了快捷方式。可以将@accept_integers添加到任何函数的前面来修饰它:

89a03b26bd45236fb886ccc849c3bacd.jpeg

这是将一个函数传递给另一个函数的另一种方式。在底层,当Python看到@符号时,它会为您执行decorator的调用。许多Python库都提供装饰器,以快速增强编写的函数,而不必输入大量重复的代码。

我们对装饰师和所有新编程特性的建议是,首先要学会识别使用该特性的情况——它能解决的问题,以及不使用它所带来的痛苦——然后再学习它是如何工作的。像往常一样,真正理解的唯一方法,就是自己编写一个。所以去做吧​,后浪们。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK