__init __ () получил несколько значений для аргумента ключевого слова 'bar' - PullRequest
0 голосов
/ 09 мая 2019

То, что кажется простым шаблоном для разрешения переменного числа позиционных аргументов вместе со стандартным именем arg, не работает.Я думаю, что могу преодолеть это с помощью **kwargs, но есть ли что-то более простое, что я делаю неправильно?

Почему это не работает?

class Foo(obect):
    """Baffling"""
    def __init__(self, bar=None, *args):
        pass

foo = Foo(1) #works
foo = Foo(1, bar=2) # explodes

----> 1 foo = Foo(1, bar='baz')
TypeError: __init__() got multiple values for keyword argument 'bar'

Как работает код вышеПередача дубликата bar аргумента ключевого слова?

Ответы [ 2 ]

2 голосов
/ 09 мая 2019

Именованные аргументы могут передаваться как по позиции, так и по имени:

>>> def foo(a):
...     print(a)
...
>>> foo(1)
1
>>> foo(a=2)
2

Если вы передадите позиционные и ключевые слова, они будут назначены в порядке.В вашем случае 1 присваивается первому позиционному аргументу (bar), затем bar=2 присваивает аргумент с именем bar.Таким образом, оба присваивают имя bar, создавая конфликт.


Вы можете передать дополнительные аргументы после вашего имени:

>>> def foo(bar=None, *args):
...    print('args=%r, bar=%r' % (args, bar))
...
... foo(2, 1)  # bar=2, *args=(1,)
args=(1,), bar=2

ВPython3, вы также можете сделать только ключевое слово вашего параметра:

>>> def foo(*args, bar=None):
...    print('args=%r, bar=%r' % (args, bar))
...
... foo(1, bar=2)
args=(1,), bar=2

Это также работает, если вы не принимаете никаких переменных аргументов:

>>> def foo(*, bar=None):
...    print('args=%r, bar=%r' % ('undefined', bar))
...
... foo(bar=2)
args='undefined', bar=2
>>> foo(1, bar=2)
TypeError: foo() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given

В Python2 разрешено только **kwargsпосле *args.Вы можете эмулировать именованные параметры, извлекая их из kwargs:

>>> def foo(*args, **kwargs):
...    bar = kwargs.pop("bar")
...    print('args=%r, bar=%r' % (args, bar))
...
... foo(1, bar=2)
args=(1,), bar=2

Если вы хотите использовать только именованные параметры без переменные позиционные и именованные параметры, вы должны сами выдавать ошибки:

>>> def foo(*args, **kwargs):
...    bar = kwargs.pop('bar')
...    if args or kwargs:
...        raise TypeError
...    print('args=%r, bar=%r' % ('undefined', bar))
...
... foo(bar=2)
args='undefined', bar=2
>>> foo(1, bar=2)
TypeError
2 голосов
/ 09 мая 2019

В Python именованные атрибуты используются после неназванных (например, *args).Таким образом, вы должны изменить __init__ следующим образом:

def __init__(self, *args, bar=None):

Вот пример:

class Foo(object):
    """Baffling"""
    def __init__(self, *args, bar=None):
        self.bar = bar

foo = Foo(1, bar=2) # explodes
foo.bar

Вернется:

Out[...]: 2


PS В любом случае, не стоит смешивать *args, **kwargs и именованные атрибуты.Я рекомендую вам избегать этого.

...