Python中的依赖注入容器是否有意义?

WeN*_*ers 16 python dependency-injection

一直在搞乱python,像往常一样,它把我刚性的静态类型面向对象的世界抛到了一个烂摊子.Python支持duck typing,没有基于接口的编程的可用概念(如在C#接口中)并允许全局变量.所有这些好东西都是依赖注入容器的任何意义,或者Python运行时是否成为容器.

我理解这些容器在静态类型的OO语言中的意义,例如Java和C#,但是这样的东西是否适合python的坚果世界(我喜欢它)?

我一直怀疑依赖注入作为一种设计模式是一种难闻的气味,一切都必须是一个"纳粹思维"的类,即c#和Java,我会是正确的还是我缺少的东西?

到目前为止,我认为只需使用Globals就可以覆盖工厂,单例,多实例对象.我也怀疑Aspect的内容也被覆盖了,虽然我还在考虑这个问题.

鸭子打字是目前让我感觉到的东西,因此习惯于定义接口然后在这些接口上基于类,让静态的东西覆盖我的愚蠢,我觉得没有静态类型,容器有点无用.

编辑

我想在使用python时我不会使用Dependency Injector框架/容器.真的没有任何意义.在思考并阅读到目前为止的反馈之后,论证清楚地表明,如果没有静态类型定义,所作出的承诺是如此宽松,以至于为什么要麻烦.鸭子打字就是这样,唯一的承诺可以通过文档来实现.只要引用通过signiture参数进入类Method/function,而不是通过编程环境的以太,那么我认为我会安全.

但令人震惊的是,我无法通过我在Java和C#中完成的过度设计实践来强化我对其他人的意愿.我在乎......不......

Kar*_*tel 13

没有基于接口的编程的可用概念(如在C#接口中)

仅仅因为编译器无法检查您是否正确使用了接口并不意味着"没有可用的接口概念".您记录一个接口,并编写单元测试.

对于全局变量,它不像public staticC#或Java类中的方法和字段真的有任何不同.例如,考虑java.lang.Math的工作原理.现在考虑java.lang.Math 不是 Singleton 的事实.他们这样做是有充分理由的.

有了所有这些好东西,依赖注入容器真的有任何意义

我对此表示怀疑,但后来我从未在C#或Java中看到它们的重点.在我看来,依赖注入是一种编程技术.而且,它也没有那么多.

我一直怀疑依赖注入作为一种设计模式是一种难闻的气味,一切都必须是"纳粹思维"

不,不是.依赖注入在很多时候都是一个好主意.您也不需要一个类来注入依赖项.每次将某些东西作为参数传递给自由函数时,不是让函数调用另一个函数来获取信息,而是基本上做同样的事情:控制反转.Python还允许您以多种方式处理类似于类的模块(当然比Java和C#更多的方式).将模块作为参数传递给函数可以解决一些问题.:)

到目前为止,我认为只需使用Globals就可以覆盖工厂,单例,多实例对象.

单身者是难闻的气味,如果有的话.在几乎所有情况下,根据我的丰富经验,它们的存在是因为有人认为原则上Bad(TM)具有全局性,没有真正考虑可能的选项,或者为什么他们想要对单个共享对象的那种访问,甚至为什么全局变量首先是"原则上的坏(TM)".

可以在Python中创建一个充当工厂的全局函数.但是,我会说更多Pythonic可以执行以下任何操作:

a)首先,真的,真的,非常确定你不能只做你想做的事__init__.我的意思是,在动态类型语言中,你可以通过这种方式做很多事情.

b)如果__init__不切断它,请尝试使用__new__控制行为.

在Python中,类是对象本身,可以调用.默认情况下,调用它们会实例化该类.有了__new__,你可以加入其中.

c)使用应用于该类的装饰器.这是一个制作Singleton的例子(仅仅因为):

def _singleton(cls):
  instance = cls()
  result = lambda: instance
  result.__doc__ = cls.__doc__
  return result

@_singleton
class example(object): pass
Run Code Online (Sandbox Code Playgroud)

它的工作方式:当你装饰类时,_singleton()调用类,传入类.构造并缓存一个实例,并_singleton()返回一个匿名函数,它将在调用时返回实例.要完成这个游戏,该类的文档将附加到匿名函数.然后Python将全局范围内的类名称重新绑定到返回的匿名函数.因此,当您调用它时,每次都会得到相同的类实例.

现在,这仍然可以解决,当然(你可以做一些类似于example().__class__()获取另一个实例的东西),但是你做错了比你简单地忽略工厂函数以便正常使用构造函数更清楚.另外,这意味着调用代码实际上就像正在调用构造函数一样:)

鸭子打字是目前让我感觉到的东西,因此习惯于定义接口然后在这些接口上基于类,让静态的东西覆盖我的愚蠢,我觉得没有静态类型,容器有点无用.

你需要改变你的想法:不要担心你被传递的东西是什么,并担心它是否可以做你想做的事情.这就是鸭子打字的方式.

  • 我是否会在大型项目中使用Python,不行.您的承诺仅通过文档制作,这使得它成为一种非常难以构建的语言.我刚刚使用AsyncCore的东西,我遇到了一个接受某个签名功能的方法.我能够制定签名的唯一方法是查看文档.在C#中,我通常可以通过大部分内容猜测,如果有任何异国情调,我会查一查,或者编译器对我大喊大叫,不再用垃圾来打击它. (5认同)
  • "精心设计的接口可减少耦合并提高内聚力".这就是问题所在.您无法在Python中认真设计界面.我刚读了一篇很好的文章,其中将python/ruby​​描述为play doh,将Java/C#描述为LEGO brick.当你在LEGO中处理定义的形状而不是在Play doh中处理编程设计时要容易得多.谢谢,我认为通过这个讨论,你已经清理了我遇到python问题的原因. (3认同)

cwa*_*ole 7

结论

(以下是原帖中最相关的部分.我承认,我有点诗意,所以我虽然应该在他们自己的部分中包含最重要的句子.那就是说,我觉得诗意的打蜡很重要足够我没有删除它.)

仍然使用依赖注入.始终需要对象与已经实例化的对象进行通信.需要"父"对象(或容器,或其他)来设置其"子"的状态.这些需要通过某种方法传递或通过某种赋值来设置,但从抽象意义上说,它是同一个东西.

原答案:

键入系统

从很多方面来说,Python是我遇到的第二个数学上最纯粹的语言 - 它只遵循Scheme(尽管我从未使用过Haskell,但我也明白它也会在那里).

Python本身支持闭包,它具有continuation(yield语法),多重继承和循环理解语法,这在很大程度上是无与伦比的.所有这些都使它更接近Alonzo Church在Lambda微积分中的原始愿景(麦卡锡在Lisp背后的原创思想).Python 3通过集合理解使其变得更加纯粹(这让我的心灵只是在思考它们固有的美丽).

不断地,持续地存在这样的想法:存储在Python变量中的数据与数学中的对应物有更多共同之处,以至于对象的界面可以简化为"形容词或描述的形容词组"物体".基本上,对象的界面完全包含在其中__dict__并与之一起显示dir.

考虑到所有这一切,它确实开始让人怀疑用传统方式查看事物(带有引号的"传统"方式,因为Python与Java一样旧)是否真的可以在这种语言中工作.甚至Python中的参数列表对他们都有OOP感觉(kwargs,任何人?)它确实让世界颠倒了.

仍然使用依赖注入.始终需要对象与已经实例化的对象进行通信.需要"父"对象(或容器,或其他)来设置其"子"的状态.这些需要通过某种方法传递或通过某种赋值来设置,但从抽象意义上说,它是同一个东西.但是有一种隐含的信任,即传递的对象的内容__dict__将包含适当的描述.因此,它变得更少了,"一旦我实例化了这个物体,我将赋予它生命所需要的东西,"而且更多,"嗯,是的,一个物体需要一个状态,所以我是给它一个."

这揭示了静态类型的隐藏方面.为了使某些东西IFoo能够发挥作用,它必须完全和完整地了解它的意义IFoo,即使它永远不需要90%的定义.同时,duck typing使得依赖对象只知道属性X,Y和Z应该在运行时存在.

全局

至于全局变量.除非你别无选择,否则不要使用它们.如果只是因为Singletons允许您在值更改时进行记录,那么最好使用Singleton.全局变量不是这样.

有一个编程规则,你的界面越暴露和复杂,维护起来就越困难.如果在全局变量中放置了某些内容,则该模块中的任何内容以及ANY模块中的任何内容都可以修改该值.代码几乎可以变得不确定.我向你保证,悲伤随之而来.