类型转换(同一类型的多个参数)

Type casting (multiple parameters of the same type)

我有以下方法声明:

def method(alpha, size=10, logged_in=False, interactions=False):
    
    if not isinstance(logged_in, bool):
        logged_in = str(logged_in).lower() in ['true']
    
    if not isinstance(interactions, bool):
        interactions = str(interactions).lower() in ['true']

if 语句是必需的,因为例如,如果我将 interaction="False" 作为参数传递,interactions 将被错误地设置为 True(因此,我传递一个字符串)。虽然上面的技巧有效,但我想知道是否有更优雅的方法来实现它(请注意,除了 logged_ininteractions 之外,我还有很多布尔参数,而且我还有一些 intfloat 参数。这里如何使用装饰器?可以将一个装饰器用于所有 bool 参数吗?我如何制作一个通用的装饰器(即支持 boolfloat, int, string)? 我发现 问题的答案可能有用,但仍想检查是否有更好的方法。

你可以尝试这样的事情。

def bool_fixer(func):
    table = {"true": True, "false": False}
    def wrapper(*args, **kwargs):
        for key, val in kwargs.items():
            if isinstance(val, str) and val.lower() in table:
                kwargs[key] = table[val.lower()]
        return func(*args, **kwargs)
    return wrapper

@bool_fixer
def method(...):
    do something

在装饰器发挥它的魔力之后,所有字符串“true”和“false”都将变成它们的 python bool 等价物,您可以跳过 [=14 中的所有检查=]函数。

如果您希望它也包含 intsfloats

import re
def converter(func):
    patterns = {r"\d*": int, r"\d*?\.\d*": float}
    table = {"true": True, "false": False}
    def wrapper(*args, **kwargs):
        for key, val in kwargs.items():
            if isinstance(val, str):
                if val.lower() in table:
                    kwargs[key] = table[val.lower()]
                    continue
                for pattern in patterns:
                    if re.match(pattern, val):
                        kwargs[key] = patterns[pattern](val)
        return func(*args, **kwargs)
    return wrapper

def converter(func):
    table = {"true": True, "false": False}
    def wrapper(*args, **kwargs):
        for key, val in kwargs.items():
            if isinstance(val, str):
                if val.lower() in table:
                    kwargs[key] = table[val.lower()]
                elif val.isdigit():
                    kwargs[key] = int(val)
                elif re.match(r"\d*?\.\d*", val):
                    kwargs[key] = float(val)
        return func(*args, **kwargs)
    return wrapper

这个装饰器应该可靠地处理布尔值、整数和浮点数。如所写,这将修改 str 类型的关键字参数。它首先检查 str 是单词“[Tt]rue”还是“[Ff]alse”。下一个测试是检查 str 是否为整数(一个简单的转换测试有效)。首先检查int是因为格式比float更讲究,因为int只能是数字,而float可以包含小数点。最后,它尝试强制转换为浮动。如果所有这些转换都失败了,那么我们假设它是一个不应被篡改的实际 str。

def cast_arguments(method):
    """decorator"""

    def wrapper(*args, **kwargs):
        for key, value in kwargs.items():

            # change special strings to bools
            if isinstance(value, str):
                if value.lower() == "true":
                    kwargs[key] = True
                elif value.lower() == "false":
                    kwargs[key] = False
                else:
                    try:
                        # change ints to int (int cannot have ".")
                        kwargs[key] = int(value)
                    except ValueError:
                        try:
                            # change floats to float (can have ".")
                            kwargs[key] = float(value)
                        except ValueError:
                            # this is an actual string
                            pass

        return method(*args, **kwargs)
    return wrapper


class Test:
    @cast_arguments
    def method(self, logged_in=False, interactions=False, other=False):
        print("logged_in: ", logged_in, type(logged_in))
        print("interactions: ", interactions, type(interactions))
        print("other: ", other, type(other))


c = Test()
c.method(logged_in="1", interactions="True", other="3.14")

输出:

$ python test.py
logged_in:  1 <class 'int'>
interactions:  True <class 'bool'>
other:  3.14 <class 'float'>