思路:

用一个字典存储beanName和资源
初始化时先将beanName和资源注册到字典中
然后用一个Dscriptor类根据beanName动态请求资源,从而实现控制反转

  1. # -*- coding:utf-8 -*-
  2. import os
  3. class BeanFactory:
  4. """
  5. Python版控制反转
  6. context: 存储bean的名字和对应的类或者值的字典
  7. allowRepalce: 是否允许替换已经注入的bean
  8. """
  9. def __init__(self,allowReplace=False):
  10. """构造函数
  11. allowReplace:是否允许替换已经注入的bean
  12. """
  13. self.context = {}
  14. self.allowReplace = allowReplace
  15. def setBean(self,beanName,resource,*args,**kwargs):
  16. if not self.allowReplace:
  17. assert not beanName in self.context,"该BeanFactory不允许重复注入%r,请修改beanName" % beanName
  18. def call():
  19. """定义一个函数闭包,如果注入的resource是可调用类型,就将*args和**kwargs传入并调用该函数,然后将返回值返回
  20. 如果是一个不可调用对象,就直接返回
  21. """
  22. if callable(resource):
  23. return resource(*args,**kwargs)
  24. else:
  25. return resource
  26. #将call闭包与beanName建立映射
  27. self.context[beanName]=call
  28. def __getitem__(self,beanName):
  29. """重载__getitem__方法,使得BeanFactory支持使用[]获取beanName对应的注册的资源
  30. """
  31. try:
  32. # 从context字典中取出beanName对应的资源
  33. resource = self.context[beanName]
  34. except KeyError:
  35. raise KeyError("%r 未注册" % beanName)
  36. # 返回闭包函数调用后的结果
  37. return resource()
  38. AppFactory = BeanFactory()
  39. def NoAssertion(obj): return True
  40. def IsInstanceOf(*classes):
  41. def test(obj): return isinstance(obj, classes)
  42. return test
  43. def HasAttributes(*attributes):
  44. def test(obj):
  45. for each in attributes:
  46. if not hasattr(obj, each): return False
  47. return True
  48. return test
  49. def HasMethods(*methods):
  50. def test(obj):
  51. for each in methods:
  52. try:
  53. attr = getattr(obj, each)
  54. except AttributeError:
  55. return False
  56. if not callable(attr): return False
  57. return True
  58. return test
  59. #
  60. #
  61. #Descriptor就是一类实现了__get__(), __set__(), __delete__()方法的对象
  62. #若一个类的成员是descriptor,在访问它的值时是通过__get__()函数访问的
  63. #用这个特性实现在访问一个类的成员时自动到BeanFactory中请求对应的资源
  64. class RequiredResource(object):
  65. def __init__(self, beanName, assertion=NoAssertion):
  66. self.beanName = beanName
  67. self.assertion = assertion
  68. def __get__(self, obj, T):#每次访问descriptor时都会调用__get__方法
  69. return self.result # <-- .操作符会自动调用__getattr__
  70. def __getattr__(self, name):
  71. assert name == 'result', "Unexpected attribute request other then 'result'"
  72. self.result = self.Request()
  73. return self.result
  74. def Request(self):
  75. obj = AppFactory[self.beanName]
  76. assert self.assertion(obj), \
  77. "The value %r of %r does not match the specified criteria" \
  78. % (obj, self.feature)
  79. return obj
  80. class Component(object):
  81. "Symbolic base class for components"
  82. class Bar(Component):
  83. # HasMethods是一个闭包函数,传入RequiredResource后用于检查'Console'
  84. # 对应的注册的那个feature是否有'WriteLine'方法
  85. # IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
  86. # 检查注册的'AppTitle'对应资源是否是一个字符串
  87. # IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
  88. # 检查'CurrentUser'对应的资源是否是一个字符串
  89. # RequiredFeatuire是desciptor,每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。
  90. con = RequiredResource('Console', HasMethods('WriteLine'))
  91. title = RequiredResource('AppTitle', IsInstanceOf(str))
  92. user = RequiredResource('CurrentUser', IsInstanceOf(str))
  93. flist = RequiredResource('show_dir',IsInstanceOf(list))
  94. def __init__(self):
  95. self.X = 0
  96. def PrintYourself(self):
  97. self.con.WriteLine('-- Bar instance --')
  98. # title 由 RequiredResource('AppTitle',IsInstanceOf(str))生成
  99. #'AppTitle'对应的值在__main__代码块注册了一个值
  100. self.con.WriteLine('Title: %s' % self.title)
  101. self.con.WriteLine('User: %s' % self.user)
  102. self.con.WriteLine('X: %d' % self.X)
  103. for f in self.flist:
  104. self.con.WriteLine(f)
  105. class BetterConsole(Component):
  106. def __init__(self, prefix=''):
  107. self.prefix = prefix
  108. def WriteLine(self, s):
  109. lines = s.split('\n')
  110. for line in lines:
  111. if line:
  112. print(self.prefix, line)
  113. else:
  114. print
  115. def GetCurrentUser():
  116. return os.getenv('USERNAME') or 'Some User' # USERNAME is platform-specific
  117. def ShowDir():
  118. return os.listdir()
  119. if __name__ == '__main__':
  120. print('\n*** IoC Demo ***')
  121. #Provide(feature,provider,*args,**kwargs) feature是要生成的对象的父类类型 provider是要注入的子类或者值
  122. AppFactory.setBean('AppTitle', 'Inversion of Control ...\n\n... The Python Way')
  123. AppFactory.setBean('CurrentUser', GetCurrentUser)
  124. AppFactory.setBean('Console', BetterConsole, prefix='-->') # <-- transient lifestyle
  125. AppFactory.setBean('show_dir',ShowDir)
  126. bar = Bar()
  127. bar.PrintYourself()

Python实现IOC控制反转的更多相关文章

  1. 回顾Spirng ioc 控制反转

    Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC .DI这两个概念是模糊不清的,是很难理解的.结合网上对Spring Ioc的理解,回顾一下自 ...

  2. 谈谈php里的IOC控制反转,DI依赖注入

    理论 发现问题 在深入细节之前,需要确保我们理解"IOC控制反转"和"DI依赖注入"是什么,能够解决什么问题,这些在维基百科中有非常清晰的说明. 控制反转(In ...

  3. DI依赖注入/IOC控制反转

    DI依赖注入# 啥都不说,直接上代码 <?php class UserController { private $user; function __construct(UserModel $us ...

  4. IoC实践--用Autofac实现MVC5.0的IoC控制反转方法

    Autofac是一个.net平台下发性能还不错的IoC框架,利用它可以实现依赖注入和控制反转,使自己的软件模块之间的耦合性大大降低,让软件扩展.维护更加容易.控制反转(Inversion of Con ...

  5. IoC控制反转与DI依赖注入

    IoC控制反转与DI依赖注入 IoC: Inversion of Control IoC是一种模式.目的是达到程序的复用.下面的两篇论文是对IoC的权威解释: InversionOfControl h ...

  6. Spring学习之Ioc控制反转(1)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  7. Spring学习之Ioc控制反转(2)

    开始之前: 1. 本博文为原创,转载请注明出处 2. 作者非计算机科班出身,如有错误,请多指正 ---------------------------------------------------- ...

  8. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

  9. Spring详解(二)------IOC控制反转

    我相信提到 Spring,很多人会脱口而出IOC(控制反转).DI(依赖注入).AOP等等概念,这些概念也是面试官经常问到的知识点.那么这篇博客我们就来详细的讲解 IOC控制反转. ps:本篇博客源码 ...

随机推荐

  1. Spring Boot2 系列教程 (十一) | 整合数据缓存 Cache

    如题,今天介绍 SpringBoot 的数据缓存.做过开发的都知道程序的瓶颈在于数据库,我们也知道内存的速度是大大快于硬盘的,当需要重复获取相同数据时,一次又一次的请求数据库或者远程服务,导致大量时间 ...

  2. 两个大数相乘 - 高精度FFT

    HDU 1402 A * B Problem Plus Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (J ...

  3. hdu 5139 数据的离线处理

    所谓的数据离线处理,就是将所有的输入数据全部读入后,在进行统一的操作,这样当然有好处,比如让你算好多数的阶层,但是输入的每个数是没有顺序的,其实跟可以线性的解决,但是由于没有顺序的输入,这样处理的话复 ...

  4. django.db.migrations.exceptions.MigrationSchemaMissing和raise ImproperlyConfigured('mysqlclient 1.3.13 or newer is required; you have %s.' % Database.__version__)

    1.使用Python3.7 + Django2.2 + MySQL 5.5 在执行(python manage.py migrate)命令时出现错误django.db.migrations.excep ...

  5. git 查看修改账号密码

    git config user.name         查看用户名 git config user.email         查看用户邮箱 修改用户名和邮箱的命令 git config --glo ...

  6. 【javaScript】js出现allocation size overflow以及字符串拼接优化

    字符串拼接长一点了,就出现了allocation size overflow异常! 先创建缓冲字符串数组,最后将数组转化为字符串 <script type="text/javascri ...

  7. Browser Security-css、javascript

    层叠样式表(css) 调用方式有三种: 1 用<style> 2 通过<link rel=stylesheet>,或者使用style参数. 3 XML(包括XHTML)可以通过 ...

  8. linux操作系统运行学习总结

    https://www.cnblogs.com/f-ck-need-u/p/10481466.html 操作系统学习总结 1.linux上面cpu通过上下文切换达到进程的不断切换,通过动态计算切换执行 ...

  9. error while loading shared libraries: libevent-2.1.so.6 的解决办法

    执行 memcached 启动命令时,报错,提示:error while loading shared libraries: libevent-2.1.so.6: cannot open shared ...

  10. C#中Equals和GetHashCode

    Equals和GetHashCode Equals每个实现都必须遵循以下约定: 自反性(Reflexive): x.equals(x)必须返回true. 对称性(Symmetric): x.equal ...