2013-09-26 184 views
7

Tôi đã viết một lớp đọc một tệp txt. Các tập tin được bao gồm các khối của dòng không trống (hãy gọi họ là "phần"), cách nhau bằng một dòng trống:máy phát điện trăn của máy phát điện?

line1.1 
line1.2 
line1.3 

line2.1 
line2.2 

thực hiện đầu tiên của tôi là để đọc toàn bộ tập tin và trả về một danh sách liệt kê, mà là một danh sách các phần, trong đó mỗi phần là một danh sách các dòng. Điều này rõ ràng là khủng khiếp về trí nhớ.

Vì vậy, tôi đã triển khai lại nó dưới dạng trình tạo danh sách, đó là ở mọi chu kỳ lớp của tôi đọc toàn bộ phần trong bộ nhớ dưới dạng danh sách và tạo ra nó.

Điều này là tốt hơn, nhưng nó vẫn còn có vấn đề trong trường hợp các phần lớn. Vì vậy, tôi tự hỏi nếu tôi có thể reimplement nó như là một máy phát điện của máy phát điện? Vấn đề là lớp học này rất chung chung và có thể đáp ứng cả hai trường hợp sử dụng sau:

  1. đọc một tệp rất lớn, chỉ đọc một phần rất lớn. Một máy phát điện của máy phát điện là hoàn hảo cho việc này.
  2. đọc một tệp nhỏ vào bộ nhớ được xoay vòng nhiều lần. Một máy phát điện các danh sách hoạt động tốt, vì người dùng chỉ có thể gọi

    danh sách (MyClass (file_handle))

Tuy nhiên, một máy phát điện của máy phát điện sẽ không hoạt động trong trường hợp 2, khi các đối tượng bên trong sẽ không được chuyển thành danh sách.

Có điều gì tao nhã hơn việc thực hiện phương thức to_list() rõ ràng, điều đó có thể biến đổi trình tạo máy phát điện thành danh sách các danh sách không?

+0

Bạn đã thử làm việc với readline chưa. Bằng cách này, chỉ đọc một dòng duy nhất; được giới hạn bởi dòng mới. Đây là một cách tốt để tải dữ liệu nhỏ trong bộ nhớ, trừ khi chính dòng của bạn là rất lớn. – Vivek

+0

@Vivek Đường của tôi rất phức tạp, và từ mỗi người trong số họ tôi tạo ra một đối tượng xác nhận dòng và trạng thái của nó phụ thuộc vào các dòng trước đó. Việc hiển thị định dạng nội bộ của tệp cho người dùng không phải là một tùy chọn. – crusaderky

+0

bạn có thể nhập dòng mẫu ... – Vivek

Trả lời

6

Python 2:

map(list, generator_of_generators) 

Python 3:

list(map(list, generator_of_generators)) 

hoặc cho cả hai:

[list(gen) for gen in generator_of_generators] 

Kể từ khi đối tượng được tạo ra là generator functions, không chỉ máy phát điện, bạn 'd muốn làm

[list(gen()) for gen in generator_of_generator_functions] 

Nếu điều đó không hiệu quả thì tôi không biết bạn đang hỏi gì. Ngoài ra, tại sao nó sẽ trả về một chức năng máy phát điện và không phải là một máy phát điện?


Kể từ khi nhận xét bạn cho biết bạn muốn tránh list(generator_of_generator_functions) do gặp sự cố một cách bí ẩn, điều này phụ thuộc vào những gì bạn thực sự muốn.

  • Đó là không có thể ghi đè lên hành vi của list theo cách này: hoặc bạn lưu trữ các yếu tố phụ máy phát điện hay không

  • Nếu bạn thực sự làm được một vụ tai nạn, tôi khuyên bạn nên cạn kiệt máy phát điện phụ với vòng lặp máy phát điện chính mỗi lần máy phát điện chính lặp lại. Đây là thực hành tiêu chuẩn và chính xác những gì itertools.groupby làm, một máy phát điện stdlib-of-máy phát điện.

ví dụ:

def metagen(): 
    def innergen(): 
     yield 1 
     yield 2 
     yield 3 

    for i in range(3): 
     r = innergen() 
     yield r 

     for _ in r: pass 
  • Hoặc sử dụng một phương pháp Hack bí mật đen tối mà tôi sẽ hiển thị trong một mo'(Tôi cần phải viết nó), nhưng đừng làm điều đó!

Như đã hứa, hack (đối với Python 3, lần này 'tròn):

from collections import UserList 
from functools import partial 


def objectitemcaller(key): 
    def inner(*args, **kwargs): 
     try: 
      return getattr(object, key)(*args, **kwargs) 
     except AttributeError: 
      return NotImplemented 
    return inner 


class Listable(UserList): 
    def __init__(self, iterator): 
     self.iterator = iterator 
     self.iterated = False 

    def __iter__(self): 
     return self 

    def __next__(self): 
     self.iterated = True 
     return next(self.iterator) 

    def _to_list_hack(self): 
     self.data = list(self) 
     del self.iterated 
     del self.iterator 
     self.__class__ = UserList 

for key in UserList.__dict__.keys() - Listable.__dict__.keys(): 
    if key not in ["__class__", "__dict__", "__module__", "__subclasshook__"]: 
     setattr(Listable, key, objectitemcaller(key)) 


def metagen(): 
    def innergen(): 
     yield 1 
     yield 2 
     yield 3 

    for i in range(3): 
     r = Listable(innergen()) 
     yield r 

     if not r.iterated: 
      r._to_list_hack() 

     else: 
      for item in r: pass 

for item in metagen(): 
    print(item) 
    print(list(item)) 
#>>> <Listable object at 0x7f46e4a4b850> 
#>>> [1, 2, 3] 
#>>> <Listable object at 0x7f46e4a4b950> 
#>>> [1, 2, 3] 
#>>> <Listable object at 0x7f46e4a4b990> 
#>>> [1, 2, 3] 

list(metagen()) 
#>>> [[1, 2, 3], [1, 2, 3], [1, 2, 3]] 

Đó là xấu như vậy tôi không muốn thậm chí giải thích nó.

Điều quan trọng là bạn có một trình bao bọc có thể phát hiện xem nó có được lặp lại hay không và nếu bạn không chạy _to_list_hack, tôi sẽ không thay đổi thuộc tính __class__.

Do bố cục xung đột, chúng tôi phải sử dụng lớp UserList và che đi tất cả các phương pháp của lớp, đó chỉ là một lớp vỏ khác.

Về cơ bản, vui lòng không sử dụng tính năng hack này. Bạn có thể thưởng thức nó như là hài hước, mặc dù.

0

Một cách khá thực tế là để nói "máy phát điện của máy phát điện" khi tạo ra có tạo ra máy phát điện hoặc danh sách hay không. Mặc dù điều này không thuận tiện khi có list kỳ diệu biết phải làm gì, nó vẫn có vẻ thoải mái hơn so với chức năng đặc biệt to_list.

def gengen(n, listmode=False): 
    for i in range(n): 
     def gen(): 
      for k in range(i+1): 
       yield k 
     yield list(gen()) if listmode else gen() 

Tùy thuộc vào thông số listmode, điều này có thể được sử dụng để tạo máy phát điện hoặc danh sách.

for gg in gengen(5, False): 
    print gg, list(gg) 
print list(gengen(5, True))