Các trình tạo được đánh giá lười biếng vì vậy return
hoặc yield
sẽ hành xử khác đi khi bạn gỡ lỗi mã của mình hoặc nếu một ngoại lệ được đưa ra.
Với return
bất kỳ ngoại lệ nào xảy ra trong bạn generator
sẽ không biết gì generate_all
, đó là vì khi generator
thực sự được thực thi, bạn đã rời khỏi generate_all
chức năng. Với yield
trong đó nó sẽ có generate_all
trong truy nguyên.
def generator(some_list):
for i in some_list:
raise Exception('exception happened :-)')
yield i
def generate_all():
some_list = [1,2,3]
return generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-3-b19085eab3e1> in <module>
8 return generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-3-b19085eab3e1> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
Và nếu nó đang sử dụng yield from
:
def generate_all():
some_list = [1,2,3]
yield from generator(some_list)
for item in generate_all():
...
Exception Traceback (most recent call last)
<ipython-input-4-be322887df35> in <module>
8 yield from generator(some_list)
9
---> 10 for item in generate_all():
11 ...
<ipython-input-4-be322887df35> in generate_all()
6 def generate_all():
7 some_list = [1,2,3]
----> 8 yield from generator(some_list)
9
10 for item in generate_all():
<ipython-input-4-be322887df35> in generator(some_list)
1 def generator(some_list):
2 for i in some_list:
----> 3 raise Exception('exception happened :-)')
4 yield i
5
Exception: exception happened :-)
Tuy nhiên điều này đi kèm với chi phí hiệu suất. Lớp máy phát bổ sung không có một số chi phí. Vì vậy, return
nói chung sẽ nhanh hơn một chút so với yield from ...
(hoặc for item in ...: yield item
). Trong hầu hết các trường hợp, điều này sẽ không quan trọng lắm, bởi vì bất cứ điều gì bạn làm trong trình tạo thường chiếm ưu thế trong thời gian chạy để lớp bổ sung sẽ không được chú ý.
Tuy nhiên yield
có một số lợi thế bổ sung: Bạn không bị hạn chế trong một lần lặp duy nhất, bạn cũng có thể dễ dàng mang lại các mục bổ sung:
def generator(some_list):
for i in some_list:
yield i
def generate_all():
some_list = [1,2,3]
yield 'start'
yield from generator(some_list)
yield 'end'
for item in generate_all():
print(item)
start
1
2
3
end
Trong trường hợp của bạn, các thao tác khá đơn giản và tôi không biết liệu có cần thiết phải tạo nhiều hàm cho việc này hay không, người ta có thể dễ dàng sử dụng biểu thức dựng sẵn map
hoặc biểu thức tạo:
map(do_something, get_the_list()) # map
(do_something(i) for i in get_the_list()) # generator expression
Cả hai nên giống hệt nhau (ngoại trừ một số khác biệt khi ngoại lệ xảy ra) để sử dụng. Và nếu họ cần một cái tên mô tả hơn, thì bạn vẫn có thể bọc chúng trong một chức năng.
Có nhiều trình trợ giúp bao bọc các hoạt động rất phổ biến trên các trình lặp được tích hợp sẵn và các trình trợ giúp khác có thể được tìm thấy trong itertools
mô-đun tích hợp. Trong những trường hợp đơn giản như vậy, tôi chỉ đơn giản là dùng đến những thứ này và chỉ cho những trường hợp không tầm thường hãy viết máy phát điện của riêng bạn.
Nhưng tôi cho rằng mã thực của bạn phức tạp hơn nên có thể không áp dụng được nhưng tôi nghĩ nó sẽ không phải là một câu trả lời hoàn chỉnh mà không đề cập đến các lựa chọn thay thế.