Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 哨兵对象及其应用?_Python_Idioms_Sentinel - Fatal编程技术网

Python 哨兵对象及其应用?

Python 哨兵对象及其应用?,python,idioms,sentinel,Python,Idioms,Sentinel,我知道在python中,内置的object()返回一个sentinel对象。我很好奇它是什么,但主要是它的应用程序。object是python 3中所有其他类继承的基类。用一个普通的旧东西你能做的不多。但是,对象的标识可能很有用。例如,该函数采用一个sentinel参数,指示何时停止终止。我们可以为它提供一个object() 这将请求输入,直到用户键入stop、exit或done。我不确定什么时候带有哨兵的iter比发电机更有用,但我想它还是很有趣的 我不确定这是否回答了你的问题。清楚地说,这只

我知道在python中,内置的
object()
返回一个sentinel对象。我很好奇它是什么,但主要是它的应用程序。

object
是python 3中所有其他类继承的基类。用一个普通的旧东西你能做的不多。但是,对象的标识可能很有用。例如,该函数采用一个
sentinel
参数,指示何时停止终止。我们可以为它提供一个object()

这将请求输入,直到用户键入stop、exit或done。我不确定什么时候带有哨兵的iter比发电机更有用,但我想它还是很有趣的


我不确定这是否回答了你的问题。清楚地说,这只是
对象
的一个可能应用。从根本上讲,它在python语言中的存在与它是否可用作sentinel值无关(据我所知)。

这是python标准库中关于使用sentinel值的源代码示例

# A sentinel object to detect if a parameter is supplied or not.  Use
# a class to give it a better repr.
class _MISSING_TYPE:
    pass
MISSING = _MISSING_TYPE()
Python中的对象标识和类 您的语句“我知道在python中,内置对象()返回一个sentinel对象。”有点不正确,但并非完全错误,所以让我先说明一下,以确保我们在同一页上:

Python中的
object()
只是所有类的父类。在Python2中,这在一段时间内是明确的。在Python 2中,您必须编写:

class Foo(object):
    ...
获得所谓的“新样式对象”。您也可以在没有超类的情况下定义类,但这只是为了向后兼容,对于这个问题并不重要

现在在Python 3中,
对象
超类是隐式的。所以所有类都继承自该类。因此,以下两个类在Python 3中是相同的:

class Foo:
    pass

class Foo(object):
    pass
知道了这一点,我们可以稍微改写一下您最初的陈述:

。。。内置对象()返回一个sentinel对象

然后变成:

。。。内置对象()返回类“object”的对象实例

因此,在写作时:

my_sentinel = object()
只需在“内存中的某个地方”创建一个空对象实例。最后一部分很重要,因为默认情况下,内置的
id()
函数将使用
进行检查。。。是…
,取决于内存地址。例如:

>>> a = object()
>>> b = object()
>>> a is b
False
这为您提供了一种创建对象实例的方法,您可以使用它来检查代码中的某种逻辑,否则这些逻辑将非常困难甚至不可能这是“哨兵”对象的主要用途

示例用例:区分“无”和“无/未初始化/空/…” 有时值
None
是变量的有效值,您可能需要检测“空”或类似值与
None
之间的差异

假设您有一个类为一个昂贵的操作执行延迟加载,其中“None”是一个有效值。然后你可以这样写:

#: sentinel value for uninitialised values
UNLOADED = object()

class MyLoader:
    def __init__(self, remote_addr):
        self.value = UNLOADED
        self.remote_addr = remote_addr
    def get(self):
        if self.value is UNLOADED:
            self.value = expensive_operation(self.remote_addr)
        return self.value
SENTINEL_A = object()
SENTINEL_B = object()

def foobar(a = SENTINEL_A, b = SENTINEL_B):
    if a is SENTINEL_A:
        a = -12
    if b is SENTINEL_B:
        b = a * 2
    print(a+b)
SENTINEL_A = object()
SENTINEL_B = object()

def foobar(a = SENTINEL_A, b = SENTINEL_B):
    if b is SENTINEL_A:  # <- bug: using *b* instead of *a*
        a = -12
    if b is SENTINEL_B:
        b = a * 2
    print(a+b)
现在,
昂贵的\u操作
可以返回任何值。即使没有或任何其他“错误”值和“缓存”也能正常工作,不会出现意外错误。它还使代码非常可读,因为它将意图非常清楚地传达给代码块的读取器。您还可以为附加的“is_loaded”布尔值保存存储(尽管可以忽略)

使用布尔值的相同代码:

class MyLoader:
    def __init__(self, remote_addr):
        self.value = None
        self.remote_addr = remote_addr
        self.is_loaded = False  # <- need for an additional variable
    def get(self):
        if not self.is_loaded:
            self.value = expensive_operation(self.remote_addr)
            self.is_loaded = True  # <- source for a bug if this is forgotten
        return self.value
通过使用这样的哨兵,不可能通过混淆变量意外触发if分支。例如,假设您重构代码并在某个地方出错,将a和b混合如下:

#: sentinel value for uninitialised values
UNLOADED = object()

class MyLoader:
    def __init__(self, remote_addr):
        self.value = UNLOADED
        self.remote_addr = remote_addr
    def get(self):
        if self.value is UNLOADED:
            self.value = expensive_operation(self.remote_addr)
        return self.value
SENTINEL_A = object()
SENTINEL_B = object()

def foobar(a = SENTINEL_A, b = SENTINEL_B):
    if a is SENTINEL_A:
        a = -12
    if b is SENTINEL_B:
        b = a * 2
    print(a+b)
SENTINEL_A = object()
SENTINEL_B = object()

def foobar(a = SENTINEL_A, b = SENTINEL_B):
    if b is SENTINEL_A:  # <- bug: using *b* instead of *a*
        a = -12
    if b is SENTINEL_B:
        b = a * 2
    print(a+b)
SENTINEL_A=object()
SENTINEL_B=对象()
def foobar(a=哨兵a,b=哨兵b):

如果b是SENTINEL_A:#它会让事情变得更简单,例如,如果你接受用户输入,你可以使用.lower(),即使他们键入caps,它也会保存为所有小写字母。因此,它使条件语句更容易处理用户输入。我可以举一个例子吗?同样有趣的是:我看到它被用作参数的默认值,替代None作为参数的值,这些参数可能接收None作为其值,而不具有“此参数未由调用方设置”的通常含义。e、 谢谢你的例子。建议以大写形式编写模块级名称,这样sentinel将成为sentinel(并且可能带有下划线以使其不可导出)。子类化不仅对更好的报告有用,而且还允许您更好地使用类型提示编写类似于
def get(值:Union[int,_MISSING_type]=MISSING)的内容:…