Có một biểu thức cho một máy phát điện vô hạn?


119

Có biểu thức máy phát chuyển tiếp thẳng có thể sinh ra phần tử vô hạn không?

Đây là một câu hỏi lý thuyết thuần túy. Không cần câu trả lời "thực tế" ở đây :)


Ví dụ, có thể dễ dàng tạo một máy phát hữu hạn:

my_gen = (0 for i in xrange(42))

Tuy nhiên, để tạo một cái vô hạn, tôi cần "gây ô nhiễm" không gian tên của mình bằng một hàm không có thật:

def _my_gen():
    while True:
        yield 0
my_gen = _my_gen()

Làm những việc trong một tệp riêng biệt và import-ing sau đó không được tính.


Tôi cũng biết điều đó itertools.repeatlàm chính xác điều này. Tôi tò mò nếu có một giải pháp một lớp lót mà không có điều đó.


9
Bạn thực sự không cần phải làm ô nhiễm không gian tên của mình ... chỉ cần đặt tên cho hàm my_genvà sau đó thực hiện my_gen = my_gen().
6502

2
bạn cũng có thể sử dụng del _my_gennếu bạn không muốn nhầm lẫn giữa hai
John La Rooy

Câu trả lời:


133
for x in iter(int, 1): pass
  • Hai đối số iter= không đối số có thể gọi + giá trị sentinel
  • int() luôn trở lại 0

Do đó, iter(int, 1)là một trình lặp vô hạn. Rõ ràng là có một số lượng lớn các biến thể về chủ đề cụ thể này (đặc biệt là khi bạn thêm lambdavào hỗn hợp). Một biến thể của lưu ý cụ thể là iter(f, object()), khi sử dụng một đối tượng mới được tạo làm giá trị sentinel gần như đảm bảo một trình lặp vô hạn bất kể có thể gọi được sử dụng làm đối số đầu tiên.


3
một cách rất thú vị để sử dụng itervới tài sản intmà chúng ta nhiều lần quên.
Senthil Kumaran

3
bạn có thể sử dụng công thức kỳ diệu này để mô phỏng itertools.count:count = lambda start=0, step=1: (start + i*step for i, _ in enumerate(iter(int, 1)))
Coffee_Table

1
Chỉ cần để giải thích những gì đang xảy ra ở đây: Khi iter-function được gọi với hai đối số, nó cư xử hơi khác một chút so với bình thường: iter(callable, sentinel) -> iterator. Đối số 1, callableđược gọi cho mọi lần lặp của trình lặp, cho đến khi nó trả về giá trị của sentinel. Tuy nhiên, như int()sẽ luôn quay trở lại 0, chúng ta có thể gọi int()mãi mãi và không bao giờ đạt được 1. Điều này có hiệu lực sẽ tạo ra một danh sách vô hạn của 0's
Olsgaard

217

itertools cung cấp ba máy phát điện vô hạn:

Tôi không biết bất kỳ người nào khác trong thư viện tiêu chuẩn.


Vì bạn đã yêu cầu một lớp lót:

__import__("itertools").count()

18
Re: repeat (x, times = ∞) - không có biểu tượng nào cho những ai thắc mắc - việc bỏ qua đối số sẽ khiến lặp lại chạy mãi mãi
Mr_and_Mrs_D

Được tán thành vì (trong khi câu trả lời của ncoghlan trực tiếp giải quyết câu hỏi của OP) thì điều này thường áp dụng hơn.
Huw Walters

Đây là một điều đáng đọc hơn rất nhiều so với iter(int, 1)câu thần chú. Thật tệ là itertoolskhông có một endlessly()phương pháp có mục đích duy nhất là làm điều này; itertools.count()không phải tất cả những thứ đó cũng có thể đọc được.
BallpointBen

19

bạn có thể lặp lại một hằng số có thể gọi trả về một hằng số luôn khác với sentinel của iter ()

g1=iter(lambda:0, 1)

8
Tôi vừa yêu vừa ghét điều này ... Tôi thích việc nó đạt được những gì tôi muốn với rất ít nhân vật, nhưng ghét việc không ai có thể nhìn vào nó và biết nó phải làm gì.
ArtOfWarfare

1
biết cú pháp của iter(ở đây với thêm sentinel) và cú pháp của lambda(ở đây mà không có bất kỳ tham số được truyền nào, chỉ return 0), nơi duy nhất để ghét là bí ẩn đó g1.
Sławomir Lenart

@ SławomirLenart đàn ông không bao giờ mắc phải. Nó chỉ là nó rất nhỏ nên tôi đã phun 1g.
user237419

8

Hệ điều hành của bạn có thể cung cấp thứ gì đó có thể được sử dụng như một bộ tạo vô hạn. Vd: trên linux

for i in (0 for x in open('/dev/urandom')):
    print i

rõ ràng là điều này không hiệu quả bằng

for i in __import__('itertools').repeat(0)
    print i

11
Giải pháp / dev / urandom thỉnh \nthoảng lại xuất hiện ... Thật đáng sợ! :)
ômomg

5

Không có nội bộ nào không sử dụng một trình lặp vô hạn khác được định nghĩa là một lớp / hàm / trình tạo (không phải -expression, một hàm với yield). Một biểu thức trình tạo luôn lấy từ anoter có thể lặp lại và không làm gì khác ngoài việc lọc và ánh xạ các mục của nó. Bạn không thể đi từ các mục hữu hạn đến các mục vô hạn chỉ với mapfilter, bạn cần while(hoặc một mục forkhông kết thúc, đó chính xác là những gì chúng ta không thể có bằng cách sử dụng fortrình vòng lặp chỉ và hữu hạn).

Thông tin bên lề: PEP 3142 bề ngoài tương tự, nhưng khi kiểm tra kỹ hơn, có vẻ như nó vẫn yêu cầu forđiều khoản (vì vậy không (0 while True)cho bạn), tức là chỉ cung cấp một phím tắt cho itertools.takewhile.


Như tôi đã nghi ngờ ... Vậy chúng ta có thể chắc chắn rằng không có một máy phát điện vô hạn sẵn có để lạm dụng không? (Đáng tiếc là xrange (0,1, -1) không hoạt động ...)
ômomg vào

2
@missingno: from itertools import repeat, count, cyclecó thể được coi là "sẵn có" đối với hầu hết mọi người.
ncoghlan

1
Rất tiếc, tôi đã quên về 2 đối số iter. Lặp vô hạn thực sự sẵn sàng như một dựng sẵn - xem câu trả lời của tôi :)
ncoghlan

5

Khá xấu và điên rồ (tuy nhiên rất buồn cười), nhưng bạn có thể xây dựng trình lặp của riêng mình từ một biểu thức bằng cách sử dụng một số thủ thuật (mà không làm "ô nhiễm" không gian tên của bạn theo yêu cầu):

{ print("Hello world") for _ in
    (lambda o: setattr(o, '__iter__', lambda x:x)
            or setattr(o, '__next__', lambda x:True)
            or o)
    (type("EvilIterator", (object,), {}))() } 

Bạn rõ ràng yêu LISP
Faissaloo

1
@Faissaloo Thật vậy ... Bạn có thể tìm thấy một biểu hiện vẫn còn điên rồ hơn trên một trang cũ mà tôi đã viết: baruchel.github.io/python/2018/06/20/…
Thomas Baruchel

2

Có thể bạn có thể sử dụng các trình trang trí như thế này chẳng hạn:

def generator(first):
    def wrap(func):
        def seq():
            x = first
            while True:
                yield x
                x = func(x)
        return seq
    return wrap

Cách sử dụng (1):

@generator(0)
def blah(x):
    return x + 1

for i in blah():
    print i

Cách sử dụng (2)

for i in generator(0)(lambda x: x + 1)():
    print i

Tôi nghĩ rằng nó có thể được cải thiện hơn nữa để loại bỏ những xấu xí (). Tuy nhiên, nó phụ thuộc vào độ phức tạp của chuỗi mà bạn muốn có thể tạo. Nói chung, nếu trình tự của bạn có thể được thể hiện bằng cách sử dụng các hàm, hơn tất cả độ phức tạp và cú pháp của trình tạo có thể bị ẩn bên trong trình trang trí hoặc một chức năng giống như trình trang trí.


9
OP yêu cầu một dòng kẻ và bạn trình bày một bộ trang trí 10 dòng với bộ ba lồng defvà đóng? ;)

2
@delnan Chà, nhưng nếu bạn xác định trang trí một lần, bạn có thể có một lớp lót của mình, phải không? Như tôi hiểu, mục đích là để mỗi bộ tạo vô hạn bổ sung được triển khai trong một dòng. Và đây là những gì được trình bày ở đây. Bạn có thể có (2^x), bạn có thể có (x). Nếu bạn cải thiện nó một chút có thể cũng fibonacci vv
julx

Không trả lời câu hỏi của tôi, nhưng làm thế nào bạn có thể không yêu tất cả những đóng cửa mềm mại? BTW, tôi khá chắc chắn rằng bạn có thể thoát khỏi dấu ngoặc thêm bằng cách loại bỏ seqvà thụt lại mã trực tiếpwrap
hugomg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.