Что ** (двойная звезда / звездочка) и * (звездочка / звездочка) делают для параметров? - PullRequest
1952 голосов
/ 31 августа 2008

В следующих определениях методов, что * и ** делают для param2?

def foo(param1, *param2):
def bar(param1, **param2):

Ответы [ 18 ]

7 голосов
/ 09 декабря 2015

В Python 3.5 вы также можете использовать этот синтаксис при отображении list, dict, tuple и set (также иногда называемых литералами). См. PEP 488: Дополнительные обобщения распаковки .

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

Он также позволяет распаковать несколько итераций за один вызов функции.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(Благодарю mgilson за ссылку PEP.)

4 голосов
/ 16 августа 2015

В дополнение к вызовам функций, * args и ** kwargs полезны в иерархиях классов и также позволяют избежать написания метода __init__ в Python. Подобное использование можно увидеть в таких средах, как код Django.

Например,

def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])

Тогда подклассом может быть

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

Подкласс затем будет создан как

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

Кроме того, подкласс с новым атрибутом, который имеет смысл только для этого экземпляра подкласса, может вызвать Базовый класс __init__, чтобы снять настройку атрибутов. Это делается с помощью * args и ** kwargs. kwargs в основном используется для того, чтобы код читался с использованием именованных аргументов. Например,

class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)

который может быть установлен как

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

Полный код здесь

2 голосов
/ 07 августа 2018

* означает получение переменных аргументов в виде списка

** означает получение переменных аргументов в качестве словаря

Используется следующим образом:

1) один *

def foo(*args):
    for arg in args:
        print(arg)

foo("two", 3)

Выход:

two
3

2) Сейчас **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])

bar(dic1="two", dic2=3)

Выход:

dic1 two
dic2 3
1 голос
/ 27 ноября 2016

Этот пример поможет вам запомнить *args, **kwargs и даже super и наследование в Python одновременно.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1
1 голос
/ 26 октября 2016

Хороший пример использования обоих в функции:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}
0 голосов
/ 02 сентября 2018
  • def foo(param1, *param2): - метод может принимать произвольное количество значений для *param2,
  • def bar(param1, **param2): - метод может принимать произвольное количество значений с ключами для *param2
  • param1 - простой параметр.

Например, синтаксис для реализации varargs в Java выглядит следующим образом:

accessModifier methodName(datatype… arg) {
    // method body
}
0 голосов
/ 02 апреля 2019

TL; DR

Она упаковывает аргументы, переданные функции, в list и dict соответственно внутри тела функции. Когда вы определяете сигнатуру функции следующим образом:

def func(*args, **kwds):
    # do stuff

он может быть вызван с любым количеством аргументов и аргументов ключевого слова. Аргументы без ключевых слов упаковываются в список с именем args внутри тела функции, а аргументы с ключевыми словами упаковываются в dict с именем kwds внутри тела функции.

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

теперь внутри тела функции, когда вызывается функция, есть две локальные переменные, args, представляющий собой список со значением ["this", "is a list of", "non-keyword", "arguments"], и kwds, представляющий собой dict, имеющий значение {"keyword" : "ligma", "options" : [1,2,3]}


Это также работает в обратном порядке, то есть со стороны вызывающего абонента. например, если у вас есть функция, определенная как:

def f(a, b, c, d=1, e=10):
    # do stuff

вы можете вызвать его, распаковав итерации или сопоставления, которые есть в области вызова:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)
0 голосов
/ 01 мая 2018

*args и **kwargs: позволяют передавать переменное число аргументов в функцию.

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

def args(normal_arg, *argv):
    print("normal argument:", normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals', 'fish', 'duck', 'bird')

Будет производить:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

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

def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print("Your %s is %s." % (key, value))

who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  

Будет производить:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
...