최근에 HTTP Range 필드를 사용하여 동시에 많은 블록을 다운로드하는 다운로드 프로그램을 작성 중입니다.func (* iterable)을 실행할 때 CPython이 len (iterable)을 호출하는 이유는 무엇입니까?
header = {'Range': 'bytes={}-{}'.format(*the_range)}
그리고 len(the_range)
얼마나 많은입니다 :
class ClosedRange:
def __init__(self, begin, end):
self.begin = begin
self.end = end
def __iter__(self):
yield self.begin
yield self.end
def __str__(self):
return '[{0.begin}, {0.end}]'.format(self)
def __len__(self):
return self.end - self.begin + 1
__iter__
마법 방법은 튜플 풀기를 지원하는 것입니다 : 나는 범위를 나타내는 파이썬 클래스를 작성 (HTTP 헤더의 범위는 폐쇄 구간입니다) 해당 범위의 바이트.
이제는 'bytes={}-{}'.format(*the_range)
이 MemoryError
인 경우가 종종 있습니다. 일부 디버깅 후 나는 CPython 인터프리터가 func(*iterable)
을 실행할 때 len(iterable)
을 호출하려고 시도하고 길이에 따라 메모리를 할당 할 수 있음을 발견했습니다. 내 컴퓨터에서 len(the_range)
이 1GB보다 크면 MemoryError
이 표시됩니다.
이 간단 하나입니다
class C:
def __iter__(self):
yield 5
def __len__(self):
print('__len__ called')
return 1024**3
def f(*args):
return args
>>> c = C()
>>> f(*c)
__len__ called
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
>>> # BTW, `list(the_range)` have the same problem.
>>> list(c)
__len__ called
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
MemoryError
그래서 제 질문은 다음과 같습니다
왜
len(iterable)
전화 CPython에? this question에서 iterator가 반복 될 때까지 iterator의 길이를 알 수 없습니다. 이것이 최적화입니까?__len__
메서드는 객체의 '가짜'길이 (즉, 메모리의 실제 요소 수가 아님)를 반환합니까?
https://www.python.org/dev/peps/pep-0424/. 어쨌든이 작업을하지 않는 것이 좋습니다 (범위의 요소를 산출하지 못하는'__iter__ '을 가짐). – Ryan
반복자가 두 개의 항목을 생성하면 시퀀스의 길이는 2입니다. – jasonharper
@ juanpa.arrivillaga @Ryan 알아요. 'list (it)'또는'f (* it)'는 모두 시퀀스를 생성하고'operator.length_hint (it) '를 호출하여 공간을 미리 할당합니다. 그리고'operator.length_hint'는'it'은'__len__' 메쏘드를 가지고 있으므로'len (it)'을 반환합니다 - 그래서 너무 큰 할당 순서. 그게 맞습니까? – CSM