思路:

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

# -*- coding:utf-8 -*-
import os
class BeanFactory:
"""
Python版控制反转
context: 存储bean的名字和对应的类或者值的字典
allowRepalce: 是否允许替换已经注入的bean
""" def __init__(self,allowReplace=False):
"""构造函数
allowReplace:是否允许替换已经注入的bean
"""
self.context = {}
self.allowReplace = allowReplace
def setBean(self,beanName,resource,*args,**kwargs):
if not self.allowReplace:
assert not beanName in self.context,"该BeanFactory不允许重复注入%r,请修改beanName" % beanName
def call():
"""定义一个函数闭包,如果注入的resource是可调用类型,就将*args和**kwargs传入并调用该函数,然后将返回值返回
如果是一个不可调用对象,就直接返回
"""
if callable(resource):
return resource(*args,**kwargs)
else:
return resource
#将call闭包与beanName建立映射
self.context[beanName]=call
def __getitem__(self,beanName):
"""重载__getitem__方法,使得BeanFactory支持使用[]获取beanName对应的注册的资源
"""
try:
# 从context字典中取出beanName对应的资源
resource = self.context[beanName]
except KeyError:
raise KeyError("%r 未注册" % beanName)
# 返回闭包函数调用后的结果
return resource() AppFactory = BeanFactory() def NoAssertion(obj): return True def IsInstanceOf(*classes):
def test(obj): return isinstance(obj, classes)
return test def HasAttributes(*attributes):
def test(obj):
for each in attributes:
if not hasattr(obj, each): return False
return True
return test def HasMethods(*methods):
def test(obj):
for each in methods:
try:
attr = getattr(obj, each)
except AttributeError:
return False
if not callable(attr): return False
return True
return test #
#
#Descriptor就是一类实现了__get__(), __set__(), __delete__()方法的对象
#若一个类的成员是descriptor,在访问它的值时是通过__get__()函数访问的
#用这个特性实现在访问一个类的成员时自动到BeanFactory中请求对应的资源 class RequiredResource(object):
def __init__(self, beanName, assertion=NoAssertion):
self.beanName = beanName
self.assertion = assertion
def __get__(self, obj, T):#每次访问descriptor时都会调用__get__方法
return self.result # <-- .操作符会自动调用__getattr__
def __getattr__(self, name):
assert name == 'result', "Unexpected attribute request other then 'result'"
self.result = self.Request()
return self.result
def Request(self):
obj = AppFactory[self.beanName]
assert self.assertion(obj), \
"The value %r of %r does not match the specified criteria" \
% (obj, self.feature)
return obj class Component(object):
"Symbolic base class for components"
class Bar(Component):
# HasMethods是一个闭包函数,传入RequiredResource后用于检查'Console'
# 对应的注册的那个feature是否有'WriteLine'方法
# IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
# 检查注册的'AppTitle'对应资源是否是一个字符串
# IsinstanceOf(str) 是一个闭包,传入RequiredResource后会被调用,用于
# 检查'CurrentUser'对应的资源是否是一个字符串 # RequiredFeatuire是desciptor,每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。 con = RequiredResource('Console', HasMethods('WriteLine'))
title = RequiredResource('AppTitle', IsInstanceOf(str))
user = RequiredResource('CurrentUser', IsInstanceOf(str))
flist = RequiredResource('show_dir',IsInstanceOf(list))
def __init__(self):
self.X = 0
def PrintYourself(self):
self.con.WriteLine('-- Bar instance --')
# title 由 RequiredResource('AppTitle',IsInstanceOf(str))生成
#'AppTitle'对应的值在__main__代码块注册了一个值
self.con.WriteLine('Title: %s' % self.title)
self.con.WriteLine('User: %s' % self.user)
self.con.WriteLine('X: %d' % self.X)
for f in self.flist:
self.con.WriteLine(f) class BetterConsole(Component):
def __init__(self, prefix=''):
self.prefix = prefix
def WriteLine(self, s):
lines = s.split('\n')
for line in lines:
if line:
print(self.prefix, line)
else:
print def GetCurrentUser():
return os.getenv('USERNAME') or 'Some User' # USERNAME is platform-specific
def ShowDir():
return os.listdir() if __name__ == '__main__':
print('\n*** IoC Demo ***')
#Provide(feature,provider,*args,**kwargs) feature是要生成的对象的父类类型 provider是要注入的子类或者值
AppFactory.setBean('AppTitle', 'Inversion of Control ...\n\n... The Python Way')
AppFactory.setBean('CurrentUser', GetCurrentUser)
AppFactory.setBean('Console', BetterConsole, prefix='-->') # <-- transient lifestyle
AppFactory.setBean('show_dir',ShowDir) bar = Bar()
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. TypeScript 源码详细解读(1)总览

    TypeScript 由微软在 2012 年 10 月首发,经过几年的发展,已经成为国内外很多前端团队的首选编程语言.前端三大框架中的 Angular 和 Vue 3 也都改用了 TypeScript ...

  2. Alodi:环境创建从未如此简单

    一个满足你各种想象的快速方便生成临时环境的系统 在『Alodi:为了保密我开发了一个系统』文章中有讲到我们开发了一个系统用来快速生成临时测试环境,短短三个月已有数百个环境被创建,简化了工作,节省了时间 ...

  3. TensorFlow——学习率衰减的使用方法

    在TensorFlow的优化器中, 都要设置学习率.学习率是在精度和速度之间找到一个平衡: 学习率太大,训练的速度会有提升,但是结果的精度不够,而且还可能导致不能收敛出现震荡的情况. 学习率太小,精度 ...

  4. 如何应用threejs实现立方体每个面用图片替换

    var geometry = new THREE.BoxGeometry(200, 200, 200);var materialsbg = []; for (var i = 0; i < geo ...

  5. 数字任意组合 - gcd

    链接:https://www.nowcoder.com/acm/contest/160/A来源:牛客网 题目描述有一个计数器,计数器的初始值为0,每次操作你可以把计数器的值加上a1,a2,...,an ...

  6. poj 2689 区间素数筛

    The branch of mathematics called number theory is about properties of numbers. One of the areas that ...

  7. Spring Boot 事务的使用

    Spring Boot 使用事务非常简单,首先使用注解 @EnableTransactionManagement 开启事务支持后,然后在访问数据库的Service方法上添加注解 @Transactio ...

  8. 9.Super详解

    super注意点: surper()是调用父类的构造方法,而且必须在构造方法的第一个 super必须只能出现在子类的方法或者构造方法中! super()和this()不能同时调用构造方法! Vs th ...

  9. ugui制作伸缩菜单

    制作一个类似与这种格式的菜单,可以伸缩滑动的.今天正好项目需要用到类似功能,所以尝试了一下,做出如下的效果 虽然只是一个思路,但是可以扩展.声明一个object物体,为but,通过GetCompone ...

  10. 每天玩转3分钟 MyBatis-Plus - 6. select 用法

    每天玩转3分钟 MyBatis-Plus - 1. 配置环境 每天玩转3分钟 MyBatis-Plus - 2. 普通查询 每天玩转3分钟 MyBatis-Plus - 3. 高级查询(一) 每天玩转 ...