2012-04-12 68 views
5

Tôi nghĩ nhiều người đã thấy hàm python nhận các tham số mặc định. Ví dụ:Tham số mặc định trong hàm Python

def foo(a=[]): 
    a.append(3) 
    return a 

Nếu chúng ta gọi hàm này sử dụng foo(), sản lượng sẽ nối số nguyên '3' mỗi lần sau khi cuộc gọi.

Khi hàm này được xác định, đối tượng hàm có tên 'foo' được xác định trong môi trường hiện tại và các giá trị thông số mặc định được đánh giá tại thời điểm này. Mỗi khi hàm được gọi mà không có tham số, giá trị tham số được đánh giá sẽ được thay đổi theo mã.

Câu hỏi của tôi là, thông số được đánh giá này tồn tại ở đâu? Có trong đối tượng hàm hay trong đối tượng phương thức khi gọi hàm không? Vì mọi thứ trong python là một đối tượng, phải có một số vị trí để giữ giá trị name-> binding của tham số 'a' -> được đánh giá. Tôi có đang suy nghĩ quá mức về vấn đề này không?

Trả lời

10

Như những người khác đã nói, giá trị mặc định được lưu trữ trong đối tượng hàm.

Ví dụ, trong CPython bạn có thể làm điều này:

>>> def f(a=[]): 
...  pass 
... 
>>> f.func_defaults 
([],) 
>>> f.func_code.co_varnames 
('a',) 
>>> 

Tuy nhiên, co_varnames có thể chứa nhiều hơn tên của args vì vậy nó cần tiếp tục xử lý và những thuộc tính này thậm chí có thể không có mặt ở đó trong việc triển khai Python khác. Vì vậy, bạn nên sử dụng các mô-đun inspect thay vì đó sẽ chăm sóc của tất cả các chi tiết thực hiện cho bạn:

>>> import inspect 
>>> spec = inspect.getargspec(f) 
>>> spec 
ArgSpec(args=['a'], varargs=None, keywords=None, defaults=([],)) 
>>> 

Các ArgSpec là một tên tuple để bạn có thể truy cập vào tất cả các giá trị như là thuộc tính:

>>> spec.args 
['a'] 
>>> spec.defaults 
([],) 
>>> 

Khi documentation nói rằng, bộ tời defaults luôn tương ứng với n đối số cuối cùng từ args. Điều này mang lại cho bạn bản đồ của bạn.

Để tạo một dict bạn có thể làm điều này:

>>> dict(zip(spec.args[-len(spec.defaults):], spec.defaults)) 
{'a': []} 
>>> 
4

Nó gắn liền với đối tượng chức năng, xem foo.func_defaults:

>>> foo() 
>>> foo.func_defaults 
([3],) 
>>> foo() 
>>> foo.func_defaults 
([3, 3],) 

Trong trường hợp nếu bạn muốn nhận được các bản đồ của a vào [], bạn có thể truy cập vào foo.func_code:

defaults = foo.func_defaults 
# the args are locals in the beginning: 
args = foo.func_code.co_varnames[:foo.func_code.co_argcount] 
def_args = args[-len(defaults):] # the args with defaults are in the end 
print dict(zip(def_args, defaults)) # {'a': []} 

(Nhưng, rõ ràng, phiên bản của yak là tốt hơn.)

+2

Có, nhưng đâu là ánh xạ 'a' với' [] 'như OP đã hỏi? – MattH

+0

@MattH đã cập nhật câu trả lời, cảm ơn. – bereal

4

Nó nằm trong đối tượng hàm, trong func_defaults :

def f(a=[]): a.append(3) 

print f.func_defaults # ([],) 

f() 

print f.func_defaults # ([3],) 
+2

Có, nhưng đâu là ánh xạ của a đến [] như OP đã hỏi? – MattH

2

Nó được lưu trữ trong thuộc tính func_defaults của đối tượng hàm.

>>> foo.func_defaults 
([],) 
>>> foo() 
([3],) 
1

Tôi đã tìm thấy một tình huống thú vị: trong python 2.5.2 phiên bản, hãy thử các chức năng 'foo()'

>>> foo() 
[1] 
>>> foo() 
[1] 
>>> foo() 
[1] 

Bởi vì đối tượng của hàm gọi là khác nhau:

>>> id(foo()) 
4336826757314657360 
>>> id(foo()) 
4336826757314657008 
>>> id(foo()) 
4336826757314683160 

Trong 2.7.2 phiên bản:

>>> foo() 
[1] 
>>> foo() 
[1, 1] 
>>> foo() 
[1, 1, 1] 

Trong này trường hợp, đối tượng giống nhau mỗi khi gọi hàm:

>>> id(foo()) 
29250192 
>>> id(foo()) 
29250192 
>>> id(foo()) 
29250192 

Đây có phải là vấn đề với các phiên bản khác nhau không?

+0

Không nên xảy ra. Đảm bảo bạn đang sử dụng * chính xác * các chức năng tương tự trên cả hai phiên bản. – yak

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