将字符串转换为数字的装饰器

时间:2017-08-20 05:11:52

标签: python decorator python-decorators

我想使用装饰器将字符串格式的数字转换为int / float值,这是我尝试的方法

def str_to_int(func):
     """
        This wrapper converts string value into integer
     """
     def wrapper(*args, **kwargs):
         for arg in args:
             arg = int(arg)
         return func(*args, **kwargs)
     return wrapper
 @str_to_int
 def number_as_string(a, b, c):
     return a,b,c
 print (number_as_string('1', '2', '3'))

输出

('1', '2', '3')

但是,我想要类似下面的内容

(1, 2, 3)

我可以使用以下代码生成以上输出

def str_to_int(func):
     """
        This wrapper converts string value into integer
     """
     def wrapper(x, y, z):
         return int(x), int(y), int(z)
     return wrapper
 @str_to_int
 def number_as_string(a, b, c):
     return a,b,c
 print (number_as_string('1', '2', '3'))

但是上面的代码在第一时间失败了使用装饰器的目的,因为我想转换字符串值而不管原始函数的参数如何。

任何人都可以建议第一个程序出了什么问题以及如何解决它。

1 个答案:

答案 0 :(得分:0)

它没有按预期工作的原因是因为你永远不会更新传入的args,你只需要覆盖循环中的值。

考虑这个修订版本:

>>> def str_to_int(f):
...   def wrapper(*args, **kwargs):
...     args = map(int, args)
...     return f(*args, **kwargs)
...   return wrapper
...
>>> @str_to_int
... def foo(a,b,c):
...   return a,b,c
...
>>> foo('1','2','3')
(1, 2, 3)

关键是列表行:

args = map(int, args)

它确保原始的args元组被完全替换,在你的循环中你默默地丢弃了这个值。

对于Python3,您应该使用:

args = tuple(map(int, args))

由于地图将返回地图对象。

当然我希望你意识到这个装饰器只有在你传递的东西才能实际转换成数字时才有效,如果你传入一个字符串然后它会引发ValueError

>>> foo('hello')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in wrapper
ValueError: invalid literal for int() with base 10: 'hello'

如果要防止这种情况,则必须忽略那些无法转换为整数的值:

def wrapper(*args, **kwargs):
   _temp = []
   for i in args:
     try:
       _temp.append(int(i))
     except ValueError:
       _temp.append(i)
   args = tuple(_temp)
   return f(*args, **kwargs)

现在它只会忽略它无法转换的内容:

>>> foo('hello', '1', '2')
('hello', 1, 2)

您可以稍微缩短您的代码,因为*会自动扩展参数,您可以利用它来发挥作用:

 # args = tuple(_temp)
 return f(*_temp, **kwargs)