for value in Team_lst: # Mọi thứ mà bạn có thể dùng cú pháp “for … in …” đều là một iterable
“Team_lst” ở đây được gọi là một iterable. Mọi thứ mà bạn có thể dùng cú pháp “Team_lst = [1, 'Kteam', 2] #“Team_lst” ở đây được gọi là một iterable.
for value in kteam_lst: # Mọi thứ mà bạn có thể dùng cú pháp “for … in …” đều là một iterable
print(value)
print('Generator')for … in …” đều là một iterable. Ví dụ như chuỗi, list, tuple, file,..
Nhưng iterable này rất thuận tiện cho chúng ta lưu dữ và truy xuất thông tin. Và để được như vậy bạn phải lưu trữ những thông tin đó trong các vùng nhớ máy tính của bạn. Vì lẽ đó, sẽ có trường hợp bạn không cần thiết phải giữ tất cả thông tin cùng một lúc vì nó quá nhiều.
Team_gen=(value for value in range(3))
for value in Team_gen:
print(value)
# Không thể tái sử dụng đối với generator
for value in kteam_gen:
print(value)
Bạn thấy đấy, không có giá trị nào được in ra. Bởi vì khi nó sinh ra giá trị đầu tiên là 0, khi bạn kêu nó sinh tiếp giá trị 1, nó sẽ vứt bỏ giá trị 0 để nhường chỗ cho giá trị 1, và nếu bạn tiếp tục yêu cầu sinh thêm giá trị nó sẽ lại tiếp tục công việc như cũ cho tới khi kết thúc.
Lệnh yield
Lệnh này cách sử dụng gần giống với lệnh return, tuy nhiên nó khác return ở chỗ trả về một object thì yield sẽ trả về một generator.
Chúng ta hãy đến với một ví dụ với return sau đó ta sẽ so sánh nó với yield
print('Sử dụng return')
def square(lst):
sq_lst = []
for num in lst:
sq_lst.append(num**2)
return sq_lst # Sử dụng return sẽ trả về list chứa các phần tử có giá trị là bình phương của nó
kteam_ret = square([1, 2, 3])
for value in kteam_ret:
print(value)
Kết quả:
1
4
9
Như bạn thấy, vì return sẽ quăng lại một list lưu trữ toàn bộ giá trị sau khi bình phương, thế nên bạn phải tạo một list để lưu hết những giá trị đó. Tuy nhiên, điều này là không cần thiết với yield. Nó sẽ lần lượt sinh ra từng giá trị bình phương một mà không cần một list để lưu trữ. Mỗi lần bạn gọi nó, nó sẽ chạy vào sinh ra cho bạn giá trị bạn cần như việc bạn sử dụng vòng lặp for để đọc từng giá trị trong một list.
Khi bạn dùng yield trong một hàm và khi gọi hàm đó, những dòng lệnh trong hàm sẽ không chạy ngay. Nó trả về một generator. Và mỗi khi bạn yêu cần nó sinh thì nó mới bắt đầu chạy vào bên trong thực hiện những dòng lệnh trong hàm CHO TỚI KHI GẶP LỆNH YIELD và nó sẽ sinh ra giá trị bạn yêu cầu yield, hàm bây giờ được tạm dừng. Bạn cần lưu ý, là chỉ tạm dừng, có nghĩa là nếu lần sau gọi, hàm sẽ tiếp tục chạy ở phần đó không phải chạy lại từ đầu
Khi nào thì yield hết? Khi mà nó đi hết phần còn lại của hàm mà không gặp lệnh yield.
Bạn sẽ hiểu rõ hơn khi xem hai ví dụ sau đây.
print('Trường hợp 1: Sử dụng yield để sinh ra các phần tử của list')
def square(lst):
for num in lst:
yield num**2 # Sử dụng yield sẽ tự sinh ra phần tử trong list
kteam_gen = square([1, 2, 3])
for value in kteam_gen:
print(value)
print('Trường hợp 2: Sử dụng yield để xuất giá trị nhiều lần ')
def gen():
print('Đây là yield lần thứ nhất')
yield 'DTU'
print('Đây là yield lần thứ hai')
yield 'trường Đại học đầu tiên ở Miifn Trung'
print('Đây là yield lần thứ ba')
yield 'Đạt top 500 của Châu Á'
for value in gen():
print(value)
Bạn cũng cần lưu ý thêm, nếu không có giá trị
yield khi được gọi tiếp thì sẽ
yield sẽ không trả về bất cứ thứ gì, có nghĩa là
None object cũng không được trả về.
Phương thức send
Lưu ý: Bạn đọc cần đọc và ngẫm thật kĩ yield ở phía trên trước khi đọc đến phần này.
Đây là phương thức giúp bạn gửi giá trị vào trong một generator.
Cú pháp:
generator.send(value)
Bạn cũng không cần phải lo lắng nếu không hiểu được đoạn code dưới đây
print('Phương thức send')
print('Đây là phương thức giúp bạn gửi giá trị vào trong một generator.')
print('Ví dụ 1 - Phương thức send')
def gen():
for i in range(4):
x = yield i
print('value sent from you',x)
g = gen() # gán generator này cho biến g
next(g) # gọi hàm next để chạy lệnh yield "x = yield i"
g.send('ABC') # x vừa nãy khi gán cho biến yield giờ sẽ được gửi giá trị
print('Ví dụ 2 - Phương thức send')
def gen():
while True:
x=yield # ở đây ta đang yield None, vì ta không cần thiết sinh giá trị gì ở đây
yield x ** 2
g=gen()
print(next(g)) # chạy lệnh yield để ta gửi giá trị cho biến x lần sau
print(g.send(2))
print(next(g)) # tiếp tục chạy yield để có thể gửi giá trị
print(g.send(10))
Vì sao nên dùng yield
Tốc độ, khi sử dụng generator, để duyệt các giá trị thì generator sẽ nhanh hơn khi khi bạn duyệt một iterable lưu trữ một lúc tất cả các giá trị
Bộ nhớ, bạn sẽ phải cân nhắc việc dùng
yield khi bạn làm việc với những tập dữ liệu lớn. Lúc đó, bạn sẽ phải xem xét lại xem liệu bạn có cần giữ tất cả các giá trị một lúc không hay chỉ cần sinh ra từng giá trị một để tiết kiệm bộ nhớ.
print('Trường hợp 1: Sử dụng yield để sinh ra các phần tử của list')
def square(lst):
for num in lst:
yield num**2 # Sử dụng yield sẽ tự sinh ra phần tử trong list
kteam_gen = square([1, 2, 3])
for value in kteam_gen:
print(value)
print('Trường hợp 2: Sử dụng yield để xuất giá trị nhiều lần ')
def gen():
print('Đây là yield lần thứ nhất')
yield 'DTU'
print('Đây là yield lần thứ hai')
yield 'trường Đại học đầu tiên ở Miifn Trung'
print('Đây là yield lần thứ ba')
yield 'Đạt top 500 của Châu Á'
for value in gen():
print(value)
print('Phương thức send')
print('Đây là phương thức giúp bạn gửi giá trị vào trong một generator.')
print('Ví dụ 1 - Phương thức send')
def gen():
for i in range(4):
x = yield i
print('value sent from you',x)
g = gen() # gán generator này cho biến g
next(g) # gọi hàm next để chạy lệnh yield "x = yield i"
g.send('ABC') # x vừa nãy khi gán cho biến yield giờ sẽ được gửi giá trị
print('Ví dụ 2 - Phương thức send')
def gen():
while True:
x=yield # ở đây ta đang yield None, vì ta không cần thiết sinh giá trị gì ở đây
yield x ** 2
g=gen()
print(next(g)) # chạy lệnh yield để ta gửi giá trị cho biến x lần sau
print(g.send(2))
print(next(g)) # tiếp tục chạy yield để có thể gửi giá trị
print(g.send(10))
là iterator, một dạng của iterable nhưng khác ở chỗ bạn không thể tái sử dụng. Vì sao lại như vậy?