Чи можна передавати змінну кількість аргументів функції?


345

Аналогічним чином, як використовувати varargs в C або C ++:

fn(a, b)
fn(a, b, c, d, ...)

5
Я посилаюсь на почесну вершину на подкаст 53: itc.conversationsnetwork.org/shows/…
Девід Сайкс

2
Я повинен поїхати з містером Лоттом на цей. Ви можете швидко отримати авторську відповідь на цю відповідь у документах Python, плюс ви отримаєте відчуття того, що ще є в документах. Ознайомитись із цими документами вам на користь, якщо ви плануєте працювати в Python.
Брайан Ніл

@DavidSykes Посилання розірвано
Дейв Лю

Відповіді:


447

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

def manyArgs(*arg):
  print "I was called with", len(arg), "arguments:", arg

>>> manyArgs(1)
I was called with 1 arguments: (1,)
>>> manyArgs(1, 2, 3)
I was called with 3 arguments: (1, 2, 3)

Як бачите, Python буде розпаковувати аргументи як єдиний кордон з усіма аргументами.

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


8
Також важливо ... Ви можете знайти час, коли їм доведеться передавати невідому кількість аргументів функції. У такому випадку зателефонуйте вашому "ManyArgs", створивши список під назвою "args" і передавши його багатьомArgs, як цей "manyArgs (* args)"
wilbbe01

4
Це близько, але це, на жаль, недостатньо загальне: manyArgs(x = 3)не вдається TypeError. Відповідь Скумеделя показує рішення цього. Ключовим моментом є те, що загальна підпис функції є f(*list_args, **keyword_args)(не f(*list_args)).
Ерік О Лебігот

2
Тип argsє tuple. kwargsозначає аргументи ключових слів . Тип kwargsє dictionary.
RoboAlex

1
Просто for arg in args:для повторення пройдених арг
MasterControlProgram

228

Додавання до публікації для розмотування:

Ви також можете надсилати кілька аргументів ключ-значення.

def myfunc(**kwargs):
    # kwargs is a dictionary.
    for k,v in kwargs.iteritems():
         print "%s = %s" % (k, v)

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

І ви можете змішати два:

def myfunc2(*args, **kwargs):
   for a in args:
       print a
   for k,v in kwargs.iteritems():
       print "%s = %s" % (k, v)

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

Вони повинні бути оголошені і викликані в тому порядку, тобто підписом функції повинні бути * args, ** kwargs і викликатися в цьому порядку.


2
Не впевнений, як ви змусили myfunc (abc = 123, def = 456) працювати, але в шахті (2.7) 'def' не може бути переданий у цій функції без отримання SyntaxError. Я припускаю, що це тому, що def має значення в python. Спробуйте замість цього myfunc (abc = 123, fgh = 567). (Інакше чудова відповідь і дякую за це!)
Dannid

@Dannid: Ніякої ідеї ні ха-ха ... не працює і на 2.6, або на 3.2. Я перейменую його.
Skurmedel

Коли ви говорите "подзвонили в тому порядку", ви маєте на увазі, що пройшли в тому порядку? Або щось інше?
Нікхіл Прабху

1
@NikhilPrabhu: Так. Аргументи ключового слова повинні бути останніми, коли ви його називаєте. Вони завжди стають останніми, якщо у дзвінку також є аргументи, що не мають ключових слів.
Скурмедель

2
Для Python 3: Просто обмінюйтесь і print aз print(a), і kwargs.iteritems():з kwargs.items().
MasterControlProgram

22

Якщо я можу, код Скурмеделя призначений для python 2; адаптувати його до Python 3, зміни iteritemsв itemsі додати дужки до print. Це може завадити новачкам, як я, натрапляти на: AttributeError: 'dict' object has no attribute 'iteritems'та шукати в іншому місці (наприклад, помилка "об’єкт" dict "не має атрибуту" iteritems "" при спробі використовувати NetworkX's write_shp () ), чому це відбувається.

def myfunc(**kwargs):
for k,v in kwargs.items():
   print("%s = %s" % (k, v))

myfunc(abc=123, efh=456)
# abc = 123
# efh = 456

і:

def myfunc2(*args, **kwargs):
   for a in args:
       print(a)
   for k,v in kwargs.items():
       print("%s = %s" % (k, v))

myfunc2(1, 2, 3, banan=123)
# 1
# 2
# 3
# banan = 123

12

Додавання до інших відмінних постів.

Іноді ви не хочете вказувати кількість аргументів і хочете використовувати для них ключі (компілятор скаржиться, якщо один аргумент, переданий у словнику, не використовується в методі).

def manyArgs1(args):
  print args.a, args.b #note args.c is not used here

def manyArgs2(args):
  print args.c #note args.b and .c are not used here

class Args: pass

args = Args()
args.a = 1
args.b = 2
args.c = 3

manyArgs1(args) #outputs 1 2
manyArgs2(args) #outputs 3

Тоді ви можете робити такі речі

myfuns = [manyArgs1, manyArgs2]
for fun in myfuns:
  fun(args)

2
def f(dic):
    if 'a' in dic:
        print dic['a'],
        pass
    else: print 'None',

    if 'b' in dic:
        print dic['b'],
        pass
    else: print 'None',

    if 'c' in dic:
        print dic['c'],
        pass
    else: print 'None',
    print
    pass
f({})
f({'a':20,
   'c':30})
f({'a':20,
   'c':30,
   'b':'red'})
____________

наведений вище код виведе

None None None
20 None 30
20 red 30

Це так само добре, як передавати змінні аргументи за допомогою словника


3
Це страшний код. Набагато краще було б:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')
метапертура

0

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

def f(x,y=None):
    print(x)
    if y is not None:
        print(y)

Врожайність

In [11]: f(1,2)
1
2

In [12]: f(1)
1
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.