需要帮助理解一些使用@,* args和** kwargs的Python代码

时间:2010-06-13 17:15:56

标签: python

我是Python的新手,并且被Boto项目中的这段代码所困扰:

class SubdomainCallingFormat(_CallingFormat):
    @assert_case_insensitive
    def get_bucket_server(self, server, bucket):
        return '%s.%s' % (bucket, server)

def assert_case_insensitive(f):
    def wrapper(*args, **kwargs):
        if len(args) == 3 and not (args[2].islower() or args[2].isalnum()):
            raise BotoClientError("Bucket names cannot contain upper-case " \
            "characters when using either the sub-domain or virtual " \
        "hosting calling format.")
        return f(*args, **kwargs)
    return wrapper

试图了解这里发生了什么。

  1. @assert_case_sensitive中的'@'符号是什么?
  2. args *args, **kwargs是什么意思?
  3. 'f'代表什么?
  4. 谢谢!

4 个答案:

答案 0 :(得分:6)

@符号用于表示decorator的应用。

这些星号表示参数为excess positional/keyword arguments put into a list/dictionary

“f”表示作为第一类对象传入装饰器的函数。有人写的时候

@decorate
def whizbang(): pass

它真的等同于

def whizbang(): pass
whizbang = decorate(whizbang)

本手册更详细,但装饰器基本上是一种用现有代码包围的代码,可以在其前后执行,而无需修改您正在装饰的代码。一切都具有一流功能的魔力。

答案 1 :(得分:4)

@assert_case_sensitive中的'@'符号是什么?

@是装饰器语法,基本上是:

@decor
def func(arg):
    pass

相当于:

def func(arg):
    pass
func = decor(func)

args * args是什么,** kwargs是什么意思?

* args和** kwargs是参数解包。它类似于C的varargs,因为任何多余的未命名参数都将转到* args元组,而无法识别的命名参数将转到** kwargs dict。

def foo(a, *arg, **kwarg):
    print a      # prints 1
    print arg    # prints (2, 3)
    print kwarg  # prints {'foo': 4}

foo(1, 2, 3, foo=4)

'f'代表什么?

这是python的高级功能。基本上在python中,一切都是包含函数的对象。由于函数是一个对象,因此可以将函数作为参数传递给另一个函数。如果这是C,则类似于传递函数指针。

答案 2 :(得分:4)

在这种特殊情况下,assert_case_sensitive是一个函数包装函数,也称为decorator

装饰器接受现有函数并返回不同的函数。通常它返回一个以某种方式调用原始函数的新函数。在这种情况下,assert_case_insensitive始终返回wrapper,这是一个在其中定义的函数,其名称仅在assert_case_insensitive内知道。

当一个函数在另一个函数体中声明时,每次调用外部函数时,封闭函数都会重新创建。这意味着内部函数可以访问它所在函数中的变量。

此技术称为closure,Python对闭包的支持不完整,因为无法修改封闭范围内的变量。但这与这个问题并不十分相关。

assert_case_insensitive的目标是对它传递的函数的参数强制执行某些条件。它返回一个新函数,强制执行这些条件并调用原始函数。为了使assert_case_insensitive能够用于包装任何函数,它需要用于具有不同数量的参数的函数,以及具有关键字参数的函数。这是*args**kargs进来的地方。

*something形式的参数获得任何剩余的非关键字(也称为位置)参数的元组,这些参数不会被先前的位置参数所占据。 **something形式的参数获取字典中任何剩余的关键字参数,这些参数不会被先前的位置参数解释。 *something**something形式的参数必须在所有其他参数之后出现。

类似的语法用于调用具有不知道的参数列表的函数。形式*(iterable sequence)的参数变成一系列位置参数,形式**(dictionary)的参数变成一组关键字参数。

所以wrapper正在使用这些结构,因此它可以非常适用于任何函数。一般来说装饰器可以用于任何功能,因此在编写时强烈建议这样做。

答案 3 :(得分:1)

@assert_case_sensitive这里是来自维基百科的装饰器的解释:

装饰器是一个Python对象,可以使用单个参数调用,并修改函数或方法。 Python装饰器的灵感部分来自Java注释,并具有类似的语法;装饰器语法是纯粹的语法糖,使用@作为关键字:

@viking_chorus
def menu_item():
    print "spam"

相当于

def menu_item():
    print "spam"
menu_item = viking_chorus(menu_item)