我想要一个可以接受(包括None)或不接受参数的方法。比如它在内置方法中的工作方式next,可以接受一个参数default,可以接受None作为参数default,也可能根本不接受,StopIterationError如果序列为空就调用它。根据这个答案,我正在尝试重载这样的StackOverflow方法:touch_first
from itertools import chain, repeat
class EnumerateUtils:
def touch_first(self, iterable):
# Raise StopIterationError if sequence is empty
iterable_iterator = iter(iterable)
first_element = next(iterable_iterator)
return (first_element, chain(repeat(first_element, 1), iterable_iterator))
class EnumerateUtilsOverloaded(EnumerateUtils):
def touch_first(self, iterable, default, *args, **kwargs):
# No raise errors
try:
return super().touch_first(iterable, *args, **kwargs)
except StopIteration:
return default
sequence = chain(range(0, 5), repeat(None, 1), range(6, 10))
empty_seq = []
def check_without_default(seq):
util = EnumerateUtilsOverloaded()
item = util.touch_first(seq)
if item is not None:
first_element, new_sequence = item
print(first_element)
print(list(new_sequence))
check_without_default(sequence) # -> I WANT: 0\n[0, 1, 2, 3, 4, None, 6, 7, 8, 9]
check_without_default(empty_seq) # -> I WANT: no print, but StopIterationError raised as in 'next' method without default
然而我只得到了TypeError "EnumerateUtilsOverloaded.touch_first() missing 1 required positional argument: 'default'",因为我没有为变量指定默认值default。但是,如果我这样做,代码将正常工作,但check_without_default(empty_seq)不会像该方法那样输出或引发StopIterationErrornext任何内容,我真的很喜欢这个。
如何获得所需的执行逻辑next?我无法区分缺席default和default=None。
最后,根据@andreymal的回答,我使用了以下代码(没有类):
from itertools import chain, repeat
_sentinel = object()
def touch_first(iterable, default=_sentinel, *args, **kwargs):
iterable_iterator = iter(iterable)
first_element = None
if default == _sentinel:
first_element = next(iterable_iterator)
else:
first_element = next(iterable_iterator, default)
return (first_element, chain(repeat(first_element, 1), iterable_iterator))
在这种情况下,经常使用的做法是在某个肯定不会从外部作为参数传递的地方创建一个对象,并将其作为该对象的默认值。
由于不可能创建另一个这样的对象来检查
объект is _sentinel将返回True(并且我们假设第三方代码不会进入模块的内部来提取这个特定的对象_sentinel) - 我们可以使用它作为对传递给函数的参数是否存在。值得记住的是,这种方法还不能很好地与类型注释配合使用,但如果您不使用注释,它也可以。
由于函数包含
*args,您可以使用另一种方法 - 删除参数default,然后它将转到列表的第一个元素args。哪种方法更好或更差取决于情况和函数所需的接口(例如,也许default应该有一个仅关键字参数?)。此处抛出错误是因为您
default在方法中声明时使用了可选参数而未指定默认值touch_first。可以设置一个默认值None,default然后在方法内部检查是否通过default(默认是否为None)。如果default不等于None,则表示它已传递给该方法。这是更正后的代码:
这是输出: