2009-04-03 40 views
27

Đó là một số kiến ​​thức phổ biến mà các hàm Python có thể có tối đa 256 đối số. Những gì tôi đang tò mò muốn biết là nếu giới hạn này áp dụng đối với *args**kwargs khi họ đang trải ra theo cách thức sau đây:Số đối số tối đa trong hàm Python là gì?

items = [1,2,3,4,5,6] 

def do_something(*items): 
    pass 

Tôi hỏi vì, giả thuyết, có thể có trường hợp một danh sách lớn hơn 256 mặt hàng bị hủy đăng ký dưới dạng một bộ gồm *args hoặc **kwargs.

Trả lời

21

WFM

>>> fstr = 'def f(%s): pass' % (', '.join(['arg%d' % i for i in range(5000)])) 
>>> exec(fstr) 
>>> f 
<function f at 0x829bae4> 

Cập nhật: như Brian nhận thấy, giới hạn là ở phía bên gọi điện thoại:

>>> exec 'f(' + ','.join(str(i) for i in range(5000)) + ')' 

Traceback (most recent call last): 
    File "<pyshell#63>", line 1, in <module> 
    exec 'f(' + ','.join(str(i) for i in range(5000)) + ')' 
    File "<string>", line 1 
SyntaxError: more than 255 arguments (<string>, line 1) 

mặt khác làm việc này:

>>> f(*range(5000)) 
>>> 

Kết luận: không, nó không áp dụng đối số chưa được kiểm.

+0

Dường như giới hạn ở bên gọi. Hãy thử exec 'f (' + ','. Tham gia (str (i) cho i trong phạm vi (5000)) + ')' – Brian

+0

"WFM"? WTF? .... –

+0

@Stefan: * Làm việc cho tôi * –

1

Tôi đã thử một danh sách 4000 mục và nó hoạt động. Vì vậy, tôi đoán nó sẽ làm việc cho các giá trị lớn hơn là tốt.

1

cho ** kwargs, Nếu tôi nhớ rõ, đây là từ điển. Do đó, nó không có giới hạn.

cho * args, tôi không chắc chắn, nhưng tôi nghĩ rằng đó là một bộ hoặc danh sách, vì vậy nó cũng không có giới hạn.

Không giới hạn, ý tôi là ngoại trừ giới hạn bộ nhớ.

+0

Có * args là một bộ dữ liệu. –

5

Điều này dường như là một hạn chế trong việc biên dịch nguồn, vì vậy có thể chỉ tồn tại đối với các đối số được truyền trực tiếp, không phải trong * args hoặc ** kwargs.

Mã liên quan có thể được tìm thấy trong ast.c:

if (nargs + nkeywords + ngens > 255) { 
    ast_error(n, "more than 255 arguments"); 
    return NULL; 
} 

Nhưng lưu ý rằng đây là trong ast_for_call, và vì vậy chỉ applys sang bên gọi. tức là f(a,b,c,d,e...), thay vì định nghĩa, mặc dù nó sẽ đếm cả tham số kiểu vị trí (a,b,c,d)keyword (a=1, b=2, c=3) vị trí. Các tham số thực tế *args**kwargs trông giống như chúng chỉ được tính là một đối số cho các mục đích này ở phía gọi.

20

Giới hạn là do cách bytecode được biên dịch xử lý việc gọi hàm bằng đối số vị trí và/hoặc đối số từ khóa.

Op bytecode quan tâm là CALL_FUNCTION mang op_arg dài 4 byte, nhưng trên hai byte ít quan trọng nhất được sử dụng. Trong số đó, byte quan trọng nhất đại diện cho số đối số từ khóa trên ngăn xếp và byte ít quan trọng nhất là số đối số vị trí trên ngăn xếp. Do đó, bạn có thể có tối đa 0xFF == 255 đối số từ khóa hoặc 0xFF == 255 đối số vị trí.

Giới hạn này không áp dụng cho * args và ** kwarg vì cuộc gọi với ngữ pháp đó sử dụng opcode bytecode CALL_FUNCTION_VAR, CALL_FUNCTION_KW và CALL_FUNCTION_VAR_KW tùy thuộc vào chữ ký. Đối với các opcodes này, stack bao gồm một iterable cho * args và dict cho ** kwargs. Các vật phẩm này được chuyển trực tiếp tới máy thu để tháo chúng khi cần thiết.

+0

Đây có phải là hạn chế triển khai CPython hay là một phần của chính Python? – EOL

+1

Đó là một chi tiết thực hiện của mã bytecode CPython. –

+0

… thực sự. Giới hạn sẽ được phát hành với CPython 3.7. – EOL

2

CPython có một giới hạn của 255 đối số được truyền một cách rõ ràng trong một cuộc gọi:

>>> def f(*args, **kwargs): pass 
... 
>>> exec("f({})".format(', '.join(map(str, range(256))))) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 1 
SyntaxError: more than 255 arguments 

Hạn chế này được đặt ra bởi vì cho đến Python 3.5, CALL_FUNCTION opcode quá tải đối số opcode để mã hóa cả. số đối số vị trí và từ khóa trên ngăn xếp, cả hai được mã hóa trong một byte đơn.

Giới hạn này bị xóa trong bản phát hành Python 3.7 sắp tới, xem issue #27213issue #12844; # 27213 reworked CALL_FUNCTION* họ mã opcodes cho hiệu năng và đơn giản (một phần của 3.6), giải phóng đối số opcode chỉ mã hóa một số đối số duy nhất, và # 12844 loại bỏ kiểm tra biên dịch thời gian ngăn mã với nhiều đối số hơn được biên dịch. Trong 3.7, với EXTENDED_ARG() opcode, hiện tại có không giới hạn ở tất cả về số lượng đối số bạn có thể chuyển bằng cách sử dụng đối số rõ ràng, lưu số lượng đối số có thể được gắn vào ngăn xếp (do đó bị ràng buộc bởi bộ nhớ của bạn):

>>> import sys 
>>> sys.version_info 
sys.version_info(major=3, minor=7, micro=0, releaselevel='alpha', serial=2) 
>>> def f(*args, **kwargs): pass 
... 
>>> exec("f({})".format(', '.join(map(str, range(256))))) 
>>> exec("f({})".format(', '.join(map(str, range(2 ** 16))))) 

Do lưu ý rằng danh sách, các bộ và từ điển được giới hạn sys.maxsize yếu tố, do đó nếu gọi là chức năng sử dụng *args và/hoặc **kwargs nhận tất cả các thông số sau đó những hạn chế.

Đối với cú pháp cuộc gọi *args**kwargs (đối số mở rộng) không có giới hạn nào khác với cùng giới hạn kích thước sys.maxint về loại tiêu chuẩn Python.

+0

Câu trả lời hay làm mới cung cấp thông tin và ngữ cảnh mới – Rookie

Các vấn đề liên quan