我有一个关于python中iterables行为的具体问题。我的iterable是pytorch中的自定义数据集类:
import torch
from torch.utils.data import Dataset
class datasetTest(Dataset):
def __init__(self, X):
self.X = X
def __len__(self):
return len(self.X)
def __getitem__(self, x):
print('***********')
print('getitem x = ', x)
print('###########')
y = self.X[x]
print('getitem y = ', y)
return y
当我初始化datasetest类的一个特定实例时,就会出现这种奇怪的行为。根据作为参数X传递的数据结构,调用list(datasetTestInstance)时,它的行为会有所不同。特别是,当经过张量作为参数是没有问题的,但是当作为参数传递dict时,它会抛出一个KeyError。原因是list(iterable)不仅调用i=0,…,len(iterable)-1,还调用i=0,…,len(iterable)。也就是说,它将迭代直到(包含)索引等于iterable的长度。显然,这个索引在任何python数据结构中都没有定义,因为最后一个元素总是索引len(datastructure)-1,而不是len(datastructure)。如果X是张量或者一个列表,不会出现错误,即使我认为应该是一个错误。即使对于索引为len(datasetTestinstance)的(不存在的)元素,它仍然会调用getitem,但它不会计算y=self.X[len(datasetTestinstance]。有人知道pytorch是否在内部优雅地处理了这个问题吗?你知道吗
当将dict作为数据传递时,它将在最后一次迭代中抛出一个错误,即x=len(datasetTestInstance)。我想这实际上是预期的行为。但为什么这种情况只发生在一个dict上,而不发生在一个list或list上呢火炬张量?你知道吗
if __name__ == "__main__":
a = datasetTest(torch.randn(5,2))
print(len(a))
print('++++++++++++')
for i in range(len(a)):
print(i)
print(a[i])
print('++++++++++++')
print(list(a))
print('++++++++++++')
b = datasetTest({0: 12, 1:35, 2:99, 3:27, 4:33})
print(len(b))
print('++++++++++++')
for i in range(len(b)):
print(i)
print(b[i])
print('++++++++++++')
print(list(b))
如果您想更好地理解我所观察到的内容,可以尝试一下这段代码。你知道吗
我的问题是:
1.)为什么list(iterable)迭代到(包括)len(iterable)?for循环不会这样做。你知道吗
2.)如果是张量或者一个作为数据X传递的列表:为什么它在调用索引len(datasetTestInstance)的getitem方法时不抛出一个错误,因为它没有在tensor/list中定义为索引,所以实际应该超出范围?或者,换句话说,当达到索引len(datasetistinstance)然后进入getitem方法时,到底发生了什么?它显然不再调用“y=self.X[X]”(否则会有索引器),但它确实进入了getitem方法,我可以看到它从getitem方法中打印索引X。那么这种方法会发生什么呢?为什么它的行为会因是否有torch.tensor/列表还是口述?你知道吗
一堆有用的链接:
关键的一点是list构造函数使用(iterable)参数的\uu len\ueem>((如果提供)来计算新的容器长度),但随后对其进行迭代(通过迭代器协议)。你知道吗
您的示例是以这种方式工作的(迭代了所有键,但未能找到与字典长度相等的键),因为发生了一个可怕的巧合(请记住,dict支持迭代器协议,并且这种情况发生在它的键(这是一个序列)上):
改变上述两个项目符号所表示的任何条件,都会使实际错误更具说服力。你知道吗
两个对象(dict和list(属于tensors))都支持迭代器协议。为了使事情正常工作,您应该将它包装在数据集类中,并稍微调整映射类型(使用值而不是键)。
代码(key\u func相关部分)有点复杂,但只是易于配置(如果您想更改某些内容-出于演示目的)。你知道吗
代码00.py:
输出:
您可能还需要检查[PyTorch]: SOURCE CODE FOR TORCH.UTILS.DATA.DATASET(IterableDataset)。你知道吗
这并不是pytorch特有的问题,而是一个一般的python问题。你知道吗
您正在使用list(iterable)构建一个列表,其中iterable类是实现sequence semantics的类。你知道吗
在这里看一下^{} 对于序列类型的预期行为(大多数相关部分用粗体表示)
这里的问题是,对于序列类型,python期望在使用无效索引调用
__getitem__
时使用IndexError
。似乎list
构造函数依赖于此行为。在您的示例中,当X
是dict时,尝试访问无效键会导致__getitem__
引发KeyError
,而这不是预期的,因此不会被捕获并导致列表的构造失败。你知道吗根据这些信息,你可以做如下的事情
我不建议在实践中这样做,因为它依赖于只包含整数键的字典
X
、0
、1
、len(X)-1
,这意味着在大多数情况下,它的行为就像一个列表,所以您最好只使用一个列表。你知道吗相关问题 更多 >
编程相关推荐