สามารถส่งค่าตัวแปรจำนวนอาร์กิวเมนต์ไปยังฟังก์ชันได้หรือไม่?


345

ในทำนองเดียวกันกับการใช้ varargs ใน C หรือ C ++:

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

5
ฉันอ้างถึง lottness ที่มีเกียรติแก่พอดคาสต์ 53: itc.conversationsnetwork.org/shows/…
David Sykes

2
ฉันต้องไปกับ Mr Lott กับอันนี้ คุณสามารถรับคำตอบที่เชื่อถือได้อย่างรวดเร็วในเอกสาร Python และคุณจะรู้สึกว่ามีอะไรอยู่ในเอกสารอีกบ้าง เพื่อประโยชน์ของคุณในการทำความรู้จักกับเอกสารเหล่านั้นถ้าคุณวางแผนที่จะทำงานใน Python
Brian Neal

@DavidSykes Link ใช้งานไม่ได้
Dave Liu

คำตอบ:


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 จะคลายข้อโต้แย้งเป็น tuple เดียวพร้อมกับอาร์กิวเมนต์ทั้งหมด

สำหรับข้อโต้แย้งคำหลักที่คุณต้องยอมรับที่เป็นข้อโต้แย้งที่เกิดขึ้นจริงที่แยกจากกันตามที่ปรากฏในคำตอบของ Skurmedel


8
ข้อสำคัญอีกอย่างหนึ่ง ... เราอาจหาเวลาที่พวกมันต้องผ่านการโต้แย้งจำนวนหนึ่งไปยังฟังก์ชัน ในกรณีเช่นนี้เรียก "manyArgs" ของคุณโดยการสร้างรายการที่เรียกว่า "args" และส่งผ่านไปยัง manyArgs เช่นนี้ "manyArgs (* args)"
wilbbe01

4
นี้อยู่ใกล้ แต่นี้เป็นที่น่าเสียดายที่พอที่จะไม่โดยทั่วไป: ล้มเหลวด้วยmanyArgs(x = 3) TypeErrorคำตอบของ Skumedel แสดงวิธีแก้ปัญหานี้ จุดสำคัญคือว่าลายเซ็นทั่วไปของฟังก์ชั่นคือf(*list_args, **keyword_args)(ไม่f(*list_args))
Eric O Lebigot

2
ประเภทของการมีargs หมายถึงคำหลัก args ประเภทของการมี tuplekwargskwargsdictionary
RoboAlex

1
เพียงแค่for arg in args:สำหรับวนผ่าน 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 มีความหมายในหลาม ลอง myfunc (abc = 123, fgh = 567) แทน (มิฉะนั้นคำตอบที่ดีและขอขอบคุณสำหรับมัน!)
Dannid

@Dannid: ก็ไม่รู้เหมือนกันฮ่าฮ่า ... ใช้ไม่ได้กับ 2.6 หรือ 3.2 ฉันจะเปลี่ยนชื่อ
Skurmedel

เมื่อคุณพูดว่า 'เรียกว่าตามลำดับ' คุณหมายถึงส่งผ่านตามลำดับนั้นหรือไม่ หรืออย่างอื่น?
Nikhil Prabhu

1
@NikhilPrabhu: ใช่ อาร์กิวเมนต์คำหลักต้องมาล่าสุดเมื่อคุณเรียก พวกเขาจะมาล่าสุดหากคุณมีข้อโต้แย้งที่ไม่ใช่คำหลักในการโทรเกินไป
Skurmedel

2
สำหรับงูหลามที่ 3: การแลกเปลี่ยนเพียงprint aด้วยprint(a)และมีkwargs.iteritems():kwargs.items()
MasterControlProgram

22

ถ้าฉันทำได้รหัสของ Skurmedel สำหรับ python 2; เพื่อปรับให้หลาม 3 การเปลี่ยนแปลงiteritemsไปและเพิ่มวงเล็บไปitems printสิ่งนี้อาจป้องกันไม่ให้ผู้เริ่มต้นอย่างฉันกระแทก AttributeError: 'dict' object has no attribute 'iteritems'และค้นหาที่อื่น (เช่นข้อผิดพลาด“ วัตถุ 'dict' ไม่มีแอตทริบิวต์ 'iteritems' "เมื่อพยายามใช้ write_shp () ของ NetworkXเหตุใดสิ่งนี้จึงเกิดขึ้น

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')
metaperture

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.