有没有办法在不对键施加约束的情况下禁用定义 __getitem__ 方法的 类 的迭代?
Is there a way to disable iteration for classes that define a __getitem__ method without putting constraints on the key?
作为我起点的class如下:
class Test:
def __getitem__(self, key):
global frame
frame = inspect.currentframe()
if key > 9:
raise KeyError
return key
我的想法是使用 frame.f_back
发现迭代器是为实例自动创建的,如下例所示:
for x in Test():
x
在 运行 这两个之后并查看 frame.f_back
,__getitem__
是否可以获得足够的信息来检测它是否被从任何地方调用并不明显 "iterator" 正在与之交互。最简单的解决方案是使容器从 1 而不是 0 开始以访问其内容,或者甚至可能在将密钥传递给函数之前强制将其包装在列表中,如下所示:
>>> class Test:
def __getitem__(self, key):
if not isinstance(key, list):
raise TypeError
if len(key) != 1:
raise ValueError
key = key.pop()
if not isinstance(key, int):
raise TypeError
if not 0 <= key < 10:
raise KeyError
return key
>>> for x in Test():
x
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
for x in Test():
File "<pyshell#39>", line 4, in __getitem__
raise TypeError
TypeError
>>> Test()[[5]]
5
>>>
有没有一种方法 __getitem__
可以知道它被自动用作迭代器并引发异常以防止这种使用?
相关: Why does defining __getitem__ on a class make it iterable in python?
如果目标是阻止对象成为可迭代对象,您可以在 __iter__
方法上强制出错:
class Test:
def __getitem__(self, key):
if key > 9:
raise KeyError
return key
def __iter__(self):
raise TypeError('Object is not iterable')
测试运行:
>>> t = Test()
>>> for x in t:
print(x)
Traceback (most recent call last):
File "<pyshell#126>", line 1, in <module>
for x in t:
File "<pyshell#122>", line 7, in __iter__
raise TypeError('Object is not iterable')
TypeError: Object is not iterable
但是 __getitem__
仍然有效:
>>> t[0]
0
>>> t[1]
1
>>> t[10]
Traceback (most recent call last):
File "<pyshell#129>", line 1, in <module>
t[10]
File "<pyshell#122>", line 4, in __getitem__
raise KeyError
KeyError
执行此操作的方法是同时实施 __getitem__
和 __iter__
方法。
当尝试访问单个元素时 __getitem__
将被触发,当尝试迭代时 __iter__
将被调用并引发异常。
class Test():
def __getitem__(self, k):
return k
def __iter__(self):
raise TypeError
作为我起点的class如下:
class Test:
def __getitem__(self, key):
global frame
frame = inspect.currentframe()
if key > 9:
raise KeyError
return key
我的想法是使用 frame.f_back
发现迭代器是为实例自动创建的,如下例所示:
for x in Test():
x
在 运行 这两个之后并查看 frame.f_back
,__getitem__
是否可以获得足够的信息来检测它是否被从任何地方调用并不明显 "iterator" 正在与之交互。最简单的解决方案是使容器从 1 而不是 0 开始以访问其内容,或者甚至可能在将密钥传递给函数之前强制将其包装在列表中,如下所示:
>>> class Test:
def __getitem__(self, key):
if not isinstance(key, list):
raise TypeError
if len(key) != 1:
raise ValueError
key = key.pop()
if not isinstance(key, int):
raise TypeError
if not 0 <= key < 10:
raise KeyError
return key
>>> for x in Test():
x
Traceback (most recent call last):
File "<pyshell#42>", line 1, in <module>
for x in Test():
File "<pyshell#39>", line 4, in __getitem__
raise TypeError
TypeError
>>> Test()[[5]]
5
>>>
有没有一种方法 __getitem__
可以知道它被自动用作迭代器并引发异常以防止这种使用?
相关: Why does defining __getitem__ on a class make it iterable in python?
如果目标是阻止对象成为可迭代对象,您可以在 __iter__
方法上强制出错:
class Test:
def __getitem__(self, key):
if key > 9:
raise KeyError
return key
def __iter__(self):
raise TypeError('Object is not iterable')
测试运行:
>>> t = Test()
>>> for x in t:
print(x)
Traceback (most recent call last):
File "<pyshell#126>", line 1, in <module>
for x in t:
File "<pyshell#122>", line 7, in __iter__
raise TypeError('Object is not iterable')
TypeError: Object is not iterable
但是 __getitem__
仍然有效:
>>> t[0]
0
>>> t[1]
1
>>> t[10]
Traceback (most recent call last):
File "<pyshell#129>", line 1, in <module>
t[10]
File "<pyshell#122>", line 4, in __getitem__
raise KeyError
KeyError
执行此操作的方法是同时实施 __getitem__
和 __iter__
方法。
当尝试访问单个元素时 __getitem__
将被触发,当尝试迭代时 __iter__
将被调用并引发异常。
class Test():
def __getitem__(self, k):
return k
def __iter__(self):
raise TypeError