개발/Python

[파이썬] len(generator()) 방법

MinorMan 2022. 10. 12. 07:18
반응형

<질문>

Python generators 매우 유용합니다. 목록을 반환하는 함수보다 장점이 있습니다. 그러나 당신은 할 수 있습니다len(list_returning_function()). 방법이 있나요len(generator_function())?

업데이트:
물론len(list(generator_function())) 작동 할 것이다.....
생성 중인 새 생성기 내부에서 생성한 생성기를 사용하려고 합니다. 새 생성기에서 계산의 일부로 이전 생성기의 길이를 알아야 합니다. 그러나 나는 두 가지를 모두 생성기와 동일한 속성으로 유지하고 싶습니다. 특히 전체 목록을 메모리에 유지하지 마십시오.매우 긴.

업데이트 2:
발전기를 가정알고 있다 첫 번째 단계부터 목표 길이입니다. 또한 유지해야 할 이유가 없습니다.len() 통사론. 예 - Python의 함수가 객체인 경우 새 생성기가 액세스할 수 있는 이 객체의 변수에 길이를 할당할 수 없습니까?


<답변1>

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

sum(1 for x in generator)

물론 이것은len(list(generator)) 일반적인 파이썬 구현에서, 그리고 생성기가 메모리 복잡성이 중요할 만큼 충분히 길다면, 작업은 꽤 오랜 시간이 걸릴 것입니다. 그래도 개인적으로 이 솔루션을 선호하는 이유는 내가 얻고자 하는 것을 설명하고 필요하지 않은 추가 항목(예: 모든 요소 목록)을 제공하지 않기 때문입니다.

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


<답변2>

Generator는 길이가 없으며 결국 컬렉션이 아닙니다.

발전기는내부 상태가 있는 기능 (그리고 멋진 구문). 반복적으로 호출하여 값 시퀀스를 얻을 수 있으므로 루프에서 사용할 수 있습니다. 그러나 요소가 포함되어 있지 않으므로 생성기의 길이를 묻는 것은 함수의 길이를 묻는 것과 같습니다.

파이썬의 함수가 객체라면 길이를 할당할 수 없습니까? 새 생성기에 액세스할 수 있는 이 개체의 변수는 무엇입니까?

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

그러나 간단히 반환할 수 있습니다.(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)

<답변3>

생성기가 있다고 가정합니다.

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)

<답변4>

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

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

<답변5>

당신은 할 수 있습니다len(list(generator)) 하지만 정말로 결과를 버리려고 한다면 더 효율적인 것을 만들 수 있을 것입니다.


<답변6>

당신이 사용할 수있는reduce.

파이썬 3의 경우:

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

파이썬 2에서는reduce 전역 네임스페이스에 있으므로 가져오기가 필요하지 않습니다.


<답변7>

당신이 사용할 수있는send 해킹으로:

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

<답변8>

발전기의 이점과 다음의 확실성을 결합할 수 있습니다.len(), 고유한 반복 가능한 객체를 생성하여:

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,

이것은 기본적으로 간단한 구현입니다.xrange, len을 취할 수 있는 객체를 반환하지만 명시적 목록을 생성하지는 않습니다.

반응형