2012-03-02 40 views
46

Tôi có hàm Python lấy danh sách làm tham số. Nếu tôi đặt giá trị mặc định của tham số vào một danh sách rỗng như thế này:Thực hành tốt nhất để đặt giá trị mặc định của tham số được cho là danh sách bằng Python?

def func(items=[]): 
    print items 

pylint sẽ cho tôi biết "giá trị mặc định nguy hiểm [] như là đối số". Vì vậy, tôi đã tự hỏi thực hành tốt nhất ở đây là gì?

+3

đây là điều mà mọi người mới bắt đầu sử dụng ngón chân của họ trên một hoặc hai lần, điều này khá thú vị rằng thông tin đã ngăn bạn viết một lỗi khủng khiếp! – wim

Trả lời

64

Sử dụng None như một giá trị mặc định:

def func(items=None): 
    if items is None: 
     items = [] 
    print items 

Vấn đề với một đối số mặc định có thể thay đổi là nó sẽ được chia sẻ giữa tất cả các lời gọi của hàm - xem "cảnh báo quan trọng" trong relevant section of the Python tutorial.

+2

Ah wow, tôi ngạc nhiên khi mọi người biết về điều này. =) Tôi ghét tính năng này của python quá nhiều đến mức tôi đã viết thư viện trang trí của riêng mình để cho phép cú pháp 'func (items = new ([]))'. – ninjagecko

+0

Cảm ơn! Có vẻ như Python nghĩ None là một kiểu hoàn toàn khác so với danh sách, vì vậy tôi tự hỏi là nó có thể chấp nhận được trong Python để đặt giá trị mặc định của tham số thành một kiểu khác (chẳng hạn như None) (tôi biết Python là kiểu ngôn ngữ, nhưng tôi đến từ C++ ... lol)? –

+0

Nó hoàn toàn khác với một ngôn ngữ được đánh máy mạnh như C++. Chỉ cần nghĩ về các biến như tên mà tham chiếu đến các đối tượng, và mọi thứ đều được truyền qua tham chiếu. – wim

2

Đối với đối tượng có thể thay đổi làm thông số mặc định trong khai báo hàm và phương thức, vấn đề là, việc đánh giá và tạo diễn ra đúng lúc. Trình phân tích cú pháp python đọc đầu hàm và đánh giá nó cùng một lúc.

Hầu hết người mới bắt đầu giả sử rằng một đối tượng mới được tạo ra ở mọi cuộc gọi, nhưng điều đó không chính xác! ONE đối tượng (trong ví dụ của bạn một danh sách) được tạo ra tại thời điểm khai báo và không theo yêu cầu khi bạn đang gọi phương thức.

Đối với các đối tượng imutable không phải là một vấn đề, bởi vì ngay cả khi tất cả các cuộc gọi chia sẻ cùng một đối tượng, nó là imutable và do đó các thuộc tính của nó vẫn giữ nguyên.

Là một quy ước, bạn sử dụng đối tượng None cho mặc định để cho biết việc sử dụng khởi tạo mặc định, hiện có thể diễn ra trong cơ thể hàm, được đánh giá tự nhiên tại thời gian gọi.

0

Bên cạnh đó và cũng để hiểu rõ hơn về những gì python là, ở đây ít đoạn tôi theo chủ đề:

from functools import wraps 
def defaultFactories(func): 
    'wraps function to use factories instead of values for defaults in call' 
    defaults = func.func_defaults 
    @wraps(func) 
    def wrapped(*args,**kwargs): 
     func.func_defaults = tuple(default() for default in defaults) 
     return func(*args,**kwargs) 
    return wrapped 

def f1(n,b = []): 
    b.append(n) 
    if n == 1: return b 
    else: return f1(n-1) + b 

@defaultFactories 
def f2(n,b = list): 
    b.append(n) 
    if n == 1: return b 
    else: return f2(n-1) + b 

>>> f1(6) 
[6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1, 6, 5, 4, 3, 2, 1] 
>>> f2(6) 
[1, 2, 3, 4, 5, 6] 
4

Tôi chỉ gặp phải điều này lần đầu tiên, và suy nghĩ trước mắt của tôi là "tốt, tôi không muốn để đột biến danh sách, vì vậy những gì tôi thực sự muốn là mặc định cho một danh sách bất biến để Python sẽ cho tôi một lỗi nếu tôi vô tình biến đổi nó. " Một danh sách bất biến chỉ là một tuple. Vì vậy:

 
    def func(items=()): 
     print items 

Chắc chắn, nếu bạn vượt qua nó để cái gì đó thực sự muốn có một danh sách (ví dụ isinstance (mặt hàng, danh sách)), thì đây sẽ giúp bạn gặp rắc rối. Nhưng đó là một mùi mã.

+1

Và nếu bên trong hàm bạn cần tạo một bản sao, hãy sử dụng 'my_copy = list (items)'. Bạn đã đưa ra một giải pháp đơn giản và rất thông minh cho một vấn đề chung. –

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