Почему использование ** kwargs в Python? Каковы некоторые преимущества реального мира перед использованием параметров, передаваемых по имени?

Мое предпочтение должно сохранить сторонние библиотеки в репозитории зависимости ( Artifactory с Знаток , например) вместо того, чтобы сохранить их в Подрывной деятельности.

, Так как сторонними библиотеками не управляют или имеющими версию как исходный код, он не имеет много смысла смешать их. Удаленные разработчики также ценят не необходимость загрузить крупные библиотеки по медленной ссылке WPN, когда они могут получить их более легко от любого количества общедоступных репозиториев.

64
задан binary lobster 13 November 2014 в 20:44
поделиться

8 ответов

Примеры из реальной жизни:

Декораторы - обычно они общие, поэтому вы не можете заранее указать аргументы:

def decorator(old):
    def new(*args, **kwargs):
        # ...
        return old(*args, **kwargs)
    return new

Места, с которыми вы хотите творить чудеса. неизвестное количество аргументов ключевого слова. ORM Django делает это, например:

Model.objects.filter(foo__lt = 4, bar__iexact = 'bar')
38
ответ дан 24 November 2019 в 15:44
поделиться

Вы можете принять аргументы с почти произвольными именами по ряду причин - и это то, что позволяет вам сделать форма ** квт .

Самая распространенная причина - передать аргументы прямо в какую-то другую функцию, которую вы обертываете (декораторы - один из случаев этого, но ДАЛЕКО от единственной!) - в данном случае ** квт ослабляет связь между оболочкой и wrappee, поскольку оболочке не нужно знать или заботиться обо всех аргументах wrappee. Вот еще одна, совершенно другая причина:

d = dict(a=1, b=2, c=3, d=4)

если все имена нужно было знать заранее, то очевидно, что такого подхода просто не могло быть, верно? И между прочим, когда это применимо, я предпочитаю этот способ создания диктовки, ключи которого являются буквальными строками, чем:

d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}

просто потому, что последний содержит много знаков пунктуации и, следовательно, менее читабелен.

Когда нет веских причин для принятия ** kwargs применимо, тогда не принимайте его: это так просто. IOW, если есть ' s нет веской причины разрешать вызывающей стороне передавать дополнительные именованные аргументы с произвольными именами, не позволяйте этому случаться - просто не помещайте форму ** kw в конце сигнатуры функции в def оператор.

Что касается с использованием ** kw в вызове, который позволяет вам собрать точный набор именованных аргументов, которые вы должны передать, каждый с соответствующими значениями , в dict, независимо от единственной точки вызова, затем используйте этот dict в единственной точке вызова. Сравните:

if x: kw['x'] = x
if y: kw['y'] = y
f(**kw)

to:

if x:
  if y:
    f(x=x, y=y)
  else:
    f(x=x)
else:
  if y:
    f(y=y)
  else:
    f()

Даже при наличии всего двух возможностей (и самого простого!) Отсутствие ** квт уже делает второй вариант абсолютно неприемлемым и невыносимым - просто представьте, как это разыграется, когда есть полдюжины возможностей, возможно, в немного более богатом взаимодействии ...

61
ответ дан 24 November 2019 в 15:44
поделиться

Еще одна причина, по которой вы можете захотеть использовать ** kwargs * args ), - это расширение существующего метода в подклассе. Вы хотите передать все существующие аргументы в метод суперкласса, но хотите, чтобы ваш класс продолжал работать, даже если подпись изменится в будущей версии:

class MySubclass(Superclass):
    def __init__(self, *args, **kwargs):
        self.myvalue = kwargs.pop('myvalue', None)
        super(MySubclass, self).__init__(*args, **kwargs)
40
ответ дан 24 November 2019 в 15:44
поделиться

** kwargs хороши, если вы заранее не знаете названия параметров. Например, конструктор dict использует их для инициализации ключей нового словаря.

 dict (** kwargs) -> новый словарь, инициализированный парами имя = значение
в списке аргументов ключевого слова. Например: dict (один = 1, два = 2)
In [3]: dict(one=1, two=2)
Out[3]: {'one': 1, 'two': 2}
4
ответ дан 24 November 2019 в 15:44
поделиться

Есть два типичных случая:

Первый: вы обертываете другую функцию, которая принимает ряд аргументов ключевого слова, но вы просто собираетесь передать их:

def my_wrapper(a, b, **kwargs):
    do_something_first(a, b)
    the_real_function(**kwargs)

Во-вторых: вы готовы принять любой аргумент ключевого слова, например, для установки атрибутов объекта:

class OpenEndedObject:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

foo = OpenEndedObject(a=1, foo='bar')
assert foo.a == 1
assert foo.foo == 'bar'
11
ответ дан 24 November 2019 в 15:44
поделиться

Вот пример, который я использовал в CGI Python. Я создал класс, который преобразовал ** kwargs в функцию __ init __ . Это позволило мне эмулировать DOM на стороне сервера с помощью классов:

document = Document()
document.add_stylesheet('style.css')
document.append(Div(H1('Imagist\'s Page Title'), id = 'header'))
document.append(Div(id='body'))

Единственная проблема в том, что вы не можете сделать следующее, потому что класс является ключевым словом Python.

Div(class = 'foo')

Решение состоит в следующем. для доступа к базовому словарю.

Div(**{'class':'foo'})

Я не говорю, что это «правильное» использование функции. Я говорю о том, что существуют всевозможные непредвиденные способы использования подобных функций.

3
ответ дан 24 November 2019 в 15:44
поделиться

А вот еще один типичный пример:

MESSAGE = "Lo and behold! A message {message!r} came from {object_} with data {data!r}."

def proclaim(object_, message, data):
    print(MESSAGE.format(**locals()))
1
ответ дан 24 November 2019 в 15:44
поделиться

Одним из примеров является реализация связывателей аргументов python , используемых следующим образом:

 >>> from functools import partial
>>> def f (a, b):
... вернуть a + b
>>> p = частичное (f, 1, 2)
>>> p ()
3
>>> p2 = частичное (f, 1)
>>> p2 (7)
8

Это из functools.partial документации python: partial «относительно эквивалентно» этому impl:

 def partial (func, * args, ** keywords):
 def newfunc (* fargs, ** fkeywords):
 newkeywords = keywords.copy ()
 newkeywords.update (fkeywords)
 return func (* (args + fargs), ** newkeywords)
 newfunc.func = func
 newfunc.args = args
 newfunc.keywords = ключевые слова
 вернуть newfunc
0
ответ дан 24 November 2019 в 15:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: