dict
有一个方便的get
版本:
get(key[, default])
如果key在字典中,则返回key的值,否则返回default。 如果 默认情况下没有给出,默认为None,所以这个方法永远不会 提出
KeyError
。
大胆强调我的,因为我看了,找不到列表的等效版本。所以我实现了自己的:
In [148]: class myList(list):
...: def pop(self, idx=-1, default=None):
...: try:
...: return super().pop(idx)
...: except IndexError:
...: return default
这可以按预期工作:
In [149]: l = myList([1, 2, 3, 4, 5])
In [150]: l.pop()
Out[150]: 5
In [151]: l.pop(12345, 'default')
Out[151]: 'default'
由于这可行,因此也可以扩展到集合。无论如何,我有几个问题:
是否有一个更容易/内置/第三方等同于我所做的并不需要我延长list
课程?
如果没有,有什么特别原因吗?我相信这将是一个有用的行为。
我能想到的一些特殊用例是在一个你不知道的地方,在一个你不想要的地方或者不想知道的地方打电话pop
捕获错误,例如列表comp。
This question探讨了相同的主题,但答案并不符合我的要求,正如我上面所解释的那样。
答案 0 :(得分:3)
仅为字典实现的一个原因是,在最坏的情况下,检查if key in some_dict
并不总是O(1)
操作可能是O(n)
。但即使查找是O(1)
,它实际上也是一项昂贵的操作,因为你需要对密钥进行散列,然后如果有匹配则需要将密钥与存储密钥进行比较以获得相等性。这使LBYL字典非常昂贵。
另一方面,对于列表,检查索引是否在边界内是一个相当便宜的操作。我的意思是你可以用一个简单的方法检查它是否在界限范围内:
valid_index = -len(some_list) <= index < len(some_list)
但这仅适用于LBYL方法。总是可以使用EAFP并捕获异常。
这应该对列表和dicts施加相同的开销。那么为什么dict
采用get
方法来避免异常处理呢?原因其实很简单:dict
是几乎所有东西的基本构建块。大多数类和所有模块基本上只是字典,很多用户代码实际上使用字典。有一个方法可以在没有异常处理开销的情况下做到保证返回,这是(现在仍然)是值得的。
对于列表它也可能有用(我在这一点上不太确定)但我认为在大多数情况下它会抛出IndexError
它意外发生,而不是故意的。因此,如果返回None
s,它会隐藏真正的“错误”。
这只是我的理由。我可能是Python开发人员对当前行为有完全不同的原因。
是否有一个更容易/内置/第三方等同于我所做的,不需要我扩展列表类?
此外,我不知道这些操作的标准库或第三方模块,列表或集的默认值。有些库实现了一个“稀疏列表”(一个填充了默认值的列表),但我看过的那些没有处理“空列表”的情况,他们使用一个默认值作为完整列表
但是,如果您不想自己进行“异常处理”,可能会有一些选项可能会很有趣:
来自itertools
documentation page的iter_except
食谱,当发生指定的异常时停止调用函数:
def iter_except(func, exception, first=None):
# Copied verbatim from the above mentioned documentation page
try:
if first is not None:
yield first()
while True:
yield func()
except exception:
pass
>>> l = [1,2,3,4]
>>> list(iter_except(l.pop, IndexError))
[4, 3, 2, 1]
import contextlib
def pop_with_default(lst, ind=-1, default=None):
with contextlib.suppress(IndexError):
return lst.pop(ind)
return default
>>> pop_with_default([1,2,3], 5, 'abc')
'abc'
这里处理一般问题的另一种方法是创建一个调用另一个函数的函数,如果指定的异常将返回一个默认值,否则调用函数的结果:
def call_with_default(func, default=None, *exceptions):
def inner(*args, **kwargs):
try:
res = func(*args, **kwargs)
except exceptions:
res = default
return res
return inner
>>> a = [1,2,3,4]
>>> a_pop_with_default = call_with_default(a.pop, 'abc', IndexError)
>>> [a_pop_with_default(2) for _ in range(10)]
[3, 4, 'abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc', 'abc']
答案 1 :(得分:1)
为什么你不能使用像这样简单的东西?
client.exec_command("/usr/bin/echo q | /usr/bin/htop | aha --black --line-fix >> htop.html")
修改强>
好评。你对这样的事情有什么看法?
my_list.pop(n) if n < len(my_list) else "default"
该功能与OP的类继承方法相同。然而,为了便于阅读和将来的维护,我通常更喜欢简单的功能而不是创建平凡的类。