【发布时间】:2023-02-10 22:13:37
【问题描述】:
哪些类型的对象属于“可订阅”域?
【问题讨论】:
标签: python terminology
哪些类型的对象属于“可订阅”域?
【问题讨论】:
标签: python terminology
它基本上意味着该对象实现了 __getitem__() 方法。换句话说,它描述的对象是“容器”,意味着它们包含其他对象。这包括字符串、列表、元组和字典。
【讨论】:
hasattr(SomeClassWithoutGetItem, '__getitem__') 确定事物是否可订阅有多可靠?
[...] 索引语法称为下标, 因为它等同于使用实际下标的数学符号;例如a[1] 是数学家会写成的 Python一个₁.所以“可订阅”就是“能够被订阅”的意思。用 Python 术语来说,这意味着它必须实现 __getitem__(),因为 a[1] 只是 a.__getitem__(1) 的语法糖。
hasattr 的调用应该可以正常工作,但这不是 Pythonic 的做事方式; Python实践鼓励Duck Typing。意思是,如果你打算尝试使用下标从你的对象中获取一个项目,那就去做吧;如果您认为它可能因为对象不可订阅而无法工作,请将其包装在带有except TypeError 的try 块中。
super 好像是个例外。 super返回的对象可以有属性__getitem__,但是它是不可订阅的,因此括号切片不起作用。
在我的脑海中,以下是唯一可订阅的内置函数:
string: "foobar"[3] == "b"
tuple: (1,2,3,4)[3] == 4
list: [1,2,3,4][3] == 4
dict: {"a":1, "b":2, "c":3}["c"] == 3
但是 mipadi's answer 是正确的 - 任何实现 __getitem__ 的类都是可订阅的
【讨论】:
下标在计算中的含义是: “一个符号(名义上写为下标,但实际上通常不是)在程序中单独或与其他符号一起使用,以指定数组的元素之一。”
现在,在@user2194711 给出的简单示例中,我们可以看到附加元素不能成为列表的一部分,原因有两个:-
1)我们并没有真正调用append方法;因为它需要() 来调用它。
2)错误提示函数或方法不可订阅;意味着它们不像列表或序列那样可索引。
现在看这个:-
>>> var = "myString"
>>> def foo(): return 0
...
>>> var[3]
't'
>>> foo[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'function' object is not subscriptable
这意味着 function 中没有下标或说元素,就像它们按顺序出现一样;在 [] 的帮助下,我们无法像现在这样访问它们。
还;正如mipadi 在他的回答中所说;它基本上意味着该对象实现了 __getitem__() 方法。 (如果它是可订阅的)。
因此产生了错误:
arr.append["HI"]
TypeError: 'builtin_function_or_method' 对象不可订阅
【讨论】:
可编写脚本的对象是记录对其执行的操作的对象,它可以将它们存储为可以重放的“脚本”。
例如见:Application Scripting Framework
现在,如果 Alistair 不知道他问的是什么,真正的意思是“可订阅”对象(由其他人编辑),那么(正如 mipadi 也回答的那样)这是正确的:
可订阅对象是实现 __getitem__ 特殊方法的任何对象(想想列表、字典)。
【讨论】:
我有同样的问题。我在做
arr = []
arr.append["HI"]
所以使用 [ 导致了错误。应该是arr.append("HI")
【讨论】:
作为此处较早答案的必然结果,这通常表明您认为自己拥有列表(或字典或其他可订阅对象),而实际上您没有。
例如,假设您有一个函数应该返回列表;
def gimme_things():
if something_happens():
return ['all', 'the', 'things']
现在,当您调用该函数时,something_happens() 由于某种原因没有返回 True 值,会发生什么? if 失败了,所以你失败了; gimme_things 没有显式 return 任何东西——所以实际上,它会隐式 return None。然后这段代码:
things = gimme_things()
print("My first thing is {0}".format(things[0]))
将失败并显示“NoneType object is not subscriptable”,因为,好吧,things 是 None 所以你正在尝试做 None[0] 这没有意义,因为......错误消息说的是什么。
有两种方法可以修复代码中的这个错误——第一种是通过在尝试使用它之前检查 things 实际上有效来避免错误;
things = gimme_things()
if things:
print("My first thing is {0}".format(things[0]))
else:
print("No things") # or raise an error, or do nothing, or ...
或者等效地捕获 TypeError 异常;
things = gimme_things()
try:
print("My first thing is {0}".format(things[0]))
except TypeError:
print("No things") # or raise an error, or do nothing, or ...
另一种方法是重新设计gimme_things,以确保它始终返回一个列表。在这种情况下,这可能是更简单的设计,因为这意味着如果有很多地方有类似的错误,它们可以保持简单和惯用。
def gimme_things():
if something_happens():
return ['all', 'the', 'things']
else: # make sure we always return a list, no matter what!
logging.info("Something didn't happen; return empty list")
return []
当然,您在 else: 分支中放入的内容取决于您的用例。也许您应该在 something_happens() 失败时引发异常,以便更明显和明确地指出实际出错的地方?将异常添加到您自己的代码中是让您自己确切知道发生故障时发生了什么的重要方法!
(还要注意后一个修复程序如何仍然没有完全修复该错误——它阻止您尝试下标 None 但是当 things 是一个空列表时,things[0] 仍然是一个 IndexError。如果您有try你也可以做except (TypeError, IndexError)来捕获它。)
【讨论】:
gimme_things在它不能做它应该做的事情时引发异常。这对初学者来说很可怕,但实际上是一个很好的学习模式。大声失败比传回虚假信息或使返回值模棱两可更好(如果您在找不到任何项目时返回一个空列表,或者当一些不相关的失败时可能会出现这种情况;通常比为后一种情况提出例外)。
基本上,如果您在对上述对象进行类型转换之后修改或添加任何字段,而不是之前这样做,就会出现此错误。
【讨论】: