2017-04-17 15 views
5

Tôi chỉ mới bắt đầu học Python và tôi là nhầm lẫn về ví dụ này:Python mặc định params nhầm lẫn

def append_to(element, to=None): 
    if to is None: 
     to = [] 
    to.append(element) 
    return to 

Nếu to được khởi tạo một lần, sẽ không to không None lần thứ 2 nó được gọi là? Tôi biết mã trên hoạt động nhưng không thể quấn quanh đầu của tôi xung quanh mô tả "khởi tạo một lần" này.

+0

Trong ví dụ xấu này (tôi gọi nó là xấu bởi vì nếu bạn vượt qua một 'str' điều này đi wreck ...) anyway, ở đây hoặc là' to' là 'None' hoặc là một danh sách.Bạn sẽ không tạo danh sách nếu 'to' không phải là' None'. Do đó, bạn chỉ gán một giá trị cho 'to' dưới lời gọi của kiểu này:' append_to ('dreamfly') 'trong trường hợp này:' append_to ('dreamfly', users) 'trong đó' users' sẽ là một danh sách, bạn không tạo danh sách bên trong hàm, bạn chỉ cần thêm giá trị ('users = [..., 'dreamfly']'). –

+0

Đó là một ví dụ từ http://python-guide-pt-br.readthedocs.io/en/latest/writing/gotchas/ – dreamfly

+0

Tôi đã đưa ra một số [phản hồi] (https://github.com/kennethreitz/python-guide/issue/813); ví dụ này sử dụng các đối tượng không thể thay đổi làm đối số mặc định, nhưng đó là một điều tốt nhưng việc xác thực bị thiếu có thể phá vỡ các phần khác của mã –

Trả lời

1

Nếu "đến" được khởi tạo một lần, "không" sẽ không "Không" lần thứ hai được gọi?

to sẽ trở thành None nếu bạn không vượt qua một giá trị cho nó: append_to(1) và chỉ khi toNone sẽ mã của bạn rebind tên địa phương to vào một danh sách mới được tạo ra bên trong cơ thể của chức năng của bạn: to = [].

Giá trị mặc định của hàm chỉ được gán khi, đó là bất cứ điều gì bạn chỉ định làm giá trị mặc định, đối tượng đó sẽ được sử dụng cho mọi cuộc gọi bạn thực hiện cho hàm và sẽ không thay đổi. giá trị sẽ được sử dụng cho mọi cuộc gọi bạn thực hiện với hàm. Vấn đề này khi bạn gán mutables như mặc định:

l = [] 
def defArgs(d=l)   # default arguments, same default list for every call 
    d.append(1) 
    return d 

defArgs() is l   # Object identity test: True 

Chạy hàm trên nhiều lần và bạn sẽ quan sát danh sách ngày càng tăng với các yếu tố hơn vì bạn nhận được chỉ có một bản duy nhất của giá trị mặc định tham số cho mỗi chức năng chia sẻ bởi tất cả các cuộc gọi chức năng . Nhưng hãy lưu ý tại đây:

def localVars(d=None): 
    if d is None: 
     d = []    # Different list for every call when d is None 

d = [] được thực hiện mỗi khi bạn gọi localVars; khi hàm kết thúc công việc của mình, mọi biến cục bộ sẽ được thu thập rác khi số tham chiếu giảm xuống 0, nhưng không phải là giá trị mặc định của đối số, chúng sẽ xuất hiện sau khi thực hiện hàm và thường không được thu thập rác sau khi thực thi chức năng.

+0

Tôi nghĩ tôi đã hiểu ý bạn sau khi đọc vài lần. Chìa khóa ở đây không phải là phạm vi của biến mà là đối tượng được sử dụng để khởi tạo biến. Khi họ nói "khởi tạo một lần", chúng có nghĩa là khởi tạo đối tượng nơi tham số trỏ đến một lần và liên kết đối tượng đó với tham số mỗi lần hàm được gọi. Vì vậy, nếu đối tượng là bất biến, nó không bao giờ có thể được thay đổi. Nếu nó có thể thay đổi, nó sẽ giữ lại giá trị cuối cùng. Bây giờ tất cả đều rõ ràng. Cảm ơn! – dreamfly

+0

Tôi muốn sử dụng cụm từ * assignment * thay vì khởi tạo ở đây để có độ chính xác. Và vâng, bạn nói đúng, nếu một đối tượng là bất biến, bạn không thể thay đổi nó. Không giống như mutables nơi bạn có thể thay đổi * part * của đối tượng 'd [0] = 20', ở đây bạn thực sự chỉ thay đổi một phần của' d', chỉ mục 0. Bạn không thể thay đổi một phần của int hoặc tuple chẳng hạn, vì chúng ' không thay đổi: 'a = 20' và sau đó bạn rebind' a' thành 30: 'a = 30' bây giờ' a' có tham chiếu khác đề cập đến 30 và 'a' không giống với' a' trước đó. Hy vọng điều này có ý nghĩa bây giờ :) – direprobs

2
def append_to(element, to=None): 
    to = ... 

to đây trở thành một biến địa phương và được gán cho một danh sách, và được deallocated nếu bạn không gán giá trị trả về để biến khác.

Nếu bạn muốn to giữ mạng sống cho các cuộc gọi tiếp theo để append_to bạn nên làm:

def append_to(element, to=[]): 
    to.append(element) 
    return to 

Demo:

>>> lst = append_to(5) 
>>> append_to(6) 
>>> append_to(7) 
>>> print lst 
[5, 6, 7] 
+0

trong ví dụ "to = []" của bạn, "không" cũng là biến cục bộ và nó trỏ đến đó là "[]" sẽ được thu thập rác thải từ "để" sẽ được đi cũng sau khi chức năng thoát? – dreamfly

+0

Không, nó không phải là một biến cục bộ và nó sẽ không biến mất ngay cả sau khi 'append_to' được gọi vì nó bị ràng buộc để hoạt động. Bạn tiếp tục gọi 'append_to', giá trị' to' giống nhau được thêm vào các phần tử mới. – ozgur

+0

Vì vậy, những gì làm cho "to = None" một biến địa phương và "to = []" không phải là một biến địa phương? Nó phụ thuộc vào sự biến đổi của giá trị? Đó có thể là cách tôi có thể nhớ nó một cách tinh thần mặc dù nó vẫn còn vô lý đối với tôi. – dreamfly

0

Trong Python không có khai báo và khởi tạo giai đoạn khi bạn sử dụng một biến. Thay vào đó, tất cả gán là một định nghĩa trong đó bạn liên kết một cá thể với tên biến.

Trình thông dịch liên kết cá thể với giá trị mặc định khi khởi tạo hàm. Khi giá trị mặc định là một đối tượng có thể thay đổi và bạn chỉ thay đổi trạng thái của nó bằng các phương thức của nó so với giá trị sẽ được "chia sẻ" giữa các cuộc gọi.