2012-02-06 28 views
28

Lỗi phổ biến là đặt đối tượng có thể thay đổi làm giá trị mặc định của đối số trong hàm. Dưới đây là một ví dụ lấy từ this excellent write-up by David Goodger:Sử dụng tốt cho các giá trị mặc định của đối số hàm có thể thay đổi được không?

>>> def bad_append(new_item, a_list=[]): 
     a_list.append(new_item) 
     return a_list 
>>> print bad_append('one') 
['one'] 
>>> print bad_append('two') 
['one', 'two'] 

Lời giải thích lý do tại sao điều này xảy ra là here.

Và bây giờ cho câu hỏi của tôi: Có trường hợp sử dụng tốt cho cú pháp này không?

Ý tôi là, nếu tất cả mọi người gặp phải lỗi đó, hãy gỡ lỗi, hiểu vấn đề và từ đó cố gắng tránh vấn đề, thì sử dụng cú pháp đó là gì?

+0

Xem http: // stackoverflow.com/questions/1132941/least-astonishment-in-python-the-mutable-default-argument – sdolan

+1

Lời giải thích tốt nhất mà tôi biết cho điều này là trong câu hỏi được liên kết: các hàm là các đối tượng hạng nhất, giống như các lớp. Các lớp có dữ liệu thuộc tính có thể thay đổi; các hàm có giá trị mặc định có thể thay đổi. – katrielalex

+0

http: // stackoverflow.com/questions/2639915/why-the-mutable-default-argument-fix-syntax-là-so-ugly-ask-python-newbie – katrielalex

Trả lời

21

Bạn có thể sử dụng nó để giá trị bộ nhớ cache giữa chức năng cuộc gọi:

def get_from_cache(name, cache={}): 
    if name in cache: return cache[name] 
    cache[name] = result = expensive_calculation() 
    return result 

nhưng thường đó đại loại như vậy được thực hiện tốt hơn với một lớp như sau đó bạn có thể có thuộc tính bổ sung để xóa bộ nhớ cache, vv

+5

... hoặc trang trí ghi nhớ. –

+9

'@ functools.lru_cache (maxsize = None)' – katrielalex

+2

@katrielalex lru_cache là mới trong Python 3.2 vì vậy không phải ai cũng có thể sử dụng nó. – Duncan

4
import random 

def ten_random_numbers(rng=random): 
    return [rng.random() for i in xrange(10)] 

Sử dụng mô-đun random, hiệu quả là một singleton có thể thay đổi, làm trình tạo số ngẫu nhiên mặc định.

+4

Nhưng đây cũng không phải là trường hợp sử dụng khủng khiếp. –

1

EDIT (làm rõ): Vấn đề đối số mặc định có thể thay đổi là một triệu chứng của lựa chọn thiết kế sâu hơn, cụ thể là giá trị đối số mặc định được lưu trữ dưới dạng thuộc tính trên đối tượng hàm. Bạn có thể hỏi tại sao lựa chọn này được thực hiện; như mọi khi, những câu hỏi như vậy khó trả lời đúng. Nhưng chắc chắn nó có công dụng tốt:

Tối ưu hóa cho hiệu suất:

def foo(sin=math.sin): ... 

Nắm lấy giá trị đối tượng trong một đóng cửa thay vì biến.

callbacks = [] 
for i in range(10): 
    def callback(i=i): ... 
    callbacks.append(callback) 
+4

số nguyên và hàm dựng sẵn không thể thay đổi được! – WolframH

+2

@ Jonathan: Vẫn không có đối số mặc định có thể thay đổi nào trong ví dụ còn lại hoặc tôi không thấy nó? – WolframH

+1

@ Jonathan: quan điểm của tôi không phải là những thứ này có thể thay đổi được. Đó là hệ thống Python sử dụng để lưu trữ các đối số mặc định - trên đối tượng hàm, được định nghĩa tại thời gian biên dịch - có thể hữu ích. Điều này ngụ ý vấn đề đối số mặc định có thể thay đổi, vì việc đánh giá lại đối số trên mỗi cuộc gọi hàm sẽ khiến cho thủ thuật vô dụng. – katrielalex

3

Có lẽ bạn không đột biến đối số có thể thay đổi, nhưng làm mong đợi một cuộc tranh luận có thể thay đổi:

def foo(x, y, config={}): 
    my_config = {'debug': True, 'verbose': False} 
    my_config.update(config) 
    return bar(x, my_config) + baz(y, my_config) 

(Vâng, tôi biết bạn có thể sử dụng config=() trong trường hợp đặc biệt này, nhưng tôi thấy rằng chưa rõ ràng . và ít nói chung)

1

câu trả lời Canonical là trang này: http://effbot.org/zone/default-values.htm

Nó cũng đề cập đến 3 trường hợp sử dụng "tốt" cho đối số mặc định có thể thay đổi:

  • ràng buộc biến địa phương để giá trị hiện tại của biến ngoài trong một callback
  • cache/memoization
  • rebinding địa phương tên toàn cầu (mã cho tối ưu hóa cao)
+1

Trong khi liên kết này có thể trả lời câu hỏi, tốt hơn nên bao gồm các phần thiết yếu của câu trả lời ở đây và cung cấp liên kết để tham khảo. Câu trả lời chỉ liên kết có thể trở thành không hợp lệ nếu trang được liên kết thay đổi. - [Từ đánh giá] (/ đánh giá/chất lượng thấp-bài viết/18212166) – Dijkgraaf

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