2014-12-02 1 views
3

Я ищу способ определить, было ли передано ключевое слово arg явно, без использования **kwargs.Обнаружение переопределения kwarg в Python

Вот пример:

def foo(first, second=None): 
    pass 

Если в этой функции, я считаю, что second содержит None, есть ли способ узнать, был ли что None от заданного по умолчанию, или был принят в явном виде? В принципе, у меня есть необязательный аргумент, который, возможно, может быть любым значением или типом. Поэтому мне либо нужно какое-то «уникальное» значение по умолчанию, так что пользователь никогда не намеренно передает это значение по умолчанию, или мне нужен способ определить, действительно ли аргумент передавался явно.

Я ожидал, что смогу открыть его, проверив стек, но я чувствую, что это слишком много.

Я также знаю, что я мог бы сделать это таким образом:

def foo(first, **kwargs): 
    if 'second' in kwargs: 
     # Overridden! 
     pass 

Но я бы предпочел не принимать **kwargs, как это делает моя функция подписи менее полезна и может скрыть ошибки.

+1

Недостаточно использовать '** kwargs', который не является ужасным, а затем использовать значение * sentinel * ... например,' sentinel = object() 'и проверить' if second is not sentinel' ... –

ответ

4

Вы всегда можете создать уникальный объект и использовать его в качестве значения по умолчанию:

_default = object() 

def foo(first, second=_default): 
    if second is not _default: 
     # Overridden! 
     pass 
+0

Спасибо, это идеально. – basepi

2

NPE's answer совершенно прав: использовать sentinel value, что не None. Любой старый объект singleton будет делать большую часть времени.

Существует один недостаток _default = object() хотя: _default не разделяет None «s удобного свойства быть логически равно False в условных. То есть None является «ложным», но _default «правдивый». Более формально, bool(None) == False еще bool(_default) == True.

Было бы здорово, если бы вы могли создать новые NoneType экземпляры, чтобы быть как None, но не совсем None. Но NoneType не может быть дополнительно инстанцирован. Однако вы можете создать аналогичный класс. Итак:

import sys 

_PY3 = sys.version_info[0] == 3 

class NullType(object): 

    """ 
    A 'null' type different from, but parallel to, None. Core function 
    is representing emptyness in a way that doesn't overload None. 
    This helps create designated identifiers with specific meanings 
    such as Passthrough, Prohibited, and Undefined. 

    Instantiate to create desired null singletons. While they are 
    singletons, depends on usage convention rather than strict 
    enforcement to maintain their singleton-ness. This is a problem 
    roughly 0% of the time. 
    """ 

    def __init__(self, name=None): 
     self.name = name 

    def __repr__(self): 
     if self.name is not None: 
      return self.name 
     else: 
      return 'NullType(id: {0})'.format(id(self)) 

    if _PY3: 
     def __bool__(self): 
      """I am always False.""" 
      return False 
    else: # PY2 
     def __nonzero__(self): 
      """I am always False.""" 
      return False 

Капля, что код в nulltype.py, а затем:

from nulltype import NullType 
_default = NullType('_default') 

def foo(first, second=_default): 
    if second is not _default: 
     # Overridden! 
     pass 

Но вы также можете сделать:

if second: 
     ... 

(в некоторых контекстах), потому что значение истинности second «s эквивалентно до None. Если вы использовали более простой фанат _default = object(), вы не могли этого сделать, потому что bool(object()) == True.

В настоящее время _default уникален, красиво печатает, когда его нужно распечатать, и всегда соответствует False. Это ваш собственный None.

+0

Мне это нравится!Я собираюсь отметить ответ NPE как реальный ответ, но это было очень полезно, спасибо! – basepi

+0

У него определенно есть красота простоты и встроенности. –

Смежные вопросы