【问题标题】:Custom placeholder like None in python自定义占位符,如 python 中的 None
【发布时间】:2011-09-05 08:12:10
【问题描述】:

我在一个函数中使用argspec,它接受另一个函数或方法作为参数,并返回一个像这样的元组:

(("arg1", obj1), ("arg2", obj2), ...)

这意味着传递函数的第一个参数是 arg1,它的默认值是 obj1,依此类推。

问题来了:如果它没有默认值,我需要一个占位符值来表示这一点。我不能使用 None,因为那样我就无法区分 no default valuedefault value is None。同样适用于 False、0、-1 等。我可以将其设置为具有单个元素的元组,但是用于检查它的代码会很丑陋,而且我不能轻易地将它变成一个 dict。所以我想我会创建一个不是 None 的类似 None 的对象,这就是我想出的:

class MetaNoDefault(type):
    def __repr__(cls):
        return cls.__name__
    __str__ = __repr__

class NoDefault(object):
    __metaclass__ = MetaNoDefault

现在("arg1", NoDefault) 表示arg1 没有默认值,我可以执行if obj1 is NoDefault: 等操作。元类使其打印为NoDefault 而不是<class '__main__.NoDefault'>

有什么理由不这样做吗?有没有更好的解决方案?

【问题讨论】:

  • 有什么理由为什么不能只有一个元素的元组没有默认值?类似:(("arg1",), ("arg2", obj2), ...) 其中“arg1”没有默认值。如果len(the_tuple) == 1 等,您可以这样做。
  • @FMc:为了避免意外修改默认参数而导致错误,最好不要使用可变默认值。
  • @Fenikso 我已经在我的问题中提到了这种可能性。简而言之,我觉得它不优雅,尽管它直观的。

标签: python metaclass


【解决方案1】:

我最喜欢的哨兵是Ellipsis,如果我可以quote我自己:

它就在那里,它是一个对象,它是一个单例,它的名字的意思是“缺乏”,它不是过度使用的 None (可以作为正常数据流的一部分放入队列中)。 YMMV。

【讨论】:

  • 然而,它在 Python 3 中消失了。:-o
  • @Keith:请引用。 AFAIK 在 Python 3 中你甚至可以说 a = ...(即 ... 语法可以在切片之外使用),所以我觉得它并没有消失。
  • 看来我可以从even earlier 引用自己的话:)
  • @Keith: Ellipsis 仍然存在于 Python 3 中。只需阅读文档以获取证据。
  • 我本可以发誓我在某处读到过这本书……但我想不会。半夜累了就别在这里写了。
【解决方案2】:

前段时间我也遇到过类似的情况。这是我想出的。

# Works like None, but is also a no-op callable and empty iterable.
class NULLType(type):
    def __new__(cls, name, bases, dct):
        return type.__new__(cls, name, bases, dct)
    def __init__(cls, name, bases, dct):
        super(NULLType, cls).__init__(name, bases, dct)
    def __str__(self):
        return ""
    def __repr__(self):
        return "NULL"
    def __nonzero__(self):
        return False
    def __len__(self):
        return 0
    def __call__(self, *args, **kwargs):
        return None
    def __contains__(self, item):
        return False
    def __iter__(self):
        return self
    def next(*args):
        raise StopIteration
NULL = NULLType("NULL", (type,), {})

它也可以作为 null 可调用和序列。

【讨论】:

    【解决方案3】:

    没有任何理由不将此类哨兵对象用于此类目的。作为类对象的替代方案,您还可以创建动态创建类型的单例实例:

    NoDefault = type('NoDefault', (object,), {
        '__str__': lambda s: 'NoDefault', '__repr__': lambda s: 'NoDefault'})()
    

    【讨论】:

      猜你喜欢
      • 2013-12-12
      • 1970-01-01
      • 2021-01-12
      • 1970-01-01
      • 2019-11-29
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多