python 究竟如何将任意对象转换为列表?
How exactly python converts arbitrary object into list?
文档 says:
The constructor builds a list whose items are the same and in the same
order as iterable‘s items. iterable may be either a sequence, a
container that supports iteration, or an iterator object. If iterable
is already a list, a copy is made and returned, similar to
iterable[:]...
但是如果我的 class A
有一个对象 a
,它实现了 __iter__
、__len__
和 __getitem__
,这list(a)
使用接口来迭代我的对象,这背后的逻辑是什么?
我的快速试验让我感到困惑:
class A(object):
def __iter__(self):
print '__iter__ was called'
return iter([1,2,3])
def __len__(self):
print '__len__ was called'
return 3
def __getitem__(self, index):
print '__getitem(%i)__ was called' % index
return index+1
a = A()
list(a)
产出
__iter__ was called
__len__ was called
[1, 2, 3]
A.__iter__
是第一个调用的,好的。但是为什么 A.__len__
被调用了呢?然后为什么 A.__getitem__
没有被调用?
然后我__iter__
变成了发电机
这改变了魔术方法调用的顺序!
class B(object):
def __iter__(self):
print '__iter__ was called'
yield 1
yield 2
yield 3
def __len__(self):
print '__len__ was called'
return 3
def __getitem__(self, index):
print '__getitem(%i)__ was called' % index
return index+1
b = B()
list(b)
产出
__len__ was called
__iter__ was called
[1, 2, 3]
为什么现在先调用 B.__len__
?但是为什么没有调用B.__getitem__
,而转换是用B.__iter__
完成的?
最让我困惑的是为什么__len__
和__iter__
的调用顺序在A
和B
的情况下是不同的?
调用顺序没有改变。 __iter__
仍然首先被调用,但是当 __iter__
是生成器时,调用 __iter__
不会立即 运行 函数体。 print
仅在 next
被调用时发生。
__len__
被调用是一个实现细节。 Python 想要提示为列表分配多少 space,因此在您的对象上 it calls _PyObject_LengthHint
,如果对象支持它,则使用 len
。预计在对象上调用 len
通常会很快并且没有可见的副作用。
文档 says:
The constructor builds a list whose items are the same and in the same order as iterable‘s items. iterable may be either a sequence, a container that supports iteration, or an iterator object. If iterable is already a list, a copy is made and returned, similar to iterable[:]...
但是如果我的 class A
有一个对象 a
,它实现了 __iter__
、__len__
和 __getitem__
,这list(a)
使用接口来迭代我的对象,这背后的逻辑是什么?
我的快速试验让我感到困惑:
class A(object):
def __iter__(self):
print '__iter__ was called'
return iter([1,2,3])
def __len__(self):
print '__len__ was called'
return 3
def __getitem__(self, index):
print '__getitem(%i)__ was called' % index
return index+1
a = A()
list(a)
产出
__iter__ was called
__len__ was called
[1, 2, 3]
A.__iter__
是第一个调用的,好的。但是为什么 A.__len__
被调用了呢?然后为什么 A.__getitem__
没有被调用?
然后我__iter__
变成了发电机
这改变了魔术方法调用的顺序!
class B(object):
def __iter__(self):
print '__iter__ was called'
yield 1
yield 2
yield 3
def __len__(self):
print '__len__ was called'
return 3
def __getitem__(self, index):
print '__getitem(%i)__ was called' % index
return index+1
b = B()
list(b)
产出
__len__ was called
__iter__ was called
[1, 2, 3]
为什么现在先调用 B.__len__
?但是为什么没有调用B.__getitem__
,而转换是用B.__iter__
完成的?
最让我困惑的是为什么__len__
和__iter__
的调用顺序在A
和B
的情况下是不同的?
调用顺序没有改变。 __iter__
仍然首先被调用,但是当 __iter__
是生成器时,调用 __iter__
不会立即 运行 函数体。 print
仅在 next
被调用时发生。
__len__
被调用是一个实现细节。 Python 想要提示为列表分配多少 space,因此在您的对象上 it calls _PyObject_LengthHint
,如果对象支持它,则使用 len
。预计在对象上调用 len
通常会很快并且没有可见的副作用。