2010-03-09 20 views
7

Tôi đang xem xét di chuyển từ Matlab sang Python/numpy để phân tích dữ liệu và mô phỏng bằng số. Tôi đã sử dụng Matlab (và SML-NJ) trong nhiều năm, và tôi rất thoải mái trong môi trường chức năng mà không có tác dụng phụ (cấm I/O), nhưng có một chút miễn cưỡng về các tác dụng phụ trong Python. Mọi người có thể chia sẻ gotchas yêu thích của họ liên quan đến tác dụng phụ, và nếu có thể, làm thế nào họ có xung quanh họ? Như một ví dụ, tôi là một chút ngạc nhiên khi tôi thử đoạn code sau trong Python:gotchas tác dụng phụ trong python/numpy? câu chuyện kinh dị và lối thoát hẹp muốn

lofls = [[]] * 4 #an accident waiting to happen! 
lofls[0].append(7) #not what I was expecting... 
print lofls   #gives [[7], [7], [7], [7]] 
#instead, I should have done this (I think) 
lofls = [[] for x in range(4)] 
lofls[0].append(7) #only appends to the first list 
print lofls   #gives [[7], [], [], []] 

cảm ơn trước

+0

Đó là Gotcha chính cho tôi trong việc chuyển sang Python, nhưng tôi nghĩ rằng nó cũng là một Gotcha phổ biến cho những người bắt đầu sử dụng Python mà không cần phải sử dụng Matlab trước. Tôi có thể sai mặc dù. –

+1

Liên quan: http://zephyrfalcon.org/labs/python_pitfalls.html http://www.ferg.org/projects/python_gotchas.html – jfs

Trả lời

9

tài liệu tham khảo Confusing với cùng đối tượng (có thể thay đổi) với tham chiếu đến đối tượng riêng biệt thực sự là một " gotcha "(chịu đựng bởi tất cả các ngôn ngữ không phải chức năng, những ngôn ngữ có đối tượng có thể thay đổi và, tất nhiên, tham chiếu). Một lỗi thường thấy trong mã Python người mới bắt đầu đang lạm dụng một giá trị mặc định là có thể thay đổi, ví dụ:

def addone(item, alist=[]): 
    alist.append(item) 
    return alist 

Mã này có thể đúng nếu mục đích là để có addone giữ trạng thái của nó (và trở về danh sách một phát triển cho người gọi kế tiếp), nhiều như dữ liệu static sẽ hoạt động trong C; nó không chính xác nếu các coder là sai giả định rằng một danh sách trống mới sẽ được thực hiện tại mỗi cuộc gọi.

Người mới bắt đầu sử dụng ngôn ngữ chức năng cũng có thể bị nhầm lẫn bởi quyết định thiết kế trong các thùng chứa tích hợp của Python: (cụ thể, họ trả lại None) - họ đang làm tất cả công việc của họ "tại chỗ". Lỗi đến từ sự hiểu lầm này rất dễ phát hiện, ví dụ:

alist = alist.append(item) 

được khá nhiều đảm bảo được một lỗi - nó gắn thêm một mục vào danh sách được gọi bằng tên alist, nhưng sau đó rebinds tên alist-None (giá trị trả về của append cuộc gọi).

Trong khi vấn đề đầu tiên tôi đề cập là một sự ràng buộc sớm có thể đánh lừa những người nghĩ rằng ràng buộc, thay vào đó, một người muộn, có những vấn đề đi theo một cách khác. trong khi ràng buộc là, thay vào đó, muộn. Ví dụ (với một khuôn khổ giả GUI ...):

for i in range(10): 
    Button(text="Button #%s" % i, 
      click=lambda: say("I'm #%s!" % i)) 

này sẽ hiển thị mười nút cho biết "Nút # 0", "Button # 1", vv, nhưng khi nhấn vào, mỗi một trong họ sẽ say#9 - bởi vì itrong số lambda bị ràng buộc muộn (có đóng cửa từ vựng). Một sửa chữa là để tận dụng thực tế là giá trị mặc định cho tham số sớm bị ràng buộc (như tôi đã chỉ ra về vấn đề đầu tiên -!) Và thay đổi dòng cuối cùng để

  click=lambda i=i: say("I'm #%s!" % i)) 

Bây giờ lambda 's i là một đối số với một giá trị mặc định, không phải là một biến miễn phí (nhìn lên bằng cách đóng dấu từ vựng) nữa, và vì vậy mã hoạt động như dự định (dĩ nhiên cũng có những cách khác).

+1

vấn đề mặc định có thể thay đổi là rất phổ biến, nó xuất hiện trong tất cả các hướng dẫn python tôi có nhìn thấy, và tôi đã sợ hãi bởi nó. Quy tắc ngón tay cái mà bạn liệt kê liên quan đến sửa đổi "tại chỗ" là một sửa đổi tốt, và tôi nghĩ nó sẽ đưa tôi đi rất xa. Tuy nhiên, sự ràng buộc muộn trong biểu thức lambda mà bạn đưa ra là rất khó hiểu với tôi; điều này ngược lại với những gì xảy ra trong MATLAB, và tôi không chắc tôi thích nó. tuy nhiên, đó là những khoảnh khắc. – shabbychef

+0

@shabbychef, giá trị liên kết với tên luôn được tra cứu vào thời điểm cần thiết - không sớm hơn (và tất nhiên là không sau ;-). Các biến miễn phí được sử dụng trong các hàm (lambda hoặc cách khác) là các biến cục bộ trong một hàm "bên ngoài" chứa từ vựng không ngoại lệ cho quy tắc này! Cơ thể của hàm (một lần nữa, lambda hay không) luôn thực thi khi hàm được gọi, không sớm hơn (và dĩ nhiên là không muộn hơn) - vì vậy rõ ràng đó là khi các giá trị của các biến tự do là cần thiết, do đó, tất nhiên đó là khi chúng nhìn lên. Hành vi nào khác có thể phù hợp? –

+0

đủ kỳ quặc, hành vi của MATLAB trong vấn đề này là những gì tôi đã biết và chịu đựng; người ta có thể định nghĩa một hàm ẩn danh (về cơ bản là 'lambda'), sử dụng các biến từ phạm vi bên ngoài, và chúng được ràng buộc với giá trị khi hàm ẩn danh được tạo ra. trong thực tế, người ta có thể lưu các chức năng ẩn danh vào tập tin (chủ yếu tẩy nó), đóng matlab, tắt máy tính, quay lại, khởi động lại, tải lại và chức năng ẩn danh vẫn hoạt động, vẫn có các biến từ ngữ cảnh của nó. Tôi nghĩ rằng Mathworks đã phải làm điều này b/c chức năng nặc danh của họ rất hạn chế trong tính hữu dụng khác ... – shabbychef

0

Tôi tình cờ gặp lại vấn đề này một lần nữa, (sau nhiều năm trăn) trong khi cố gắng loại bỏ một sự phụ thuộc nhỏ vào sự numpy.

Nếu bạn đến từ MATLAB, bạn nên sử dụng và tin tưởng các chức năng numpy để xử lý mảng đơn loại. Cùng với matplotlib, chúng là một số gói rất thuận tiện cho việc chuyển đổi suôn sẻ.

import numpy as np 
np.zeros((4,)) # to make an array full of zeros [0,0,0,0] 
np.zeros((4,1)) # another one full of zeros but 2 dimensions [[0],[0],[0],[0]] 
np.zeros((4,0)) # an empty array like [[],[],[],[]] 
np.zeros((0,4)) # another empty array, which can not be represented with python lists o_O 

, vv

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