Пользовательский заполнитель, такой как None в Python - PullRequest
7 голосов
/ 31 мая 2011

Я использую argspec в функции, которая принимает в качестве аргумента другую функцию или метод и возвращает кортеж, подобный этому:

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

Это означает, что первым аргументом переданной функции является arg1, и он имеет значение по умолчанию obj1 и т. Д.

Вот загвоздка : если у него нет значения по умолчанию, мне нужно значение заполнителя, чтобы обозначить это. Я не могу использовать None, потому что тогда я не могу различить нет значения по умолчанию и значение по умолчанию None . То же самое для False, 0, -1 и т. Д. Я мог бы сделать его кортежем с одним элементом, но тогда код для проверки его будет уродливым, и я не могу легко превратить его в диктовку. Так что я решил создать объект, подобный 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'>.

Есть ли причина не делать это так? Есть ли лучшее решение?

Ответы [ 3 ]

5 голосов
/ 31 мая 2011

Мой любимый страж - Ellipsis, и если я могу процитировать себя:

это там, это объект, это одиночка, и его имя означает "отсутствие"of ", и это не чрезмерное None (которое может быть помещено в очередь как часть обычного потока данных).YMMV.

4 голосов
/ 31 мая 2011

У меня была похожая ситуация некоторое время назад. Вот что я придумал.

# 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,), {})

Он также может выступать в качестве нулевого вызова и последовательности.

3 голосов
/ 31 мая 2011

Нет никаких причин не использовать такие дозорные объекты для таких целей. В качестве альтернативы объекту класса вы также можете создать одноэлементный экземпляр динамически создаваемого типа:

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