python: Hãy cẩn thận ở những nơi này.
python是一门非常有趣的语言。它提供了许多非常方便的标准库和许多内置命令是我们轻松完成任务.但是好东西太多了就有选择恐惧症了,以至于我们不能很好第利用这个标准库和它的基本机构。下面列出了一些对python新手来说很简单有效的陷阱。
Phân loại phiên bản của Python
Đây là một vấn đề mà mọi người liên tục đưa ra trên StackOverflow. Khi bạn chạy mã hoàn hảo trên máy tính của người khác, bạn sẽ phải kiểm tra xem phiên bản python của bạn có phù hợp không. Hãy chắc chắn rằng mã của bạn chạy trên phiên bản python mà bạn biết. Bạn có thể xem phiên bản python bằng mã sau:
$ python --version
Python 2.7.9
quản lý phiên bản python
pyenv là một công cụ quản lý phiên bản python tốt. Thật không may, nó chỉ chạy trên hệ thống *nix. Trên Mac OS, bạn có thể đơn giản cài đặt pyenv bằng brew install.
Bị mắc kẹt trong việc giải quyết tất cả các vấn đề bằng một dòng mã
Nhiều người khoe rằng tôi đã giải quyết tất cả các vấn đề bằng một dòng mã, ngay cả khi mã của họ kém hiệu quả hơn so với mã viết bình thường, và mã đó khó đọc hơn, thậm chí có thể gây hiểu nhầm; ví dụ:
l = [m for a, b in zip(this, that) if b.method(a) != b for m in b if not m.method(a, b) and reduce(lambda x, y: a + y.method(), (m, a, b))]
Thật ra, tôi đã viết mã trên để minh họa cho điều này. Nhưng tôi đã thấy rất nhiều người đã làm điều này. Nếu bạn chỉ đơn giản là thêm một thứ vào một danh sách hoặc một tập hợp để chứng minh mình đang giải quyết một vấn đề phức tạp, bạn có thể sẽ không được trả tiền.
Một dòng mã kiểm soát không phải là một thành tựu lớn, mặc dù đôi khi có vẻ đặc biệt thông minh. Mã tốt là ngắn gọn nhưng tập trung nhiều hơn vào hiệu quả và dễ đọc.
Set khởi động sai
这是一个更加微妙的问题,有时候会让你措手不及。set推导式起来有点像list推导式.
>>> { n for n in range(10) if n % 2 == 0 }
{0, 8, 2, 4, 6}
>>> type({ n for n in range(10) if n % 2 == 0 })
Ví dụ trên cho thấy điều này. Set giống như đặt list trong một container. Sự khác biệt của chúng là các tập hợp không có giá trị lặp lại và không có thứ tự. Người ta thường coi {} là một tập hợp trống, nhưng nó không phải, nó là một tập lệnh trống.
>>> {}
{}
>>> type({})
Vì vậy, nếu chúng ta muốn khởi tạo một tập hợp trống, chúng ta chỉ cần sử dụng tập hợp
>>> set()
set()
>>> type(set())
Lưu ý rằng một set trống có thể được thể hiện như là một set (((), nhưng là một tập hợp chứa các yếu tố để được định nghĩa là một set (([1, 2])).
Nhầm lẫn GIL
GIL (global interpreter lock) có nghĩa là chỉ có một chuỗi trong một chương trình Python có thể chạy tại bất kỳ thời điểm nào. Điều này có nghĩa là khi chúng ta không thể tạo ra một chuỗi và mong đợi nó chạy song song. Các trình giải thích Python thực sự làm là nhanh chóng chuyển đổi các chuỗi chạy khác nhau.
Nhiều người sẽ cố gắng bào chữa cho Python rằng tất cả những điều này đều là các chuỗi thực. 3 Điều này thực sự đúng, nhưng không thay đổi một thực tế: Python xử lý các chuỗi khác với cách bạn mong đợi. Ruby cũng có tình huống tương tự ((và có một khóa giải thích)).
Giải pháp được đề xuất là sử dụng các module đa xử lý. Các quy trình được cung cấp bởi các module đa xử lý về cơ bản có thể che phủ sự khác biệt tốt. Tuy nhiên, sự khác biệt cao hơn nhiều so với chi phí của các chuỗi. Vì vậy, chạy song song không phải lúc nào cũng tốt.
Tuy nhiên, không phải tất cả các chương trình Python đều gặp phải vấn đề này. PyPy-stm là một ví dụ về việc triển khai Python không bị ảnh hưởng bởi GIL. Các triển khai được xây dựng trên các nền tảng khác như JVM (Jython) hoặc CLR (IronPython) không có vấn đề GIL.
Nói tóm lại, hãy cẩn thận khi sử dụng các loại thread, bạn có thể không nhận được những gì bạn muốn.
Sử dụng kiểu lỗi thời
Trong Python 2 có hai loại lớp, lớp kiểu cũ và lớp kiểu mới. Nếu bạn đang sử dụng Python 3, bạn đang sử dụng lớp kiểu mới mặc định. Để đảm bảo bạn sử dụng lớp kiểu mới trong Python 2, bạn cần phải thừa hưởng object hoặc bất kỳ lớp mới nào bạn tạo không phải lúc nào cũng thừa hưởng lệnh int hoặc list.
class MyNewObject(object): # stuff here
Những kiểu dáng mới này sửa chữa một số vấn đề rất cơ bản trong các kiểu dáng cũ, nếu bạn quan tâm, bạn có thể xem tài liệu.
Sự lặp lại sai
Những sai lầm sau đây là rất phổ biến đối với những người mới bắt đầu:
for name_index in range(len(names)):
print(names[name_index])
Rõ ràng là không cần phải sử dụng len, thực tế, đi qua danh sách có thể được thực hiện bằng một câu rất đơn giản:
for name in names:
print(name)
Ngoài ra, có một loạt các công cụ khác để bạn xử lý việc đơn giản hóa lặp đi lặp lại. Ví dụ, zip có thể được sử dụng để đi qua hai danh sách:
for cat, dog in zip(cats, dogs):
print(cat, dog)
Nếu chúng ta muốn xem xét các biến trong danh sách chỉ mục và giá trị, chúng ta có thể sử dụng enumerate
for index, cat in enumerate(cats):
print(cat, index)
Có rất nhiều tính năng khác trong iTools. Nếu iTools có một tính năng mà bạn muốn, nó rất dễ dàng để sử dụng. Nhưng cũng đừng sử dụng nó quá nhiều để sử dụng nó.
Các itertools lạm dụng khiến một vị thần lớn trên StackOverflow mất nhiều thời gian để giải quyết nó.
Sử dụng các tham số mặc định biến
Tôi đã đọc rất nhiều bài như sau:
def foo(a, b, c=[]):
# append to c
# do some more stuff
Không sử dụng các tham số mặc định thay vì biến:
def foo(a, b, c=None):
if c is None:
c = []
# append to c
# do some more stuff
Ví dụ dưới đây sẽ giúp chúng ta hiểu vấn đề một cách trực quan:
In[2]: def foo(a, b, c=[]):
... c.append(a)
... c.append(b)
... print(c)
...
In[3]: foo(1, 1)
[1, 1]
In[4]: foo(1, 1)
[1, 1, 1, 1]
In[5]: foo(1, 1)
[1, 1, 1, 1, 1, 1]
Cùng một c được trích dẫn nhiều lần mỗi lần gọi hàm này. Điều này có thể gây ra một số hậu quả rất không mong muốn.