python如何将任意对象转换为列表?

Rus*_*sky 4 python casting duck-typing list object

文件:

构造函数构建一个列表,其项目与iterable的项目相同且顺序相同.iterable可以是序列,支持迭代的容器,也可以是迭代器对象.如果iterable已经是一个列表,则会生成并返回一个副本,类似于iterable [:] ...

但是如果我有一个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)
Run Code Online (Sandbox Code Playgroud)

输出

__iter__ was called
__len__ was called
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

输出

__len__ was called
__iter__ was called
[1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

为什么B.__len__现在先叫?但为什么然后B.__getitem__没有被调用,转换完成了B.__iter__

什么最让我困惑的是呼叫的原因的顺序__len__,并__iter__在案件不同的是AB

use*_*ica 5

呼叫顺序没有改变.__iter__仍然首先被调用,但是__iter____iter__生成器时调用不会立即运行函数体.该print只发生一次next被调用.

__len__被调用是一个实现细节.Python需要提示为列表分配多少空间,因此它会调用_PyObject_LengthHint您的对象,len如果对象支持它,则使用该对象.预期呼叫len对象通常会很快并且没有可见的副作用.