在Python中自动键入Cast参数

2024-04-18 23:44:49 发布

您现在位置:Python中文网/ 问答频道 /正文

背景:
我主要通过管道中的命令行运行python脚本,因此我的参数始终是需要类型转换为适当类型的字符串。我每天制作很多小脚本,为每个脚本输入每个参数所需的时间比应该的要长。

问题:
有没有一种规范的方法可以为函数自动键入强制转换参数?

我的方式:
如果没有更好的方法,我已经开发了一个装饰师来做我想做的事情。decorator是下面的autocast fxn。在示例中,修饰的fxn是fxn2。注意,在代码块的末尾,我将1和2作为字符串传递,如果运行脚本,它将自动添加它们。这是个好办法吗?

def estimateType(var):
    #first test bools
    if var == 'True':
            return True
    elif var == 'False':
            return False
    else:
            #int
            try:
                    return int(var)
            except ValueError:
                    pass
            #float
            try:
                    return float(var)
            except ValueError:
                    pass
            #string
            try:
                    return str(var)
            except ValueError:
                    raise NameError('Something Messed Up Autocasting var %s (%s)' 
                                      % (var, type(var)))

def autocast(dFxn):
    '''Still need to figure out if you pass a variable with kw args!!!
    I guess I can just pass the dictionary to the fxn **args?'''
    def wrapped(*c, **d):
            print c, d
            t = [estimateType(x) for x in c]
            return dFxn(*t)
    return wrapped

@autocast
def fxn2(one, two):

   print one + two 

fxn2('1', '2')      

编辑:对于任何来到这里并想要更新和简洁的工作版本的人,请转到这里:

https://github.com/sequenceGeek/cgAutoCast

这里还有一个基于以上内容的快速工作版本:

def boolify(s):
    if s == 'True' or s == 'true':
            return True
    if s == 'False' or s == 'false':
            return False
    raise ValueError('Not Boolean Value!')

def estimateType(var):
    '''guesses the str representation of the variables type'''
    var = str(var) #important if the parameters aren't strings...
    for caster in (boolify, int, float):
            try:
                    return caster(var)
            except ValueError:
                    pass
    return var

def autocast(dFxn):
    def wrapped(*c, **d):
            cp = [estimateType(x) for x in c]
            dp = dict( (i, estimateType(j)) for (i,j) in d.items())
            return dFxn(*cp, **dp)

    return wrapped

######usage######
@autocast
def randomFunction(firstVar, secondVar):
    print firstVar + secondVar

randomFunction('1', '2')

Tags: the脚本falsetruereturnifvardef
3条回答

如果要自动转换值:

def boolify(s):
    if s == 'True':
        return True
    if s == 'False':
        return False
    raise ValueError("huh?")

def autoconvert(s):
    for fn in (boolify, int, float):
        try:
            return fn(s)
        except ValueError:
            pass
    return s

如果愿意,可以调整boolify以接受其他布尔值。

我想你可以用一个函数装饰器来创建一个类型签名系统,就像你所拥有的,只有一个接受参数。例如:

@signature(int, str, int)
func(x, y, z):
    ...

这样的装潢师很容易建造。像这样的东西(编辑——工作!)以下内容:

def signature(*args, **kwargs):
    def decorator(fn):
        def wrapped(*fn_args, **fn_kwargs):
            new_args = [t(raw) for t, raw in zip(args, fn_args)]
            new_kwargs = dict([(k, kwargs[k](v)) for k, v in fn_kwargs.items()])

            fn(*new_args, **new_kwargs)

        return wrapped

    return decorator

就这样,现在可以在函数中嵌入类型签名了!

@signature(int, int)
def foo(x, y):
    print type(x)
    print type(y)
    print x+y

>>> foo('3','4')
<type: 'int'>
<type: 'int'>
7

基本上,这是@utdemir方法的类型显式版本。

如果您信任源,可以使用纯eval输入字符串:

>>> eval("3.2", {}, {})
3.2
>>> eval("True", {}, {})
True

但如果不信任源,可以使用ast模块中的literal_eval。

>>> ast.literal_eval("'hi'")
'hi'
>>> ast.literal_eval("(5, 3, ['a', 'b'])")
(5, 3, ['a', 'b'])

编辑: 作为Ned Batchelder的评论,它不接受非引用的字符串,因此我添加了一个解决方法,也是一个关于使用关键字参数自动保存decorator的示例。

import ast

def my_eval(s):
    try:
        return ast.literal_eval(s)
    except ValueError: #maybe it's a string, eval failed, return anyway
        return s       #thanks gnibbler

def autocaste(func):
    def wrapped(*c, **d):
        cp = [my_eval(x) for x in c]
        dp = {i: my_eval(j) for i,j in d.items()} #for Python 2.6+
        #you can use dict((i, my_eval(j)) for i,j in d.items()) for older versions
        return func(*cp, **dp)

    return wrapped

@autocaste
def f(a, b):
    return a + b

print(f("3.4", "1")) # 4.4
print(f("s", "sd"))  # ssd
print(my_eval("True")) # True
print(my_eval("None")) # None
print(my_eval("[1, 2, (3, 4)]")) # [1, 2, (3, 4)]

相关问题 更多 >