development

len (generator ())하는 방법

big-blog 2020. 7. 6. 07:08
반응형

len (generator ())하는 방법


파이썬 생성기 는 매우 유용합니다. 리스트를 리턴하는 함수보다 장점이 있습니다. 그러나 당신은 할 수 len(list_returning_function())있습니다. 방법이 len(generator_function())있습니까?

업데이트 :
물론 len(list(generator_function()))작동합니다 .....
내가 생성하는 새 생성기 내부에서 생성 한 생성기를 사용하려고합니다. 새로운 발전기의 계산의 일부로 이전 발전기의 길이를 알아야합니다. 그러나 나는 둘 다 생성기와 동일한 속성으로 함께 유지하고 싶습니다. 특히 전체 목록이 너무수 있으므로 메모리에 전체 목록을 유지하지 마십시오 .

업데이트 2 :
발전기 첫 번째 단계에서도 목표 길이를 알고 있다고 가정하십시오 . 또한 len()구문 을 유지할 이유가 없습니다 . 예-파이썬의 함수가 객체 인 경우 새 생성기에 액세스 할 수있는이 객체의 변수에 길이를 할당 할 수 없습니까?


생성기는 길이가 없으며 결국 수집되지 않습니다.

제너레이터는 내부 상태 (및 고급 구문)를 가진 함수입니다 . 반복적으로 값을 호출하여 일련의 값을 얻을 수 있으므로 루프에서 사용할 수 있습니다. 그러나 어떤 요소도 포함하지 않으므로 생성기의 길이를 묻는 것은 함수의 길이를 묻는 것과 같습니다.

파이썬의 함수가 객체 인 경우 새 생성기에 액세스 할 수있는이 객체의 변수에 길이를 할당 할 수 없습니까?

함수는 객체이지만 새로운 속성을 할당 할 수 없습니다. 그 이유는 아마도 이러한 기본 객체를 가능한 한 효율적으로 유지하기 위해서 일 것입니다.

그러나 단순히 (generator, length)함수에서 쌍을 반환 하거나 생성기를 다음과 같은 간단한 객체로 래핑 할 수 있습니다 .

class GeneratorLen(object):
    def __init__(self, gen, length):
        self.gen = gen
        self.length = length

    def __len__(self): 
        return self.length

    def __iter__(self):
        return self.gen

g = some_generator()
h = GeneratorLen(g, 1)
print len(h), list(h)

list다른 대답에서 제안 된 변환 은 나중에 생성기 요소를 처리하려고하지만 결함이있는 경우 가장 좋은 방법입니다 .O (n) 메모리를 사용합니다. 다음과 같이 많은 메모리를 사용하지 않고 생성기의 요소를 계산할 수 있습니다.

sum(1 for x in generator)

물론 이것은 len(list(generator))일반적인 파이썬 구현 보다 속도가 느릴 수 있으며 생성기가 메모리 복잡성을 중요하게 만들기에 충분히 길면 작업에 상당한 시간이 걸릴 수 있습니다. 아직도, 나는 개인적 으로이 솔루션을 선호하고 싶습니다. 필요하지 않은 추가 요소는 제공하지 않습니다 (예 : 모든 요소 목록).

또한 delnan의 조언을 들어보십시오. 생성기의 출력을 버릴 경우 요소를 실행하지 않고 또는 다른 방식으로 계산하여 요소 수를 계산하는 방법이있을 가능성이 큽니다.


발전기가 있다고 가정 해보십시오.

def gen():
    for i in range(10):
        yield i

알려진 길이와 함께 생성기를 객체로 감쌀 수 있습니다.

import itertools
class LenGen(object):
    def __init__(self,gen,length):
        self.gen=gen
        self.length=length
    def __call__(self):
        return itertools.islice(self.gen(),self.length)
    def __len__(self):
        return self.length

lgen=LenGen(gen,10)

LenGen호출하면 반복자를 반환하므로의 인스턴스 는 생성기 자체입니다.

이제 lgen대신에 생성기를 사용 gen하고 액세스 len(lgen)할 수도 있습니다.

def new_gen():
    for i in lgen():
        yield float(i)/len(lgen)

for i in new_gen():
    print(i)

사용할 수 있습니다 len(list(generator_function()). 그러나 이것은 생성기를 소비하지만 이것이 생성되는 요소 수를 알 수있는 유일한 방법입니다. 따라서 항목을 사용하려는 경우 목록을 어딘가에 저장할 수 있습니다.

a = list(generator_function())
print(len(a))
print(a[0])

You can len(list(generator)) but you could probably make something more efficient if you really intend to discard the results.


You can use send as a hack:

def counter():
    length = 10
    i = 0
    while i < length:
        val = (yield i)
        if val == 'length':
            yield length
        i += 1

it = counter()
print(it.next())
#0
print(it.next())
#1
print(it.send('length'))
#10
print(it.next())
#2
print(it.next())
#3

You can combine the benefits of generators with the certainty of len(), by creating your own iterable object:

class MyIterable(object):
    def __init__(self, n):
        self.n = n

    def __len__(self):
        return self.n

    def __iter__(self):
        self._gen = self._generator()
        return self

    def _generator(self):
        # Put your generator code here
        i = 0
        while i < self.n:
            yield i
            i += 1

    def next(self):
        return next(self._gen)

mi = MyIterable(100)
print len(mi)
for i in mi:
    print i,

This is basically a simple implementation of xrange, which returns an object you can take the len of, but doesn't create an explicit list.


You can use reduce.

For Python 3:

>>> import functools
>>> def gen():
...     yield 1
...     yield 2
...     yield 3
...
>>> functools.reduce(lambda x,y: x + 1, gen(), 0)

In Python 2, reduce is in the global namespace so the import is unnecessary.

참고URL : https://stackoverflow.com/questions/7460836/how-to-lengenerator

반응형