Що робить ** (подвійна зірка / зірочка) та * (зірка / зірочка) для параметрів?


2348

У наступних визначеннях методів, для чого *і що потрібно **робити param2?

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

4
дивіться також stackoverflow.com/questions/6967632/…
Aaron Hall


Дивіться також stackoverflow.com/questions/14301967/… для голої зірочки
naught101

24
Це питання є дуже популярною дублікатом цілі, але, на жаль, воно часто використовується неправильно. Майте на увазі, що це питання задає питання про визначення функцій з varargs ( def func(*args)). Питання про те, що це означає у функціональних викликах ( func(*[1,2])), дивіться тут . Питання про розпакування списків аргументів дивіться тут . За запитання, що *означає засоби в літералах ( [*[1, 2]]), дивіться тут .
Аран-Фей

Дізнатися про його використання у визначенні функції та виклику функції можна тут: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Anurag

Відповіді:


2235

*argsІ **kwargsє загальним ідіома , щоб довільне число аргументів функцій , як описано в розділі більш про визначення функцій в документації на Python.

Це *argsдасть вам усі параметри функції як кортеж :

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

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

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

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

bar(name='one', age=27)
# age 27
# name one

Обидві ідіоми можна змішати із звичайними аргументами, щоб дозволити набір фіксованих та деяких змінних аргументів:

def foo(kind, *args, **kwargs):
   pass

Це також можна використовувати навпаки:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Ще одне використання *lідіоми - це розпакування списків аргументів під час виклику функції.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

У Python 3 можна використовувати *lліву частину завдання ( Extended Iterable Unpacking ), хоча він дає список замість кортежу в цьому контексті:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Також Python 3 додає новий семантичний (див. PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Така функція приймає лише 3 позиційні аргументи, і все після цього *може бути передано лише як аргументи ключових слів.


9
Вихід [6] знаходиться в зворотному порядку.
називайте

54
@ thanos.a Дікти Python, семантично використовувані для передачі аргументів ключових слів, довільно упорядковуються. Однак у Python 3.6 аргументи ключових слів гарантовано запам'ятовують порядок вставки. "Порядок елементів у **kwargsтепер відповідає порядку, в якому аргументи ключових слів були передані функції." - docs.python.org/3/whatsnew/3.6.html Фактично, всі дикти в CPython 3.6 запам'ятовують порядок вставки як деталі реалізації, це стає стандартом у Python 3.7.
Аарон Холл

13
Дуже точний, чистий і легкий для розуміння. Я вдячний, що ви відзначили, що це "оператор розпакування", щоб я міг відрізнятись від проходження посиланням у C. +1
bballdave025

Як перевірити останню функцію за допомогою PEP 3102? Я називаю це func (1,2,3, name = "мені", вік = 10), і він кидає виняток:got an unexpected keyword argument 'name'
Kok How Teh

@KokHowTeh Вам потрібно передати названих kwargs так, як вони є у функції: func (1, 2, 3, kwarg1 = 'я', kwarg2 = 10)
Джон Аарон

622

Також варто зазначити, що ви можете використовувати *і **при виклику функцій. Це ярлик, який дозволяє передавати кілька аргументів функції безпосередньо за допомогою списку / кортежу або словника. Наприклад, якщо у вас є така функція:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Ви можете робити такі речі, як:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Примітка: Клавіші в mydictповинні бути названі точно так, як параметри функції foo. Інакше він кине TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'

175

Сингл * означає, що може бути будь-яка кількість додаткових позиційних аргументів. foo()можна викликати якfoo(1,2,3,4,5) . У тілі foo () param2 - послідовність, що містить 2-5.

Подвійний ** означає, що може бути будь-яка кількість додаткових іменованих параметрів. bar()можна викликати як bar(1, a=2, b=3). В тілі bar () param2 - словник, що містить {'a': 2, 'b': 3}

З наступним кодом:

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

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

foo(1,2,3,4,5)
bar(1,a=2,b=3)

вихід є

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}

5
Можливо, foobar(param1, *param2, **param3)для повноти цієї відповіді потрібен додатковий приклад з .
Анікет Такур

1
@AniketThakur додали решту тут .
Радж

148

Що робить **(подвійна зірка) і *(зірка) для параметрів

Вони дозволяють визначати функції, які приймають, а користувачі передають будь-яку кількість аргументів, позиційних ( *) та ключових слів ( **).

Визначення функцій

*argsдозволяє будь-яку кількість необов'язкових позиційних аргументів (параметрів), які будуть присвоєні кордону з назвою args.

**kwargs допускає будь-яку кількість необов'язкових аргументів ключових слів (параметрів), які будуть міститись у назвою dict kwargs .

Ви можете (і повинні) вибрати будь-яке відповідне ім'я, але якщо намір аргументів має неспецифічну семантику argsі kwargsє стандартними іменами.

Розширення, передача будь-якої кількості аргументів

Ви також можете використовувати *argsта **kwargsпередавати параметри зі списків (або будь-яких ітерабельних) та диктів (або будь-якого відображення) відповідно.

Функція, що отримує параметри, не повинна знати, що вони розширюються.

Наприклад, xrange Python 2 явно не очікує *args, але оскільки він бере аргументи 3 цілих чисел:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

В якості іншого прикладу ми можемо використовувати розширення dict у str.format:

>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Нове в Python 3: визначення функцій з аргументами лише для ключових слів

Ви можете мати лише аргументи для ключових слів після *args- наприклад, тут kwarg2потрібно вказати як аргумент ключового слова - не позитивно:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Використання:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

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

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Тут kwarg2знову повинен бути явно названий аргумент ключового слова:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

І ми більше не можемо приймати необмежені позиційні аргументи, оскільки у нас немає *args*:

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Знову ж таки, простіше, тут нам потрібно kwargвказати ім’я, а не позитивно:

def bar(*, kwarg=None): 
    return kwarg

У цьому прикладі ми бачимо, що якщо ми спробуємо пройти kwargпозиційно, ми отримаємо помилку:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

Ми повинні явно передавати kwargпараметр як аргумент ключового слова.

>>> bar(kwarg='kwarg')
'kwarg'

Демонстраційні сумісні програми Python 2

*args(типово сказані "зіркові арги") та **kwargs(зірки можуть мати на увазі, кажучи "kwargs", але бути явними з "double-star kwargs") є загальними ідіомами Python для використання *та **позначення. Ці конкретні імена змінних не потрібні (наприклад, ви могли б використовувати *foosі **bars), але відхід від конвенції, швидше за все, розлютить ваших колег Python-кодерів.

Зазвичай ми їх використовуємо, коли ми не знаємо, яка наша функція буде отримувати або скільки аргументів ми можемо передавати, а іноді навіть при іменуванні кожної змінної окремо виходитиме дуже безладним і зайвим (але це випадок, коли зазвичай явний краще, ніж неявне).

Приклад 1

Наступна функція описує способи їх використання та демонструє поведінку. Зверніть увагу, що названий bаргумент буде використаний другим позиційним аргументом раніше:

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))

Ми можемо перевірити в Інтернеті довідку щодо підпису функції, за допомогою help(foo)якої вона нам повідомляє

foo(a, b=10, *args, **kwargs)

Давайте назвемо цю функцію за допомогою foo(1, 2, 3, 4, e=5, f=6, g=7)

який друкує:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

Приклад 2

Ми також можемо викликати його за допомогою іншої функції, в яку ми просто надаємо a:

def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 

bar(100) відбитки:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Приклад 3: практичне використання в декораторах

Гаразд, тому, можливо, ми ще не бачимо утиліту. Тож уявіть, що у вас є кілька функцій із зайвим кодом до та / або після диференціюючого коду. Наступні названі функції є лише псевдокодом для ілюстративних цілей.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on

Ми можемо впоратися з цим по-різному, але ми, безумовно, можемо витягти надмірність з декоратором, і тому наш нижній приклад демонструє, як *argsі **kwargsможе бути дуже корисним:

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

А тепер кожну завернуту функцію можна записати набагато коротше, оскільки ми вигадали надмірність:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

І, визначаючи наш код, який *argsі **kwargsдозволяє нам це робити, ми зменшуємо рядки коду, покращуємо читабельність та ремонтопридатність та маємо єдині канонічні місця для логіки в нашій програмі. Якщо нам потрібно змінити будь-яку частину цієї структури, у нас є одне місце, в якому можна внести кожну зміну.


48

Давайте спочатку розберемося, що таке позиційні аргументи та аргументи ключових слів. Нижче наводиться приклад визначення функції з позиційними аргументами.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Отже, це визначення функції з позиційними аргументами. Ви також можете викликати його за допомогою ключових / іменованих аргументів:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Тепер вивчимо приклад визначення функції з аргументами ключових слів :

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

Цю функцію можна викликати і позиційними аргументами:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Тож тепер ми знаємо визначення функцій з позиційними та ключовими аргументами.

Тепер вивчимо оператора "*" та "**".

Зверніть увагу, що ці оператори можуть використовуватися в двох областях:

а) виклик функції

б) визначення функції

Використання оператора "*" та "**" у виклику функції.

Перейдемо до прикладу, а потім обговоримо його.

def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.

Тож пам’ятайте

коли оператор "*" або "**" використовується у виклику функції -

Оператор '*' розпаковує структуру даних, таких як список або вкладається в аргументи, необхідні для визначення функції.

Оператор '**' розпаковує словник в аргументи, необхідні для визначення функції.

Тепер вивчимо використання оператора '*' у визначенні функції . Приклад:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

У визначенні функції оператор '*' пакує отримані аргументи в кортеж.

Тепер подивимось приклад "**", який використовується у визначенні функції:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

У визначенні функції Оператор '**' пакує отримані аргументи у словник.

Тож пам’ятайте:

У виклику функції '*' розпаковує структуру даних кортежу або списку в позиційні або ключові аргументи, які повинні бути отримані за допомогою визначення функції.

У виклику функції "**" розпаковує структуру даних словника в позиційні або ключові аргументи, які повинні бути отримані за допомогою визначення функції.

У визначенні функції '*' пакує позиційні аргументи в кортеж.

У визначенні функції '**' пакує аргументи ключових слів у словник.


Дійсно чистий, крок за кроком і легко слідувати поясненням!
Олександр

дякуйте, продовжуйте надходити. [Також для подальших записок від мене, я в @mrtechmaker на Twitter]
Каран Ахуджа,

32

Ця таблиця зручна для використання *і **в функції побудови і функції виклику :

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Це дійсно просто служить для узагальнення Лорін Хохштейна в відповідь , але я знаходжу це корисним.

Відповідно: використання для операторів зірки / splat було розширено в Python 3


22

*і **мають спеціальне використання у списку аргументів функцій. * Має на увазі, що аргумент є списком і **означає, що аргумент є словником. Це дозволяє функціям приймати довільну кількість аргументів


17

Для тих із вас, хто вчиться на прикладах!

  1. Мета * - надати вам можливість визначати функцію, яка може приймати довільну кількість аргументів, поданих як список (наприклад,f(*myList) ).
  2. Мета **- надати вам можливість подавати аргументи функції, надаючи словник (наприклад f(**{'x' : 1, 'y' : 2})).

Покажемо це, визначивши функцію, яка приймає дві нормальні змінні x, yі може прийняти більше аргументів як myArgsі може прийняти ще більше аргументів як myKW. Пізніше ми покажемо, як годувати, yвикористовуючи myArgDict.

def f(x, y, *myArgs, **myKW):
    print("# x      = {}".format(x))
    print("# y      = {}".format(y))
    print("# myArgs = {}".format(myArgs))
    print("# myKW   = {}".format(myKW))
    print("# ----------------------------------------------------------------------")

# Define a list for demonstration purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("myEx", *myList, **myDict)
# x      = myEx
# y      = Left
# myArgs = ('Right', 'Up', 'Down')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# y is matched and fed first
# The rest of myArgDict becomes additional arguments feeding myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
# x      = myEx
# y      = 4
# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# Without the stars, the entire provided list and dict become x, and y:
f(myList, myDict)
# x      = ['Left', 'Right', 'Up', 'Down']
# y      = {'Wubba': 'lubba', 'Dub': 'dub'}
# myArgs = ()
# myKW   = {}
# ----------------------------------------------------------------------

Коваджі

  1. ** виключно зарезервовано для словників.
  2. Необов'язкове призначення аргументів відбувається спочатку.
  3. Ви не можете використовувати необов'язковий аргумент двічі.
  4. Якщо потрібно, **потрібно *завжди приймати після .

14

З документації Python:

Якщо є більше позиційних аргументів, ніж є формальні слоти параметрів, виникає виняток TypeError, якщо тільки формальний параметр із синтаксисом "* ідентифікатор" не присутній; у цьому випадку цей формальний параметр отримує кортеж, що містить надлишкові позиційні аргументи (або порожній кортеж, якщо не було зайвих позиційних аргументів).

Якщо будь-який аргумент ключового слова не відповідає формальному імені параметра, підвищується виняток TypeError, якщо тільки формальний параметр із синтаксисом "** ідентифікатор" не присутній; у цьому випадку цей формальний параметр отримує словник, що містить надлишки аргументів ключового слова (використовуючи ключові слова як ключі та значення аргументу як відповідні значення) або (новий) порожній словник, якщо не було зайвих аргументів ключового слова.


10

* означає отримувати змінні аргументи як кортеж

** означає отримувати змінні аргументи як словник

Використовується так:

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

8

Я хочу навести приклад, про який інші не згадували

* також можна розпакувати генератор

Приклад з Python3 Document

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x буде [1, 2, 3], unzip_y буде [4, 5, 6]

Zip () отримує декілька аргументів, що можна відрегулювати, і повертає генератор.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))

7

В 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.)


1
Я не впевнений, що це порушення "є лише один спосіб зробити це". Немає іншого способу ініціалізації списку / кортежу з декількох ітерабелів - Вам наразі потрібно зв'язати їх в один ітерабельний файл, що не завжди зручно. Про раціональне ви можете прочитати в PEP-0448 . Крім того, це не функція python3.x, це функція python3.5 + :-).
mgilson

@mgilson, це пояснило б, чому вона не згадувалася раніше.
leewz

6

Окрім викликів функцій, * args та ** kwargs корисні в ієрархіях класів, а також уникають необхідності записувати __init__метод у Python. Подібне використання можна побачити в таких структурах, як код Джанго.

Наприклад,

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())

Крім того, підклас з новим атрибутом, який має сенс лише для цього екземпляра підкласу, може викликати клас Base __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')

Повний код є тут


1
1. В основному ініт - це метод, тому (в цьому контексті) насправді це не інакше. 2. Використовуйте # для коментарів, а не "" ", що просто позначає буквальні рядки. 3. Використання супер має бути кращим способом, особливо для вашого прикладу з багаторівневим успадкуванням.
0xc0de

4

Спираючись на відповідь Нікка ...

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


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


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Вихід:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

1
(2, 3, 4)
{'s': 5}

В основному, будь-яка кількість позиційних аргументів може використовувати * args, а будь-які названі аргументи (або аргументи ключового слова kwargs, також можуть використовувати ** kwargs).


3

*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.

2

Цей приклад допоможе вам запам’ятати *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

Хороший приклад використання обох у функції:

>>> 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')
{}

1

TL; DR

Нижче наведено 6 різних випадків використання для *та **в програмуванні python:

  1. Щоб прийняти будь-яку кількість позиційних аргументів, використовуючи *args:, def foo(*args): pass тут приймається будь-foo яка кількість позиційних аргументів, тобто дійсні наступні виклики foo(1),foo(1, 'bar')
  2. Щоб прийняти будь-яку кількість аргументів ключових слів, використовуючи **kwargs:, def foo(**kwargs): pass тут 'foo' приймає будь-яку кількість аргументів ключових слів, тобто дійсні наступні дзвінки foo(name='Tom'),foo(name='Tom', age=33)
  3. Щоб прийняти будь-яку кількість аргументів позиції та ключових слів, використовуючи *args, **kwargs:, def foo(*args, **kwargs): pass тут приймається будь-яка кількість аргументівfoo позиції та ключових слів, тобто дійсні наступні дзвінки foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Щоб застосувати аргументи лише для ключових слів, використовуючи *:, def foo(pos1, pos2, *, kwarg1): pass тут *означає, що foo приймає аргументи ключових слів лише після pos2, отже, foo(1, 2, 3)піднімає TypeError, але foo(1, 2, kwarg1=3)це нормально.
  5. Щоб не висловлювати більше зацікавленості в більш позитивних аргументах, використовуючи *_(Примітка: це лише конвенція): def foo(bar, baz, *_): pass засоби (за умовою) fooвикористовують лише barтаbaz аргументи на його роботі і буде ігнорувати інші.
  6. Щоб висловити ніякого подальший інтересу до більш іменованих аргументів , використовуючи \**_(Примітка: ця угода тільки): def foo(bar, baz, **_): pass кошти (за згодою) fooтільки використовує barі bazаргументи на його роботі і буде ігнорувати інші.

БОНУС: Від python 3.8 і далі можна використовувати /у визначенні функції примусове застосування лише позиційних параметрів. У наступному прикладі параметри a і b є лише позиційними , тоді як c або d можуть бути позиційними або ключовими словами, а e або f повинні бути ключовими словами:

def f(a, b, /, c, d, *, e, f):
    pass

0

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

Контекст

  • пітон 3.x
  • розпакування с **
  • використовувати при форматуванні рядків

Використовувати при форматуванні рядків

Окрім відповідей у ​​цій темі, ще одна деталь, яка не згадувалася в іншому місці. Це пояснюється відповіддю Бреда Соломона

Розпакування з **також корисно при використанні python str.format.

Це дещо схоже на те, що ви можете зробити з f-string pythonf-strings але з доданими накладними витратами оголошення дектату для зберігання змінних (f-string не вимагає дікта).

Короткий приклад

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.append('''
  Hello {fname} {lname}!

  Today you are {age} years old!

  We love your motto "{motto}" and we agree with you!
  '''.format(**ddvars)) 
  pass

  ## ********************
  ## multiple unpack supported in py 3.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])

-2
  • def foo(param1, *param2):- метод може приймати довільне число значень для *param2,
  • def bar(param1, **param2): це метод, який може приймати довільне число значень за допомогою ключів для *param2
  • param1 - простий параметр.

Наприклад, синтаксис реалізації varargs в Java наступним чином:

accessModifier methodName(datatype arg) {
    // method body
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.