处理参数以便在Python中进行预处理,如果顺序很重要
我想对命名变量的外观顺序做一点改变 我想有一个关于编辑图像的管道,它会对我首先应用的技术产生影响。与其单独调用函数,我仍然希望使用包装器函数 例如:处理参数以便在Python中进行预处理,如果顺序很重要,python,function,arguments,Python,Function,Arguments,我想对命名变量的外观顺序做一点改变 我想有一个关于编辑图像的管道,它会对我首先应用的技术产生影响。与其单独调用函数,我仍然希望使用包装器函数 例如: def preprocess(cutoff=None, resize=None, blur=None): .... 现在,如果我调用像preprocess(resize=(100100),cutoff=55)这样的函数,我希望它首先调整大小,然后执行cutoff,尽管当预处理(cutoff=55,resize=(100100))时,反之亦
def preprocess(cutoff=None, resize=None, blur=None):
....
现在,如果我调用像preprocess(resize=(100100),cutoff=55)
这样的函数,我希望它首先调整大小
,然后执行cutoff,尽管当预处理(cutoff=55,resize=(100100))时,反之亦然。
实现这一点的最佳方法是什么?您不能使用关键字参数。如果您像以前一样通过普通参数接受它们,那么唯一的顺序就是参数的顺序。如果您通过
**kwargs
接受它们,您将获得一个dict
(没有订单)
如果你想知道参数的顺序,它们必须是位置参数;真的没办法
然而,可能有更好的设计。例如,为什么不把它们分开呢?然后,与此相反:
newfoo = foo.preprocess(resize=(100, 100), cutoff=55)
…您可以这样做:
newfoo = foo.resize(100, 100).cutoff(55)
或者提供简单的类型,这些类型只对参数进行包装:
newfoo = foo.preprocess(Resize(100, 100), Cutoff(55))
然后您可以让预处理
通过*args
获取其参数,并根据类型(arg)
进行分派
如果你看看你将如何实现这一点,它指出了另一种可能性:
class DumbArgWrapper(object):
def __init__(self, *args):
self.args = args
class Resize(DumbArgWrapper): pass
class Cutoff(DumbArgWrapper): pass
class Blur(DumbArgWrapper): pass
class ImageProcessor(object):
def preprocess(self, *args):
for arg in args:
if isinstance(arg, Resize):
do_resize(*arg.args)
# etc.
如果您只需将do_resize
代码移动到resize
(换句话说,使其成为一种“惰性函数”对象),它会更干净:
class SmartArgWrapper(object):
def __init__(self, *args):
self.args = args
class Resize(SmartArgWrapper):
def __call__(self, target):
do_resize(target, *self.args)
# etc.
class ImageProcessor(object):
def preprocess(self, *args):
for arg in args:
arg(self)
这样做之后,您就可以制作一个简单的包装器,将任何函数转换为
SmartArtWrapper
,而不是制作一堆子类
然后
关键是,有很多可能性。对于知道你想要什么和为什么的人来说,应该有一种而且只有一种明显的方法来实现……但是对于不知道你想要什么和为什么的人来说,这是不对的。为什么你希望这是一个单一的功能?这似乎是一个违反直觉的设计,如果我们知道背后的原因,我敢打赌有人会想出一个更好的设计来解决同样的问题。主要原因是我知道大多数情况下会出现默认行为,但我现在发现,也许在某些情况下,我想再次切换顺序。通过这种方式,仍然可以简单地将其称为
预处理(5,(10,10))
,但这个循环仍然不是完全确定的,现在不需要很多长函数名。那么使用调整大小
方法、切断
方法、模糊
方法怎么样,然后是一个preprocess
方法,它只适用于(非常常见的)情况,当您需要1到3个最常见的顺序时?所以,通常您只需调用preprocess(5,(10,10))
,但是如果您想向后执行操作,您可以调整大小(10,10)。切断(5)
?我想这很公平。谢谢分享你的想法。我在想,也许我遗漏了一些明显的东西。嗯,你正在寻找的功能不存在可能并不明显。事实上,如果在**kwargs
语法之前就已经发明了orderedict
的当前智能优化实现,那么它可能是可行的(不是很常见,但不是被禁止的,因为为什么要麻烦禁止它?)。例如,在所有支持运算符重载的编程语言中,第三方库设计人员非常喜欢的一件事是使用
运算符将顺序操作链接在一起。因此,在这种情况下,不要使用preprocess
函数,而是写入foo | resize(100100)| cutoff(55)
。但是,这可能会导致一些混乱的界面,我怀疑这就是为什么第一方语言设计师不那么容易找到它;-)@SteveJessop:我不会说它在“所有支持操作符重载的编程语言”中都很流行,尤其是在Python中,它不流行,也不惯用。(在C++中,另一方面…)“流行”可能是错误的词。我的意思是,有人总是试图这样做,而不是人们经常这样做。上一次,我发现有几次Python的尝试,我并没有努力寻找。并不像C++中的每个库作者都直接达到<代码> < /C>作为流水线操作符,大多数仍然使用函数调用。但是,它在C++中比Python更常见。@史蒂夫杰索普:当然,只要你能做到,就有人会像写一个C++ -助推lambda风格来娱乐一样。只有傻瓜才会在Python中这样做,但我做到了。:)