2016-06-28 13 views
8

Vì vậy, tôi đã xem bài nói chuyện của Raymond Hettinger Transforming Code into Beautiful, Idiomatic Python và anh ấy trả về hình thức iter mà tôi chưa bao giờ biết. Ví dụ của mình là như sau:Các công dụng của iter (callable, sentinel) là gì?

Thay vì:

blocks = [] 
while True: 
    block = f.read(32) 
    if block == '': 
     break 
    blocks.append(block) 

Sử dụng:

blocks = [] 
read_block = partial(f.read, 32) 
for block in iter(read_block, ''): 
    blocks.append(block) 

sau khi kiểm tra documentation của iter, tôi tìm thấy một ví dụ tương tự:

with open('mydata.txt') as fp: 
    for line in iter(fp.readline, ''): 
     process_line(line) 

này có vẻ khá hữu ích với tôi, nhưng tôi đã tự hỏi nếu bạn Pythonis tas biết của bất kỳ ví dụ về cấu trúc này mà không liên quan đến I/O-đọc vòng? Có lẽ trong Thư viện chuẩn?

tôi có thể nghĩ ra ví dụ rất giả tạo, như sau:

>>> def f(): 
...  f.count += 1 
...  return f.count 
... 
>>> f.count = 0 
>>> list(iter(f,20)) 
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 
>>> 

Nhưng rõ ràng đây không phải là bất kỳ hữu ích hơn mà được xây dựng trong iterables. Ngoài ra, nó có vẻ như mã mùi với tôi khi bạn đang gán trạng thái cho một hàm. Tại thời điểm đó, tôi có thể sẽ làm việc với một lớp học, nhưng nếu tôi sẽ viết một lớp, tôi cũng có thể thực hiện giao thức lặp cho bất cứ điều gì tôi muốn thực hiện.

+2

Đối với những người mà downvoted câu hỏi hoặc bình chọn để đóng, tôi sẽ đánh giá cao một số thông tin phản hồi như thế nào để hỏi câu hỏi này tốt hơn. –

Trả lời

4

như một quy luật, những ứng dụng chính tôi đã nhìn thấy hai arg iter liên quan đến chuyển đổi các hàm tương tự như các API C (trạng thái ngầm định, không có khái niệm lặp lại) cho các trình vòng lặp. Các đối tượng giống như tệp là một ví dụ phổ biến, nhưng nó xuất hiện trong các thư viện khác mà bao bọc các API C kém. Mẫu bạn mong đợi sẽ được thấy trong các API như FindFirstFile/FindNextFile, nơi tài nguyên được mở và mỗi cuộc gọi sẽ tiến hành trạng thái nội bộ và trả về giá trị mới hoặc biến đánh dấu (như NULL trong C). Việc gói nó trong một lớp thực hiện giao thức vòng lặp thường là tốt nhất, nhưng nếu bạn phải tự làm điều đó, trong khi API là một mức C tích hợp, gói có thể kết thúc việc sử dụng chậm, trong đó hai arg lặp lại, được thực hiện trong C như tốt, có thể tránh được chi phí thực thi mã byte bổ sung.

ví dụ khác liên quan đến đối tượng có thể thay đổi được thay đổi trong vòng lặp chính nó, ví dụ, vòng lặp theo thứ tự ngược trên dòng trong một bytearray, loại bỏ dòng chỉ một lần xử lý xong:

>>> from functools import partial 
>>> ba = bytearray(b'aaaa\n'*5) 
>>> for i in iter(partial(ba.rfind, b'\n'), -1): 
...  print(i) 
...  ba[i:] = b'' 
... 
24 
19 
14 
9 
4 

trường hợp khác là khi sử dụng cắt theo cách tiến bộ, ví dụ, cách hiệu quả (nếu được thừa nhận là xấu xí) để nhóm một nhóm có thể lặp lại thành các nhóm n mục trong khi cho phép nhóm cuối cùng nhỏ hơn n mục nếu đầu vào có thể lặp lại không phải là bội số của n các mặt hàng có chiều dài (cái này tôi đã thực sự sử dụng, mặc dù tôi thường sử dụng itertools.takewhile(bool thay vì hai arg iter):

# from future_builtins import map # Python 2 only 
from itertools import starmap, islice, repeat 

def grouper(n, iterable): 
    '''Returns a generator yielding n sized tuples from iterable 

    For iterables not evenly divisible by n, the final group will be undersized. 
    ''' 
    # Keep islicing n items and converting to groups until we hit an empty slice 
    return iter(map(tuple, starmap(islice, repeat((iter(iterable), n)))).__next__,()) # Use .next instead of .__next__ on Py2 

Một sử dụng: Viết nhiều đối tượng ngâm vào một tập tin duy nhất, sau đó là một giá trị trọng điểm (None chẳng hạn), vì vậy khi unpickling, bạn có thể sử dụng thành ngữ này thay vì cần phải bằng cách nào đó nhớ số các mặt hàng muối, hoặc cần phải gọi load hơn và hơn cho đến khi EOFError:

with open('picklefile', 'rb') as f: 
    for obj in iter(pickle.Unpickler(f).load, None): 
     ... process an object ... 
+0

Cảm ơn bạn đã liên quan đến các chức năng chuyển đổi tương tự như API C, đó chính xác là những gì tôi đang tìm kiếm. –

8

Dưới đây là một ví dụ ngớ ngẩn tôi đã đưa ra:

from functools import partial 
from random import randint 

pull_trigger = partial(randint, 1, 6) 

print('Starting a game of Russian Roulette...') 
print('--------------------------------------') 

for i in iter(pull_trigger, 6): 
    print('I am still alive, selected', i) 

print('Oops, game over, I am dead! :(') 

Mẫu đầu ra:

$ python3 roulette.py 
Starting a game of Russian Roulette... 
-------------------------------------- 
I am still alive, selected 2 
I am still alive, selected 4 
I am still alive, selected 2 
I am still alive, selected 5 
Oops, game over, I am dead! :(

Ý tưởng là để có một máy phát điện mà mang lại các giá trị ngẫu nhiên, và bạn muốn một quá trình một lần giá trị cụ thể đã được chọn. Bạn có thể ví dụ: sử dụng mẫu này trong mỗi lần chạy mô phỏng cố gắng xác định kết quả trung bình của một quá trình ngẫu nhiên.

Tất nhiên quá trình bạn sẽ là mô hình có khả năng sẽ phức tạp hơn nhiều dưới mui xe hơn một cuộn xúc xắc đơn giản ...

Một ví dụ khác tôi có thể nghĩ đến sẽ được thực hiện lặp đi lặp lại một hoạt động cho đến khi nó thành công, chỉ định bởi một thông báo lỗi rỗng (chúng ta hãy chỉ giả định rằng một số chức năng bên thứ 3 được thiết kế như thế thay vì ví dụ như sử dụng ngoại lệ):

from foo_lib import guess_password 

for msg in iter(guess_password, ''): 
    print('Incorrect attempt, details:', msg) 

# protection cracked, continue... 
+0

Tôi nên nghĩ đến một hàm trả lại giá trị ngẫu nhiên cho bản thân mình! –

Các vấn đề liên quan