python:构造函数参数表示法

python: constructor argument notation

我学习了几个月 python。 通过金字塔教程后,我无法理解 init.py

中的一行
from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )



def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.include('pyramid_chameleon')
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home', '/')
    config.scan()
    return config.make_wsgi_app()

我不知道配置器参数中的 settings=settings。

这说明了什么 python?

这意味着您正在将参数 settings 传递给 Configurator,其中包含一个名为 settings[=26 的变量=]

举个例子,你有一个函数:

def function_test(a=None, b=None, c=None):
    pass

你可以这样称呼它:

c = "something"
function_test(c=c)

这意味着您将创建的变量 c 作为参数传递给函数 中的参数 c function_test

Python 函数支持关键字参数:

def add(a, b):
    return a + b

add(a=1, b=2)

这发生在这里。

 Configurator(settings=settings)

第一个settingsConfigurator__init__中的参数名。第二个是当前名称中对象的名称 space.

这是说它正在传递本地名称 settings 作为 Configurator 中名为 settings 的参数。

对于 x=y 形式的函数或构造函数调用,x 是在 function/constructor 端本地使用的参数名称,而 y 是名称在来电方。在这种情况下,它们恰好是同一个名字。

Python 支持调用任何可调用对象(即函数、构造函数,甚至对象理解 __call__ 方法)指定位置参数、命名参数,甚至两种类型的参数。

当您传递命名参数时,它们必须位置参数之后(如果传递的话)。

因此您可以调用任何函数,例如:

def f(a, b):
    return a + b

通过以下方式:

f(1, 2)
f(1, b=2)
f(a=1, b=2)
f(b=1, a=2) # Order doesn't matter among named arguments

而以下形式会触发错误:

f(a=1, 2) # Named arguments must appear AFTER positional arguments
f(1, a=2) # You are passing the same argument twice: one by position, one by name

因此,当您传递一个命名参数时,请确保您没有传递相同的参数两次(即也按位置),并检查参数名称是否存在(另外:如果记录了参数could/should名传千里,敬inheritance/override).

另外 Python支持传递*arguments**keyword_arguments。这些是您可以以可变方式处理的附加参数,因为许多语言都支持它们。

*args(名称无关紧要 - 它必须有一个星号才能成为位置可变参数;它是一个元组)保留剩余的 unmatched 位置参数(而不是位置参数意外出现 TypeError,这样的参数作为元素进入 *args)。

**kwargs(名称无关紧要 - 它必须有两个星号才能成为 named/keyword 可变参数;它是一个字典)包含剩余的 unmatched 命名参数(而不是为命名参数意外获取 TypeError,这样的参数作为元素进入 **kwargs)。

所以,也许您会看到这样的函数:

def f(*args, **kwargs):
    ...

您可以使用任何您想要的参数来调用它:

f(1, 2, 3, a=4, b=5, c=6)

保持顺序:命名参数在位置参数之后。

您可以这样声明一个函数:

f(m1, m2, ..., o1=1, o2=2, ..., *args, **kwargs):
    pass

了解以下内容:

  • m1、m2、... 强制性:调用时,必须按照位置或名称填写。
  • o1, o2, ... 是 可选的:当你调用时,你可以省略这些参数(省略它们意味着不按位置或按名称传递它们),并且它们将保留等号后的值(此类值在函数声明时计算 - 避免使用可变对象作为它们的值)。
  • args 和 kwargs 是我之前向您解释的:任何按位置和名称不匹配的参数都会进入这些参数。有了这些特性,你就可以清楚地区分什么是形参,什么是实参。
  • 所有这些参数都是可选的。您可以选择不使用强制性的,而只使用可选的。您可以选择不使用 *args 但使用 **kwargs,依此类推。但是尊重声明中的顺序:强制,可选,*args**kwargs

当你调用方法并传递参数时语义非常不同所以要小心:

f(1) # passes a positional argument. Has nothing to do with the parameter being mandatory.
f(a=1) # passes a named argument. Has nothing to do with the parameter being optional.
f(**i) # UNPACKS the positional arguments. Has nothing to do with the function having a *args parameter, but *args will hold any unpacked -but unmatched- positional argument from i (which is any type of sequence or generator)
f(**d) # UNPACKS its values as named arguments. Has nothing to do with the function having a **kwargs parameter, but **kwargs will hold any unpacked -but unmatched- argument from d (which is a dict having string keys).

当你调用的时候,你可以随意传递它们,这与实际的方法签名无关(即预期的参数),但是 尊重参数的顺序:positional, named, *positionalUnpack, **keywordUnpack,否则你会得到一个很好的 TypeError.

示例:

def f(a, b=1, *args, **kwargs):
    pass

有效调用:

f(1) # a = 1, b = 2, args = (), kwargs = {}
f(*[1]) #a = 1, b = 2, args = (), kwargs = {}
f(*[3, 4]) #a = 3, b = 4, args = (), kwargs = {}

f(**{'a':1, 'b':3}) #a = 1, b=3, args = (), kwargs = {}
f(1, *[2, 3, 4], **{'c': 5}) #a = 1, b=2, args=(3, 4), kwargs = {'c': 5}

再次注意:

  • 不要传递相同的参数两次(**解压参数与其他命名参数、位置参数或*解压参数之间会发生冲突)。
  • 如果要将 *args 或 **kwargs 传递给 super 调用,请确保使用解包语法:

    def my_method(self, a, b, *args, **kwargs):
        super(MyClass, self).my_method(a+1, b+1, *args, **kwargs)