背景
我主要从管道中的命令行运行python脚本,所以我的参数总是字符串,需要类型转换为适当的类型。我每天都会编写很多小脚本,并为每个脚本输入每个参数的类型需要更多的时间。
问题:
是否有规范的方法来自动为函数键入强制转换参数?
我的方式:
如果没有更好的方法,我已经开发了一个装饰器来做我想做的事情。装饰器是下面的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')
答案 0 :(得分:15)
如果您想自动转换值:
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
以接受其他布尔值。
答案 1 :(得分:6)
如果您信任来源,则可以使用普通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的评论,它不会接受非引用的字符串,所以我添加了一个解决方法,也是一个关于带有关键字参数的autocaste 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)]
答案 2 :(得分:4)
我想你可以创建一个带有函数装饰器的类型签名系统,就像你一样,只有一个带参数。例如:
@signature(int, str, int)
func(x, y, z):
...
这样的装饰器可以很容易地构建。这样的事情(编辑 - 工作!):</ p>
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方法的类型显式版本。
答案 3 :(得分:2)
如果要从命令行解析参数,则应使用argparse
module(如果您使用的是Python 2.7)。
每个参数都可以有一个预期的类型,因此知道如何处理它应该相对简单。您甚至可以定义自己的类型。
...通常命令行字符串应该被解释为另一种类型,如float或int。 add_argument()的type关键字参数允许执行任何必要的类型检查和类型转换。常见的内置类型和函数可以直接用作类型参数的值:
parser = argparse.ArgumentParser()
parser.add_argument('foo', type=int)
parser.add_argument('bar', type=file)
parser.parse_args('2 temp.txt'.split())
>>> Namespace(bar=<open file 'temp.txt', mode 'r' at 0x...>, foo=2)
答案 4 :(得分:0)
您的代码段中有几个问题。
#first test bools
if var == 'True':
return True
elif var == 'False':
return False
这将始终检查True
,因为您正在测试字符串'True'
和'False'
。
python中没有类型的自动强制。通过*args
和**kwargs
收到的论据可以是任何内容。首先将查找值列表(每个值可以是任何数据类型,基元和复杂),然后查找映射(可以使用任何有效映射)。因此,如果您编写装饰器,最终会得到一个很好的错误检查列表。
通常情况下,如果您希望发送str,就在调用该函数时,请通过(str
)将其强制转换为字符串并发送它。
答案 5 :(得分:0)
我知道我在这场比赛中来得很晚,但是eval怎么样?
def my_cast(a):
try:
return eval(a)
except:
return a
或者(更安全):
from ast import literal_eval
def mycast(a):
try:
return literal_eval(a)
except:
return a