2012-01-11 27 views
6

Tôi có một phương thức trong đó tôi cần chuyển một số nguyên ngày càng tăng sang một hàm khác.Có thể gọi tự động được không?

tôi có thể làm điều này như sau:

def foo(i): 
    print i 

def bar(): 

    class Incrementer(object): 
     def __init__(self, start=0): 
      self.i = start 

     def __get__(self): 
      j = self.i 
      self.i += 1 
      return j 

    number = Incrementer() 
    foo(number) 
    foo(number) 
    foo(number) 

đó một cách chính xác kết quả đầu ra 0 1 2 ... nhưng tôi cảm thấy như tôi đang nhìn ra một (hoặc built-in) cách dễ dàng hơn nhiều để làm điều này?

+1

Bạn có chắc là mã của bạn đang hoạt động không? Phương thức '__get __()' chỉ được gọi khi lấy một thuộc tính từ một lớp kiểu mới, mà dường như không xảy ra ở đây. –

+0

Đúng, nó hoạt động tốt. Bạn có nghĩa là nó chỉ nên làm việc nếu tôi: 'number = new Incrementer()'? Tại sao vậy? –

+1

[Tôi nghi ngờ mã của bạn in '0 1 2'] (http://ideone.com/kvCE1). Và tôi không nói về 'number = new Incrementer()' - bạn có vẻ khó hiểu ở đây, không có toán tử 'new' nào trong Python. Tôi đang nói về việc gọi [descriptors] (http://docs.python.org/reference/datamodel.html#descriptors). –

Trả lời

14

Hãy thử itertools.count() - nó thực hiện chính xác những gì bạn cần:

>>> c = itertools.count() 
>>> next(c) 
0 
>>> next(c) 
1 
>>> next(c) 
2 
+0

Đây chính xác là những gì tôi đang tìm kiếm. cảm ơn! –

7

Nói chung, nếu bạn cần phải duy trì trạng thái giữa một cuộc gọi đến một hàm và tiếp theo, những gì bạn muốn là một trong hai một đối tượng (của bạn giải pháp) hoặc máy phát điện. Trong một số trường hợp, một cái sẽ đơn giản hơn cái kia, nhưng không có gì là sai với cách bạn đã thực hiện nó, về nguyên tắc (mặc dù bạn dường như có một số vấn đề với việc triển khai).

Đề xuất của Sven, itertools.count(), là máy phát điện. thực hiện của nó là một cái gì đó như thế này:

def count(): 
    i = 0 
    while True: 
     yield i 
     i += 1 

Bây giờ, nếu bạn muốn nó được callable như một chức năng, thay vì phải làm next(c), bạn có thể định nghĩa một wrapper mà làm cho nó như vậy:

def count(c=itertools.count()): 
    return next(c) 

Hoặc một dòng không thể tránh khỏi lambda:

count = lambda c=itertools.count(): next(c) 

sau đó count() trả về số nguyên tiếp theo mỗi lần bạn gọi nó.

Tất nhiên, nếu bạn muốn để có thể tạo ra bất kỳ số chức năng có thể được gọi, đều có truy cập của riêng mình, bạn có thể viết một nhà máy cho rằng:

def counter(): 
    return lambda c=itertools.count(): next(c) 

Sau đó, nó là:

c = counter() 
print c() # 0 
print c() # 1 
# etc 

Điều này dường như vẫn đơn giản đối với tôi hơn là một đối tượng, nhưng không nhiều. Nếu trạng thái hoặc logic của bạn phức tạp hơn, việc đóng gói của đối tượng có thể thắng.

+1

Hoặc 'count = itertools.count() .__ next__', hoặc' count = itertools.count(). Next' cho Python 2.6 trở xuống. –

+1

@ F.J: Biến thể thứ hai áp dụng cho tất cả các phiên bản 2.x bao gồm 2.7. '__next __()' chỉ có sẵn trong 3.x. –

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