首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >导入的python模块中的依赖项注入

导入的python模块中的依赖项注入
EN

Stack Overflow用户
提问于 2015-11-22 21:56:17
回答 2查看 917关注 0票数 1

我的python模块使用了另一个模块中的一些函数,但我有该模块接口的几个实现。怎么指出,该用哪一个呢?

简单的例子:

A.py:

代码语言:javascript
复制
import B
def say_hi()
   print "Message: " + B.greeting()

main.py:

代码语言:javascript
复制
import A(B=my_B_impl)
A.say_hi()

my_B_impl.py:

代码语言:javascript
复制
def greeting():
   return "Hallo!"

输出:

代码语言:javascript
复制
Message: Hallo!
EN

回答 2

Stack Overflow用户

发布于 2015-11-23 18:53:50

在python中,这可以通过继承来最优雅地完成:

A.py:

代码语言:javascript
复制
import B
class SayHi(object):
    b = B
    def say_hi(self):
       print "Message: " + self.b.greeting()

my_B_impl.py:

代码语言:javascript
复制
class AlternativeHi(object):
    def greeting(self):
       return "Hallo!"

main.py:

代码语言:javascript
复制
import A
from my_B_impl.py import AlternativeHi
class MyHi(SayHi):
    b=AlternativeHi
a=MyHi()
MyHi.say_hi()

输出:

代码语言:javascript
复制
Message: Hallo!

您还可以使用工厂模式来避免显式声明类AlternativeHiMyHi

A.py

代码语言:javascript
复制
from B import greeting
class SayHi(object):
    def __init__(self,*args,**kwargs):
        self.greeting = greeting
    def say_hi(self):
       print "Message: " + self.greeting()

def hi_factory(func):
    class CustomHi(SayHi):
        def __init__(self,*args,**kwargs):
            result = super(CustomHi, self).__init__(*args, **kwargs)
            self.greeting = func
    return CustomHi

my_B_impl.py:

代码语言:javascript
复制
def greeting(self):
    return "Hallo!"

main.py:

代码语言:javascript
复制
form A import hi_factory
from my_B_impl import greeting
a = hi_factory(greeting)
a.say_hi()
票数 1
EN

Stack Overflow用户

发布于 2015-11-23 09:03:21

你问的问题不是直接可能的。Python的模块系统中没有内置的参数化功能。如果你仔细想想,就不清楚这样的建议应该如何工作:如果模块AB都导入了模块M,但它们提供了不同的参数,那么在导入M时使用哪个参数?是否导入了两次?这对于模块级配置(就像在logging中)意味着什么?如果第三个模块C试图导入不带参数的M,情况会变得更糟。此外,您可以从外部覆盖任何import语句的“开放世界”思想违反了“您编写的代码就是运行的代码”的语言设计原则。

其他语言已经以不同的方式集成了参数化模块(比较Scala的对象模型、ML的模块和签名,以及C++的模板),但尚不清楚这样的特性是否适合Python. (也就是说,如果你有足够的决心和自虐精神,你可能会用importlib破解一些类似参数化模块的东西。)

然而,Python确实具有非常强大和灵活的动态分派功能。Python的标准、日常特性,如函数、类、参数和覆盖,为这种支持提供了基础。

有很多方法可以在你的函数示例中切开蛋糕,这个函数的行为可以由它的客户配置。

由值参数化的函数:

代码语言:javascript
复制
def say_hi(greeting):
    print("Message: " + greeting)

def main():
    say_hi("Hello")

由值参数化的类:

代码语言:javascript
复制
class Greeter:
    def __init__(self, greeting):
        self.greeting = greeting
    def say_hi(self):
        print("Message: " + self.greeting)


def main():
    Greeter("Hello").say_hi()

具有虚方法的类:

代码语言:javascript
复制
class Greeter:
    def say_hi(self):
        print("Message: " + self.msg())

class MyGreeter(Greeter):
    def msg(self):
        return "Hello"

由函数参数化的函数:

代码语言:javascript
复制
def say_hi(greeting):
    print("Message: " + greeting())

def make_greeting():
    return "Hello"

def main():
    say_hi(make_greeting)

还有更多的选择(我在避免使用Java-y的对象调用其他对象的例子),但是您已经明白了。在每种情况下,行为的选择(参数的传递,方法的覆盖)都与使用它的代码解耦,可以放在不同的文件中。正确的选择取决于您的情况(尽管这里有个提示:正确的总是最简单的有效方法)。

API :在一条评论中,你提到你想要一个在模块级设置依赖的。这样做的主要问题是依赖关系是全局的-模块是单例的,因此任何导入模块的人都必须使用相同的依赖关系实现。

我的建议是提供一个具有“适当的”(每个实例)依赖注入的面向对象的API,并提供使用依赖的(可配置的)“默认”设置的顶级便利函数。然后您可以选择不使用全局配置的版本。这大致就是how asyncio does it

代码语言:javascript
复制
# flexible object with dependency injection
class Greeter:
    def __init__(self, msg):
        self.msg = msg
    def say_hi(self):
        print("Message: " + self.msg)

# set up a default configuration of the object to be used by the high-level API
_default_greeter = Greeter("Hello")
def configure(msg):
    global _default_greeter
    _default_greeter = Greeter(msg)

# delegate to whatever default has been configured
def say_hi():
    _default_greeter.say_hi()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33855560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档