2011-05-31 15 views
7

estoy usando argspec en una función que toma otra función o método que el argumento, y devuelve una tupla de esta manera:marcador personalizado como en Pitón Ninguno

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

Esto significa que el primer argumento del pasado la función es arg1 y tiene un valor predeterminado de obj1, y así sucesivamente.

Aquí está el roce: si no tiene un valor predeterminado, necesito un valor de marcador de posición para indicar esto. No puedo usar None, porque entonces no puedo distinguir entre , ningún valor predeterminado y el valor predeterminado es None. Lo mismo para False, 0, -1, etc. Podría convertirlo en una tupla con un solo elemento, pero luego el código para verificarlo sería feo, y no puedo convertirlo fácilmente en un dict. Así que pensé en crear un objeto Ninguno-como que no es ninguno, y esto es lo que he llegado con:

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

class NoDefault(object): 
    __metaclass__ = MetaNoDefault 

ahora ("arg1", NoDefault) indica arg1 no tiene ningún valor por defecto, y no puedo hacer las cosas como if obj1 is NoDefault: etc. La metaclase lo hace imprimir como solo NoDefault en lugar de <class '__main__.NoDefault'>.

¿Hay alguna razón para no hacerlo así? ¿Hay una mejor solución?

+0

¿Hay alguna razón por la que no se puede tener una sola tupla de un elemento para no tener valores predeterminados? Algo como: '((" arg1 ",), (" arg2 ", obj2), ...)' donde "arg1" no tiene valor predeterminado. A continuación, puede hacer si 'len (the_tuple) == 1' etc. – Fenikso

+2

@FMc: para evitar errores provenientes de la modificación accidental de los argumentos predeterminados, es mejor nunca usar los valores predeterminados mutables. – lunaryorn

+0

@Fenikso He cubierto esta posibilidad en mi pregunta. En resumen, me parece poco elegante, a pesar de que es intuitivo. –

Respuesta

5

Mi centinela favorito es Ellipsis, y si se me permite quote a mí mismo:

que está ahí, que es un objeto, es un producto único, y su nombre significa "falta de", y no es el exceso Ninguno (que podría ponerse en cola como parte del flujo de datos normal). YMMV.

+1

Sin embargo, está desapareciendo en Python 3.: -o – Keith

+3

@Keith: cita, por favor. AFAIK en Python 3 incluso puede decir 'a = ...' (es decir, la sintaxis '...' se puede usar fuera de las divisiones), así que tengo la impresión de que no está desapareciendo. – tzot

+0

Parece que podría citarme a mí mismo [incluso antes] (http://mail.python.org/pipermail/python-list/2004-August/273139.html) :) – tzot

3

No hay ninguna razón para no utilizar tales objetos centinelas para tales fines. Como alternativa a un objeto de clase, también se puede crear una instancia singleton de un tipo creado de forma dinámica:

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

que tenían una situación similar hace algún tiempo. Esto es lo que se me ocurrió.

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

También puede actuar como secuencia y null invocable.

Cuestiones relacionadas