Hãy xem xét những điều sau đây:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Làm thế nào để tôi có được số lượng các yếu tố trong danh sách items
?
Hãy xem xét những điều sau đây:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
# FAKE METHOD:
items.amount() # Should return 3
Làm thế nào để tôi có được số lượng các yếu tố trong danh sách items
?
Câu trả lời:
Làm thế nào để có được kích thước của một danh sách?
Để tìm kích thước của danh sách, hãy sử dụng hàm dựng sẵn , len
:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
Và bây giờ:
len(items)
trả về 3.
Mọi thứ trong Python là một đối tượng, bao gồm cả danh sách. Tất cả các đối tượng có một tiêu đề của một số loại trong việc thực hiện C.
Danh sách và các đối tượng dựng sẵn tương tự khác có "kích thước" trong Python, đặc biệt, có một thuộc tính được gọi ob_size
, trong đó số lượng phần tử trong đối tượng được lưu trữ. Vì vậy, kiểm tra số lượng đối tượng trong một danh sách là rất nhanh.
Nhưng nếu bạn đang kiểm tra xem kích thước danh sách có bằng 0 hay không, thì đừng sử dụng len
- thay vào đó, hãy đặt danh sách đó trong bối cảnh boolean - nó được coi là Sai nếu trống, Đúng khác .
len(s)
Trả về chiều dài (số lượng vật phẩm) của một đối tượng. Đối số có thể là một chuỗi (chẳng hạn như chuỗi, byte, tuple, danh sách hoặc phạm vi) hoặc một bộ sưu tập (chẳng hạn như từ điển, tập hợp hoặc tập hợp đóng băng).
len
được thực hiện với __len__
, từ các tài liệu mô hình dữ liệu :
object.__len__(self)
Được gọi để thực hiện chức năng tích hợp
len()
. Nếu trả về độ dài của đối tượng, một số nguyên> = 0. Ngoài ra, một đối tượng không xác định phương thức__nonzero__()
[trong Python 2 hoặc__bool__()
trong Python 3] và__len__()
phương thức của nó trả về 0 được coi là sai trong ngữ cảnh Boolean.
Và chúng ta cũng có thể thấy đó __len__
là một phương pháp của danh sách:
items.__len__()
trả về 3.
len
(độ dài) củaVà trên thực tế, chúng tôi thấy chúng tôi có thể nhận được thông tin này cho tất cả các loại được mô tả:
>>> all(hasattr(cls, '__len__') for cls in (str, bytes, tuple, list,
xrange, dict, set, frozenset))
True
len
để kiểm tra danh sách trống hoặc không trốngTất nhiên, để kiểm tra độ dài cụ thể, chỉ cần kiểm tra sự bằng nhau:
if len(items) == required_length:
...
Nhưng có một trường hợp đặc biệt để kiểm tra danh sách độ dài bằng không hoặc nghịch đảo. Trong trường hợp đó, không kiểm tra sự bình đẳng.
Ngoài ra, không làm:
if len(items):
...
Thay vào đó, chỉ cần làm:
if items: # Then we have some items, not empty!
...
hoặc là
if not items: # Then we have an empty list!
...
Tôi giải thích tại sao ở đây nhưng trong ngắn hạn, if items
hoặc if not items
là cả dễ đọc hơn và hiệu quả hơn.
Mặc dù điều này có thể không hữu ích do thực tế là nó có ý nghĩa hơn nhiều so với chức năng "ngoài luồng", một cách hack khá đơn giản sẽ là xây dựng một lớp với một thuộc length
tính:
class slist(list):
@property
def length(self):
return len(self)
Bạn có thể sử dụng nó như vậy:
>>> l = slist(range(10))
>>> l.length
10
>>> print l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Về cơ bản, nó hoàn toàn giống hệt với một đối tượng danh sách, với lợi ích bổ sung là có một length
tài sản thân thiện với OOP .
Như mọi khi, phụ cấp của bạn có thể khác nhau.
length = property(len)
và bỏ qua chức năng trình bao bọc một dòng và giữ tài liệu / hướng nội len
với tài sản của bạn.
Ngoài ra, len
bạn cũng có thể sử dụng operator.length_hint
(yêu cầu Python 3,4+). Đối với list
cả hai bình thường đều tương đương, nhưng length_hint
làm cho nó có thể có được độ dài của trình lặp danh sách, có thể hữu ích trong một số trường hợp nhất định:
>>> from operator import length_hint
>>> l = ["apple", "orange", "banana"]
>>> len(l)
3
>>> length_hint(l)
3
>>> list_iterator = iter(l)
>>> len(list_iterator)
TypeError: object of type 'list_iterator' has no len()
>>> length_hint(list_iterator)
3
Nhưng length_hint
theo định nghĩa chỉ là một "gợi ý", vì vậy hầu hết thời gian len
là tốt hơn.
Tôi đã thấy một số câu trả lời đề nghị truy cập __len__
. Điều này hoàn toàn đúng khi xử lý các lớp tích hợp như list
, nhưng nó có thể dẫn đến các vấn đề với các lớp tùy chỉnh, bởi vì len
(và length_hint
) thực hiện một số kiểm tra an toàn. Ví dụ: cả hai đều không cho phép độ dài âm hoặc độ dài vượt quá một giá trị nhất định (sys.maxsize
giá trị). Vì vậy, nó luôn an toàn hơn khi sử dụng len
hàm thay vì __len__
phương thức!
Trả lời câu hỏi của bạn như các ví dụ cũng được đưa ra trước đây:
items = []
items.append("apple")
items.append("orange")
items.append("banana")
print items.__len__()
__foo__
: đây chỉ là một quy ước, một cách để hệ thống Python sử dụng các tên không xung đột với tên người dùng. 2 . _foo
: đây chỉ là một quy ước, một cách để lập trình viên chỉ ra rằng biến đó là riêng tư (bất cứ điều gì có nghĩa là trong Python). 3 . __foo
: điều này có ý nghĩa thực sự: trình thông dịch thay thế tên này _classname__foo
như một cách để đảm bảo rằng tên đó sẽ không trùng với tên tương tự trong một lớp khác. * Không có hình thức gạch dưới nào khác có ý nghĩa trong thế giới Python. * Không có sự khác biệt giữa lớp, biến, toàn cầu, vv trong các quy ước này.
Và để hoàn thiện (chủ yếu là giáo dục), có thể mà không cần sử dụng len()
chức năng. Tôi sẽ không chấp nhận điều này như là một lựa chọn tốt ĐỪNG CHƯƠNG TRÌNH THÍCH NÀY TRONG PYTHON , nhưng nó phục vụ mục đích học thuật toán.
def count(list):
item_count = 0
for item in list[:]:
item_count += 1
return item_count
count([1,2,3,4,5])
(Dấu hai chấm list[:]
là ẩn và do đó cũng là tùy chọn.)
Bài học ở đây cho các lập trình viên mới là: Bạn không thể có được số lượng mục trong danh sách mà không đếm chúng tại một số điểm. Câu hỏi trở thành: khi nào là thời điểm tốt để đếm chúng? Ví dụ, mã hiệu suất cao như cuộc gọi hệ thống kết nối cho các ổ cắm (được viết bằng C) connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
, không tính toán độ dài của các phần tử (giao trách nhiệm đó cho mã gọi). Lưu ý rằng độ dài của địa chỉ được truyền qua để lưu bước đếm chiều dài trước? Một tùy chọn khác: tính toán, có thể có ý nghĩa để theo dõi số lượng vật phẩm khi bạn thêm chúng vào trong đối tượng mà bạn vượt qua. Lưu ý rằng điều này chiếm nhiều không gian trong bộ nhớ. Xem câu trả lời của Naftuli Kay .
Ví dụ về việc theo dõi độ dài để cải thiện hiệu suất trong khi chiếm nhiều không gian hơn trong bộ nhớ. Lưu ý rằng tôi không bao giờ sử dụng hàm len () vì độ dài được theo dõi:
class MyList(object):
def __init__(self):
self._data = []
self.length = 0 # length tracker that takes up memory but makes length op O(1) time
# the implicit iterator in a list class
def __iter__(self):
for elem in self._data:
yield elem
def add(self, elem):
self._data.append(elem)
self.length += 1
def remove(self, elem):
self._data.remove(elem)
self.length -= 1
mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
print(mylist.length) # 3
mylist.remove(3)
print(mylist.length) # 2
for item in list[:]:
? Tại sao không for item in list:
? Ngoài ra, tôi sẽ sử dụng += 1
để tăng lên.
Về cách thức len()
thực sự hoạt động, đây là triển khai C của nó :
static PyObject *
builtin_len(PyObject *module, PyObject *obj)
/*[clinic end generated code: output=fa7a270d314dfb6c input=bc55598da9e9c9b5]*/
{
Py_ssize_t res;
res = PyObject_Size(obj);
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
return PyLong_FromSsize_t(res);
}
Py_ssize_t
là chiều dài tối đa mà đối tượng có thể có. PyObject_Size()
là một hàm trả về kích thước của một đối tượng. Nếu nó không thể xác định kích thước của một đối tượng, nó sẽ trả về -1. Trong trường hợp đó, khối mã này sẽ được thực thi:
if (res < 0) {
assert(PyErr_Occurred());
return NULL;
}
Và một ngoại lệ được đưa ra như là kết quả. Nếu không, khối mã này sẽ được thực thi:
return PyLong_FromSsize_t(res);
res
đó là một C
số nguyên, được chuyển đổi thành một con trăn long
và được trả lại. Tất cả các số nguyên python được lưu trữ longs
kể từ Python 3.