简体   繁体   中英

Best way to succinctly evaluate default parameters in Python?

Relatively new to Python, I find myself having to evaluate a lot of arguments in functions/static methods and I was thinking if there is a user-friendly way to do this, so I ended up writing a function like so:

from typing import Any, Optional, Union

# Standard evaluator for default values
def eval_default(x: Any, default: Any, type: Optional[Any] = None) -> Any:
    """Helper function to set default value if None and basic type checking

    Args:
        x: the value to be evaluated
        default: the value to return if x is None
        type: the expected type of x, one of bool, int, float, str

    Raises:
        TypeError: for bool, int, float, str if x is not None and not of type

    Returns:
        x: either 'as is' if not None, or default if None, unless exception is raised.
    """
    # Infer type from default
    type = type(default) if type is None else type

    # Return default value if x is None, else check type and/or return x
    if x is None:
        return default
    elif not isinstance(x, type):
        if type == bool:
            raise TypeError("Variable can be either True or False.")
        elif type == int:
            raise TypeError("Variable must be an integer.")
        elif type == float:
            raise TypeError("Variable must be a float.")
        elif type == str:
            raise TypeError("Variable must be a string.")
    else:
        return x

Then in my main code I can do something like:


def some_method(self, some_variable:Optional[bool] = None) -> bool:
    """Some description
    """

    try:
        some_variable = eval_default(some_variable, False, bool)
    except TypeError:
        print("some_variable must be True or False.")

    return some_variable

Is there a simpler, more concise or more elegant standard practice to handle such a situation?

Many thanks in advance.

Your eval_default doesn't do anything to narrow the type from Optional[bool] to bool :

def some_method(self, some_variable:Optional[bool] = None) -> bool:
    try:
        some_variable = eval_default(some_variable, False, bool)
    except TypeError:
        print("some_variable must be True or False.")

    reveal_type(some_variable)  # note: Revealed type is "Union[builtins.bool, None]"

It potentially could with careful use of generics, but you'd need to assign the return value to a different name, which only makes it harder to use.

My usual pattern for de- Optional -ing default- None args is:

def some_method(self, some_variable:Optional[bool] = None) -> bool:
    some_variable = some_variable or False
    reveal_type(some_variable)  # note: Revealed type is "builtins.bool"

Of course for a bool you could just do:

def some_method(self, some_variable: bool = False) -> bool:
    reveal_type(some_variable)  # note: Revealed type is "builtins.bool"

which avoids the whole problem! The optional_arg or default trick is really only useful for cases where you need to construct a new object per function call (eg you want to initialize the default to a new empty list).

It looks to me like your eval_default function is just adding unnecessary complexity. If type checking is required, I'd just put it in the function, and declare the default as the actual default:

def some_method(self, some_variable:Optional[bool] = False) -> bool:
    """Some description
    """

    if not isinstance(some_variable, bool):
        print(f"some_variable must be True of False")

    return some_variable

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM