>>> range(1,11)
mang đến cho bạn
[1,2,3,4,5,6,7,8,9,10]
Tại sao không phải là 1-11?
Họ chỉ quyết định làm điều đó một cách ngẫu nhiên hay nó có một số giá trị mà tôi không thấy?
range()
có ý nghĩa thường xuyên hơn nhiều
>>> range(1,11)
mang đến cho bạn
[1,2,3,4,5,6,7,8,9,10]
Tại sao không phải là 1-11?
Họ chỉ quyết định làm điều đó một cách ngẫu nhiên hay nó có một số giá trị mà tôi không thấy?
range()
có ý nghĩa thường xuyên hơn nhiều
Câu trả lời:
Bởi vì nó phổ biến hơn để gọi range(0, 10)
trả về [0,1,2,3,4,5,6,7,8,9]
trong đó có 10 phần tử bằng nhau len(range(0, 10))
. Hãy nhớ rằng các lập trình viên thích lập chỉ mục dựa trên 0.
Ngoài ra, hãy xem xét đoạn mã phổ biến sau:
for i in range(len(li)):
pass
Bạn có thể thấy rằng nếu range()
đi lên chính xác len(li)
thì điều này sẽ có vấn đề? Các lập trình viên sẽ cần phải trừ một cách rõ ràng 1. Điều này cũng theo xu hướng chung của các lập trình viên thích for(int i = 0; i < 10; i++)
hơn for(int i = 0; i <= 9; i++)
.
Nếu bạn đang gọi phạm vi bắt đầu bằng 1 thường xuyên, bạn có thể muốn xác định chức năng của riêng mình:
>>> def range1(start, end):
... return range(start, end+1)
...
>>> range1(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
range(start, count)
không?
range(10)
là tương đương với range(0, 10)
.
range1
sẽ không làm việc với các phạm vi có kích thước bước khác 1
.
for i in range(len(li)):
đúng hơn là một antipotype. Người ta nên sử dụng enumerate
.
Mặc dù có một số giải thích thuật toán hữu ích ở đây, tôi nghĩ rằng nó có thể giúp thêm một số lý do đơn giản 'đời thực' vào lý do tại sao nó hoạt động theo cách này, điều mà tôi thấy hữu ích khi giới thiệu chủ đề này cho những người mới đến:
Với một cái gì đó như 'phạm vi (1,10)' có thể nảy sinh từ suy nghĩ rằng cặp tham số đại diện cho "bắt đầu và kết thúc".
Nó thực sự bắt đầu và "dừng lại".
Bây giờ, nếu đó là giá trị "kết thúc" thì, vâng, bạn có thể mong đợi số đó sẽ được đưa vào làm mục cuối cùng trong chuỗi. Nhưng nó không phải là "kết thúc".
Những người khác gọi nhầm tham số đó là "đếm" bởi vì nếu bạn chỉ sử dụng 'phạm vi (n)' thì dĩ nhiên, nó sẽ lặp đi lặp lại 'n' lần. Logic này bị hỏng khi bạn thêm tham số bắt đầu.
Vì vậy, điểm quan trọng là nhớ tên của nó: " dừng lại ". Điều đó có nghĩa là nó là điểm mà khi đạt tới, việc lặp lại sẽ dừng ngay lập tức. Không phải sau thời điểm đó.
Vì vậy, mặc dù "bắt đầu" thực sự đại diện cho giá trị đầu tiên được đưa vào, nhưng khi đạt đến giá trị "dừng", nó sẽ "phá vỡ" thay vì tiếp tục xử lý "giá trị đó" trước khi dừng.
Một điểm tương tự mà tôi đã sử dụng để giải thích điều này với trẻ em là, trớ trêu thay, nó lại cư xử tốt hơn trẻ em! Nó không dừng lại sau khi nó được yêu cầu - nó dừng lại ngay lập tức mà không hoàn thành những gì nó đang làm. (Họ hiểu điều này;))
Một sự tương tự khác - khi bạn lái xe ô tô, bạn không vượt qua điểm dừng / nhường / 'nhường đường' và kết thúc bằng việc ngồi ở đâu đó bên cạnh hoặc phía sau xe của bạn. Về mặt kỹ thuật bạn vẫn chưa đạt được nó khi bạn dừng lại. Nó không được bao gồm trong 'những điều bạn đã vượt qua trên hành trình của mình'.
Tôi hy vọng một số điều đó sẽ giúp giải thích cho Pythonitos / Pythonitas!
Nó hoạt động tốt kết hợp với lập chỉ mục dựa trên không và len()
. Ví dụ: nếu bạn có 10 mục trong danh sách x
, chúng được đánh số 0-9. range(len(x))
cho bạn 0-9.
Tất nhiên, mọi người sẽ nói với bạn rằng đó là nhiều Pythonic để làm for item in x
hay for index, item in enumerate(x)
hơn là for i in range(len(x))
.
Cắt lát cũng hoạt động theo cách đó: foo[1:4]
là các mục 1-3 của foo
(lưu ý rằng mục 1 thực sự là mục thứ hai do lập chỉ mục dựa trên số không). Để thống nhất, cả hai nên làm việc theo cùng một cách.
Tôi nghĩ về nó như sau: "số đầu tiên bạn muốn, tiếp theo là số đầu tiên bạn không muốn." Nếu bạn muốn 1-10, số đầu tiên bạn không muốn là 11, vì vậy nó là range(1, 11)
.
Nếu nó trở nên cồng kềnh trong một ứng dụng cụ thể, thật dễ dàng để viết một hàm trợ giúp nhỏ thêm 1 vào chỉ mục kết thúc và các cuộc gọi range()
.
w = 'abc'; w[:] == w[0:len(w)]; w[:-1] == w[0:len(w)-1];
def full_range(start,stop): return range(start,stop+1) ## helper function
for index, item in enumerate(x)
để tránh nhầm lẫn
Nó cũng hữu ích để phân chia phạm vi; range(a,b)
có thể được chia thành range(a, x)
và range(x, b)
, trong khi với phạm vi bao gồm bạn sẽ viết x-1
hoặc x+1
. Mặc dù bạn hiếm khi cần phân chia phạm vi, nhưng bạn có xu hướng phân chia danh sách khá thường xuyên, đó là một trong những lý do cắt một danh sách l[a:b]
bao gồm phần tử thứ a nhưng không phải là phần b. Sau đó range
có cùng một tài sản làm cho nó phù hợp độc đáo.
Độ dài của phạm vi là giá trị hàng đầu trừ đi giá trị dưới cùng.
Nó rất giống với một cái gì đó như:
for (var i = 1; i < 11; i++) {
//i goes from 1 to 10 in here
}
trong một ngôn ngữ kiểu C.
Cũng giống như phạm vi của Ruby:
1...11 #this is a range from 1 to 10
Tuy nhiên, Ruby nhận ra rằng nhiều lần bạn sẽ muốn bao gồm giá trị đầu cuối và cung cấp cú pháp thay thế:
1..10 #this is also a range from 1 to 10
1..10
vs 1...10
là khó để phân biệt giữa khi đọc mã!
Về cơ bản trong python range(n)
lặp đi lặp lại n
, đó là bản chất độc quyền đó là lý do tại sao nó không đưa ra giá trị cuối cùng khi nó được in, chúng ta có thể tạo một hàm mang lại giá trị bao gồm, nó cũng sẽ in giá trị cuối cùng được đề cập trong phạm vi.
def main():
for i in inclusive_range(25):
print(i, sep=" ")
def inclusive_range(*args):
numargs = len(args)
if numargs == 0:
raise TypeError("you need to write at least a value")
elif numargs == 1:
stop = args[0]
start = 0
step = 1
elif numargs == 2:
(start, stop) = args
step = 1
elif numargs == 3:
(start, stop, step) = args
else:
raise TypeError("Inclusive range was expected at most 3 arguments,got {}".format(numargs))
i = start
while i <= stop:
yield i
i += step
if __name__ == "__main__":
main()
Xem xét mã
for i in range(10):
print "You'll see this 10 times", i
Ý tưởng là bạn có được một danh sách độ dài y-x
mà bạn có thể (như bạn thấy ở trên) lặp đi lặp lại.
Đọc các tài liệu python cho phạm vi - họ xem xét lặp vòng lặp for usecase chính.
Nó chỉ thuận tiện hơn để lý do trong nhiều trường hợp.
Về cơ bản, chúng ta có thể nghĩ về một phạm vi như một khoảng giữa start
và end
. Nếu start <= end
, độ dài của khoảng giữa chúng là end - start
. Nếu len
thực sự được định nghĩa là độ dài, bạn sẽ có:
len(range(start, end)) == start - end
Tuy nhiên, chúng tôi đếm các số nguyên có trong phạm vi thay vì đo độ dài của khoảng. Để giữ cho thuộc tính trên đúng, chúng ta nên bao gồm một trong các điểm cuối và loại trừ các điểm cuối khác.
Thêm step
tham số giống như giới thiệu một đơn vị chiều dài. Trong trường hợp đó, bạn mong đợi
len(range(start, end, step)) == (start - end) / step
cho chiều dài. Để có được số đếm, bạn chỉ cần sử dụng phép chia số nguyên.