xticks barplot python function optional-parameters

python - barplot - pandas plot



Python: cómo verificar si se establece un parámetro de función opcional (7)

¿Hay alguna manera fácil en Python para verificar si el valor de un parámetro opcional proviene de su valor predeterminado, o porque el usuario lo ha establecido explícitamente en la llamada a la función?


A veces uso una cadena universalmente única (como un UUID).

import uuid DEFAULT = uuid.uuid4() def foo(arg=DEFAULT): if arg is DEFAULT: # it was not passed in else: # it was passed in

De esta forma, ningún usuario podría adivinar el valor predeterminado si lo intentaran, así que puedo estar muy seguro de que cuando vea ese valor para arg , no se transfirió.


El siguiente decorador de funciones, explicit_checker , crea un conjunto de nombres de parámetros de todos los parámetros explícitamente. Agrega el resultado como un parámetro adicional ( explicit_params ) a la función. Simplemente haz ''a'' in explicit_params para verificar si el parámetro a está dado explícitamente.

def explicit_checker(f): varnames = f.func_code.co_varnames def wrapper(*a, **kw): kw[''explicit_params''] = set(list(varnames[:len(a)]) + kw.keys()) return f(*a, **kw) return wrapper @explicit_checker def my_function(a, b=0, c=1, explicit_params=None): print a, b, c, explicit_params if ''b'' in explicit_params: pass # Do whatever you want my_function(1) my_function(1, 0) my_function(1, c=1)


Estoy de acuerdo con el comentario de Volatility. Pero puedes verificarlo de la siguiente manera:

def function(arg1,...,**optional): if ''optional_arg'' in optional: # user has set ''optional_arg'' else: # user has not set ''optional_arg'' optional[''optional_arg''] = optional_arg_default_value # set default


He visto este patrón algunas veces (por ejemplo, library unittest , py-flags , jinja ):

class Default: def __repr__( self ): return "DEFAULT" DEFAULT = Default()

... o el equivalente de un trazador de líneas ...:

DEFAULT = type( ''Default'', (), { ''__repr__'': lambda x: ''DEFAULT'' } )()

A diferencia de DEFAULT = object() , esto ayuda a verificar el tipo y proporciona información cuando se producen errores. Con frecuencia, la representación de cadena ( "DEFAULT" ) o el nombre de clase ( "Default" ) se utilizan en los mensajes de error.


Puedes verificarlo desde foo.__defaults__ y foo.__kwdefaults__

ver un ejemplo simple abajo

def foo(a, b, c=123, d=456, *, e=789, f=100): print(foo.__defaults__) # (123, 456) print(foo.__kwdefaults__) # {''e'': 789, ''f'': 100} print(a, b, c, d, e, f) #and these variables are also accessible out of function body print(foo.__defaults__) # (123, 456) print(foo.__kwdefaults__) # {''e'': 789, ''f'': 100} foo.__kwdefaults__[''e''] = 100500 foo(1, 2) #(123, 456) #{''f'': 100, ''e'': 100500} #1 2 123 456 100500 100

luego usando operator = y puedes compararlos

y para algunos casos el código de abajo es suficiente

Por ejemplo, debe evitar cambiar el valor predeterminado, entonces puede verificar la igualdad y luego hacer frente, si es así.

def update_and_show(data=Example): if data is Example: data = copy.deepcopy(data) update_inplace(data) #some operation print(data)


Realmente no. La forma estándar es usar un valor predeterminado que no se espera que el usuario pase, por ejemplo, una instancia de object :

DEFAULT = object() def foo(param=DEFAULT): if param is DEFAULT: ...

Por lo general, puede usar None como valor predeterminado, si no tiene sentido como valor que el usuario desea aprobar.

La alternativa es usar kwargs :

def foo(**kwargs): if ''param'' in kwargs: param = kwargs[''param''] else: ...

Sin embargo, esto es demasiado detallado y hace que su función sea más difícil de usar ya que su documentación no incluirá automáticamente el parámetro param .


Un pequeño acercamiento anormal sería:

class CheckerFunction(object): def __init__(self, function, **defaults): self.function = function self.defaults = defaults def __call__(self, **kwargs): for key in self.defaults: if(key in kwargs): if(kwargs[key] == self.defaults[key]): print ''passed default'' else: print ''passed different'' else: print ''not passed'' kwargs[key] = self.defaults[key] return self.function(**kwargs) def f(a): print a check_f = CheckerFunction(f, a=''z'') check_f(a=''z'') check_f(a=''b'') check_f()

Qué salidas:

passed default z passed different b not passed z

Ahora bien, como mencioné, es bastante extraño, pero cumple su función. Sin embargo, esto es bastante ilegible y de forma similar a la suggestion no se documentará automáticamente.