Một số lượng đối số biến có thể được truyền cho một hàm?


345

Theo cách tương tự với việc sử dụng varargs trong C hoặc C ++:

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

5
Tôi giới thiệu sự chậm chạp đáng kính cho podcast 53: itc.conversationsnetwork.org/shows/iêu
David Sykes

2
Tôi phải đi với ông Lott về điều này. Bạn có thể nhanh chóng nhận được câu trả lời có thẩm quyền về câu hỏi này trong tài liệu Python, cộng với bạn sẽ có cảm giác về những gì khác có trong tài liệu. Lợi ích của bạn là tìm hiểu những tài liệu đó nếu bạn dự định làm việc với Python.
Brian Neal

Liên kết @DavidSykes bị hỏng
Dave Liu

Câu trả lời:


446

Đúng. Bạn có thể sử dụng *argsnhư một đối số không phải từ khóa . Sau đó, bạn sẽ có thể vượt qua bất kỳ số lượng đối số.

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)

Như bạn có thể thấy, Python sẽ giải nén các đối số dưới dạng một tuple với tất cả các đối số.

Đối với các đối số từ khóa, bạn cần chấp nhận chúng như một đối số thực tế riêng biệt, như thể hiện trong câu trả lời của Skurmedel .


8
Cũng quan trọng ... người ta có thể tìm thấy một thời gian khi họ phải truyền một số lượng đối số không xác định cho một hàm. Trong trường hợp như thế này, hãy gọi "manyArss" của bạn bằng cách tạo một danh sách gọi là "args" và chuyển nó cho nhiềuArss như thế này "manyArss (* args)"
wilbbe01

4
Điều này là gần, nhưng điều này không may là không đủ chung: manyArgs(x = 3)thất bại với TypeError. Câu trả lời của Skumedel cho thấy giải pháp cho vấn đề này. Điểm mấu chốt là chữ ký chung của hàm là f(*list_args, **keyword_args)(không f(*list_args)).
Eric O Lebigot

2
Các loại argstuple. kwargscó nghĩa là từ khóa args . Các loại kwargsdictionary.
RoboAlex

1
Chỉ for arg in args:để lặp qua các đối số đã qua
MasterControlProgram

228

Thêm vào thư giãn bài:

Bạn cũng có thể gửi nhiều đối số khóa-giá trị.

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

Và bạn có thể kết hợp cả hai:

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

Chúng phải được khai báo và gọi theo thứ tự đó, đó là chữ ký hàm cần phải là * args, ** kwargs và được gọi theo thứ tự đó.


2
Không chắc chắn làm thế nào bạn có myfunc (abc = 123, def = 456) để hoạt động, nhưng trong tôi (2.7), 'def' không thể được truyền vào hàm này mà không nhận được SyntaxError. Tôi cho rằng điều này là do def có ý nghĩa trong python. Thay vào đó, hãy thử myfunc (abc = 123, fgh = 567). (Nếu không, câu trả lời tuyệt vời và cảm ơn vì điều đó!)
Dannid

@Dannid: Không có ý tưởng nào cả haha ​​... cũng không hoạt động trên 2.6 hoặc 3.2. Tôi sẽ đổi tên nó.
Skurmedel

Khi bạn nói 'được gọi theo thứ tự đó', bạn có nghĩa là được thông qua theo thứ tự đó? Hay cái gì khác?
Nikhil Bohhu

1
@NikhilPrabhu: Vâng. Đối số từ khóa phải đến cuối cùng khi bạn gọi nó. Chúng luôn đến sau cùng nếu bạn cũng có các đối số không phải từ khóa trong cuộc gọi.
Skurmedel

1
Đối với Python 3: Chỉ cần trao đổi print avới print(a)kwargs.iteritems():với kwargs.items().
MasterControl

22

Nếu tôi có thể, mã của Skurmedel là dành cho python 2; để thích ứng với nó để python 3, thay đổi iteritemsđể itemsvà thêm dấu ngoặc đơn để print. Điều đó có thể ngăn những người mới bắt đầu như tôi va vào: AttributeError: 'dict' object has no attribute 'iteritems'và tìm kiếm ở nơi khác (ví dụ: đối tượng Error 'dict' không có thuộc tính 'iteritems', khi cố gắng sử dụng write_shp ()) của NetworkX tại sao điều này xảy ra.

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

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

và:

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

Thêm vào các bài viết xuất sắc khác.

Đôi khi bạn không muốn chỉ định số lượng đối số muốn sử dụng các khóa cho chúng (trình biên dịch sẽ khiếu nại nếu một đối số được truyền trong từ điển không được sử dụng trong phương thức).

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

Sau đó, bạn có thể làm những việc như

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

đoạn mã trên sẽ xuất ra

None None None
20 None 30
20 red 30

Điều này cũng tốt như truyền các đối số biến bằng từ điển


3
Đây là mã khủng khiếp. Tốt hơn nhiều sẽ là:f = lambda **dic: ' '.join(dic.get(key, 'None') for key in 'abc')
metaperture

0

Một cách khác để nói về nó, bên cạnh những câu trả lời hay đã được đề cập, phụ thuộc vào thực tế là bạn có thể chuyển các đối số có tên tùy chọn theo vị trí. Ví dụ,

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

Sản lượng

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

In [12]: f(1)
1
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.