注入;“全球进口”;转换为Python函数 简短但完整的摘要

注入;“全球进口”;转换为Python函数 简短但完整的摘要,python,Python,我希望允许我的函数(类工厂)的用户在使用我的函数时插入/覆盖全局导入(下面对基本原理进行更详细的解释)。但是大约有10个不同的变量可以传入,它在代码中添加了大量重复的行。(当然,这也使得调用更为复杂:P)现在,我正在做如下的事情(只是简化了所有这些)。为了使其可运行,我使用了一个虚拟类,但在实际脚本中我将使用import pkg1,等等。我认为这比类工厂更清晰、更短,等等 class Dummy(object): pass pkg1, pkg2 = Dummy(), Dummy() pkg1.

我希望允许我的函数(类工厂)的用户在使用我的函数时插入/覆盖全局导入(下面对基本原理进行更详细的解释)。但是大约有10个不同的变量可以传入,它在代码中添加了大量重复的行。(当然,这也使得调用更为复杂:P)现在,我正在做如下的事情(只是简化了所有这些)。为了使其可运行,我使用了一个虚拟类,但在实际脚本中我将使用
import pkg1
,等等。我认为这比类工厂更清晰、更短,等等

class Dummy(object): pass

pkg1, pkg2 = Dummy(), Dummy()
pkg1.average = lambda *args : sum(args) / len(args)
pkg2.get_lengths = lambda *args : map(len, args)


def get_average(*args, **kwargs):
    average = kwargs.get("average") or pkg1.average
    get_lengths = kwargs.get("get_lengths") or pkg2.get_lengths
    return average(*get_lengths(*args))

adjusted_length = lambda *args: map(len, args) + [15]
print get_average([1,2], [10, 4, 5, 6]) == 3 # True
print get_average([1,2], [10, 4, 5, 6], get_lengths=adjusted_length) == 7 # True
相关SO问题 这个堆栈溢出帖子:,似乎特别相关,最初我想通过存储到本地字典来覆盖本地,但(1)它似乎不起作用,(2)这似乎是个坏主意。所以,我想知道是否有其他方法可以做到这一点

这一个看起来很有希望(),但我不确定如何以与模块相同的方式访问当前文件的全局文件。(这个问题——实际上并不适用,因为我(最终)用它来定义类)

我想我可以用exec语句(比如这篇文章-)来包装所有内容,但这既繁琐又意味着执行错误检查/linting等要困难得多

这就是我想做的。(注意:我会使用pkg1导入平均值的
和pkg2导入获取长度的

但我希望示例更清晰(需要复制上面的pkg1和pkg2才能运行此示例))

我的特定用例的基本原理 现在,我正试图编写一个动态生成的类工厂(用作SQLAlchemy mixin),但我希望允许我的类的用户传入替代构造函数,以便他们可以使用SQLAlchemy适配器,等等


例如,Flask SQLAlchemy提供了与SQLAlchemy相同的接口,但提供了一个自定义对象/类(
db
),它环绕所有SQLAlchemy对象以提供更多功能。

您可以使用参数传递函数。这实际上是你正在做的,但更干净。我使用了
列表
作为单个参数,而不是
*args
,因为当您有其他参数时,它更容易处理。您必须将列表包含在一个元组中,才能将它们传递到
get\u average

内置函数是这样工作的,因此Python程序员应该很容易理解它

get_average(lists, average=pkg1.average, get_lengths=pkg2.get_lengths):
    return average(*get_lengths(*lists))

print get_average(([1,2], [10, 4, 5, 6]))
print get_average(([1,2], [10, 4, 5, 6]), get_lengths=adjusted_length)
如果有许多关键字参数,可以将它们打包到一个对象中:

class GetAverageContext(object):
    def __init__(self, average=pkg1.average, get_lengths=pkg2.get_lengths):
        self.average = average
        self.get_lengths = get_lengths

DefaultGetAverageContext = GetAverageContext()

def get_average(lists, context=DefaultGetAverageContext):
    return context.average(*context.get_lengths(*lists))

这里有一个要点展示了相同的例子,但是有一个类工厂(读起来有点复杂,所以我没有在文章中使用它):很好的观点。关于使用默认值——我想到了这一点,这是一个合理的选择,但它仍然以(在我的例子中)10个关键字参数结束,这有点长。另一方面,它使您在使用函数时应该传递的内容更加明确。关于使用列表,虽然我同意我发布的函数是一种更好的方法,但这是类工厂的产物(因为类的
\uuuu init\uuuu
方法接受
(self,*args,**kwargs)
,并且不使用任何关键字参数(只是为了mro/超级兼容性))@杰夫·特兰特:我认为使用
**kwargs
并不能改善情况。无论如何,您必须在某个地方记录所有关键字参数。如果您有许多关键字参数,您可以将它们打包到一个对象中。我用一个例子编辑了我的答案。坦率地说,在我读了你的第一个答案后,我意识到你的想法是正确的(特别是因为它使函数的文档更具描述性)。不过,用这个物体还是个好主意。
class GetAverageContext(object):
    def __init__(self, average=pkg1.average, get_lengths=pkg2.get_lengths):
        self.average = average
        self.get_lengths = get_lengths

DefaultGetAverageContext = GetAverageContext()

def get_average(lists, context=DefaultGetAverageContext):
    return context.average(*context.get_lengths(*lists))