我们如何使用装饰器清理函数的每个参数输入?
在下面的示例中,我希望类方法sani.by_signature
能够清理名为pow
的函数的每个输入参数
import functools
class sani:
def getattr(attrname:str):
lamby = lambda *args, **kwargs: None
return lamby
def by_signature(*arg_cleaners, **kwarg_cleaners):
return Decorator(*arg_cleaners, **kwarg_cleaners)
class Decorator:
def __new__(*arg_cleaners, **kwarg_cleaners):
obj = super().__new__(cls)
### obj = functools.update_wrapper(a, b)
return obj
def __init__(self, *arg_cleaners, **kwarg_cleaners):
obj = super().__new__()
obj = functools.
return obj
def __call__(*iargs, **ikwargs):
# variables with an `i` on the left-end of the variable name are inputs
for iarg in iargs:
args[0] = sani.to_float(iargs[0])
args = tuple(iargs)
kwargs = dict.fromkeys(ikwargs)
for ikey in ikwargs:
kwargs[ikey] =
return pow(*args, **kwargs)
return new_pow
下面我们有一个pow
函数,它应该被清理。
class PowClass:
@classmethod
@sani.by_signature(sani.to_float, sani.to_int, debug_on=sani.clean_str_or_none)
def pow(cls, base:float, exponent:int, *, debug_on=None)
"""
| BASE | EXP | OUTPUT |
|-------|--------|-----------|
| 10 | 0 | 1 |
| 10 | 1 | 10 |
| 10 | 2 | 100 |
| 10 | 3 | 1000 |
| 3.5 | 0 | 1 |
| 3.5 | 4 | 150.0625 |
"""
if debug_on:
cls.log("pow(", base, exponent, ")")
if exponent == 0:
return 1
return base*pow(base, exponent - 1)
###### COMMENT: @sani.each_pos_arg(clean_str_or_none)
def log(*args, sep=" ", end="\n"):
pass
# print(*args, sep=sep, end=end, file=some_file)
装饰器应该清理所有的输入。
对于这个问题,to_float
和clean_str_or_none
做什么并不重要,为了使代码可操作,我们可以有以下内容。
import singledispatched from functools
class sani
@singledispatched
def to_float(input:object):
"""
+--------------------------------+-------------+
| INPUT | OUTPUT |
+--------------------------------+-------------+
| string "4.992" | float 4.992 |
| list ["4", ".", "9", "9", "2"] | float 4.992 |
| list ["4.9", 9, "2"] | float 4.992 |
| float 4.992 | float 4.992 |
+--------------------------------+-------------+
"""
# doc string shown above
@to_float.register(list)
def to_float_from_iterable(input:object):
"""
+--------------------------------+-------------+
| INPUT | OUTPUT |
+--------------------------------+-------------+
| list ["4.9", 9, "2"] | float 4.992 |
+--------------------------------+-------------+
"""
# TO DO LATER: predicate dispatch
# @to_float.register(lambda obj: hasattr(obj, '__iter__'))
return float("".join(str(ch) for ch in input).strip())
@to_float.register(float)
def to_float_from_float(input:object):
"""
+--------------------------------+-------------+
| INPUT | OUTPUT |
+--------------------------------+-------------+
| float 4.992 | float 4.992 |
+--------------------------------+-------------+
"""
return input
下面是to_int
的代码
def to_int(input:object):
if isinstance(input, float):
input = str(input)
return float("".join(str(ch) for ch in input).strip())
下面是clean_str_or_none
的代码
import singledispatched from functools
@singledispatched
def clean_str_or_none(input):
pass
@clean_str_or_none.register(type(None))
def clean_str_or_none_from_none(input:type(None)):
return None
@clean_str_or_none.register(str)
def clean_str_or_none_from_str(input:str):
"""
converts all uppercase letters to lower-case
deletes all underscore characters, line-feeds, tab characters, and spaces
+----------------------------+------------------------+
| INPUT | OUTPUT |
+----------------------------+------------------------+
| "makeLinesTransparent" | "makelinestransparent" |
| "make_lines_transparent" | "makelinestransparent" |
| " make lines transparent " | "makelinestransparent" |
+----------------------------+------------------------+
"""
return "".join(filter(lambda ch: ch != "\n\r\t _", input.strip().lower()))
我不知道如何用santi.by_signature
修饰名为pow
的可调用对象,以便pow
的每个输入都通过一个清理函数传递,例如以下函数之一:
to_non_positive_int
to_float
clean_str_or_none
1条答案
按热度按时间6yjfywim1#
装饰器接受一个函数作为其参数,并返回一个修改后的函数。你的装饰器在它自己的定义中显式引用
pow
(你打算装饰的特定函数),这违背了装饰器的目的;相反,它应该修改作为参数传递给它的任何函数。您还需要仔细跟踪以下两者之间的差异:1.创建装饰器所调用的函数
1.转换后的函数(它接收调用修饰函数的实际参数)
在你添加的OOP间接层中可以做到这一点,但是在你的代码中有很多地方都弄不清它当前在哪个抽象层操作,并且将功能分散在一堆嵌套类中会使其更难分解。我建议首先让你的装饰器的基本版本作为一个简单的嵌套函数工作,如果需要的话,可以在以后将其扩展为更复杂的OOP版本。
下面是一个你正在尝试做的工作示例:
使用任意位置和关键字参数
f_args
和f_kwargs
调用by_signature
函数,并定义一个decorator
,它定义了一个wrapped
函数,该函数使用根据f_args
和f_kwargs
转换的参数调用其func
arg。t做任何错误检查,并假设它将有一个f
为每个arg
;更复杂的实现可能尝试检查func
的签名,并在没有提供所有期望的转换函数时产生有用的错误消息或提供默认值。请注意,在对
test
的调用中,位置参数通过float
和int
函数进行转换,kwargdebug_on
通过str
函数进行转换,因此当我们在函数中打印这些参数时,我们看到它们分别呈现为float、int和str。如果我们去掉装饰器,我们会看到: