Is there a framework equivalent to Guice (http://code.google.com/p/google-guice) for Python?
问题:
回答1:
I haven't used it, but the Spring Python framework is based on Spring and implements Inversion of Control.
There also appears to be a Guice in Python project: snake-guice
回答2:
Spring Python is an offshoot of the Java-based Spring Framework and Spring Security, targeted for Python. This project currently contains the following features:
- Inversion Of Control (dependency injection) - use either classic XML, or the python @Object decorator (similar to the Spring JavaConfig subproject) to wire things together. While the @Object format isn't identical to the Guice style (centralized wiring vs. wiring information in each class), it is a valuable way to wire your python app.
- Aspect-oriented Programming - apply interceptors in a horizontal programming paradigm (instead of vertical OOP inheritance) for things like transactions, security, and caching.
- DatabaseTemplate - Reading from the database requires a monotonous cycle of opening cursors, reading rows, and closing cursors, along with exception handlers. With this template class, all you need is the SQL query and row-handling function. Spring Python does the rest.
- Database Transactions - Wrapping multiple database calls with transactions can make your code hard to read. This module provides multiple ways to define transactions without making things complicated.
- Security - Plugin security interceptors to lock down access to your methods, utilizing both authentication and domain authorization.
- Remoting - It is easy to convert your local application into a distributed one. If you have already built your client and server pieces using the IoC container, then going from local to distributed is just a configuration change.
- Samples - to help demonstrate various features of Spring Python, some sample applications have been created:
- PetClinic - Spring Framework's sample web app has been rebuilt from the ground up using python web containers including: CherryPy. Go check it out for an example of how to use this framework. (NOTE: Other python web frameworks will be added to this list in the future).
- Spring Wiki - Wikis are powerful ways to store and manage content, so we created a simple one as a demo!
- Spring Bot - Use Spring Python to build a tiny bot to manage the IRC channel of your open source project.
回答3:
I like this simple and neat framework.
http://pypi.python.org/pypi/injector/
Dependency injection as a formal pattern is less useful in Python than in other languages, primarily due to its support for keyword arguments, the ease with which objects can be mocked, and its dynamic nature.
That said, a framework for assisting in this process can remove a lot of boiler-plate from larger applications. That's where Injector can help. It automatically and transitively provides keyword arguments with their values. As an added benefit, Injector encourages nicely compartmentalized code through the use of Module s.
While being inspired by Guice, it does not slavishly replicate its API. Providing a Pythonic API trumps faithfulness.
回答4:
As an alternative to monkeypatching, I like DI. A nascent project such as http://code.google.com/p/snake-guice/ may fit the bill.
Or see the blog post Dependency Injection in Python by Dennis Kempin (Aug '08).
回答5:
pinject (https://github.com/google/pinject) is a newer alternative. It seems to be maintained by Google and follows a similar pattern to Guice (https://code.google.com/p/google-guice/), it's Java counterpart.
回答6:
Besides that:
- Zope component architekture
- pyContainer
回答7:
There is a somewhat Guicey python-inject project. It's quite active, and a LOT less code then Spring-python, but then again, I haven't found a reason to use it yet.
回答8:
If you just want to do dependency injection in Python, you don't need a framework. Have a look at Dependency Injection the Python Way. It's really quick and easy, and only c. 50 lines of code.
回答9:
Here is a small example for a dependency injection container that does constructor injection based on the constructor argument names:
http://code.activestate.com/recipes/576609-non-invasive-dependency-injection/
回答10:
Will leave my 5 cents here :)
https://pypi.python.org/pypi/dependency_injector
"""Pythonic way for Dependency Injection."""
from dependency_injector import providers
from dependency_injector import injections
@providers.DelegatedCallable
def get_user_info(user_id):
"""Return user info."""
raise NotImplementedError()
@providers.Factory
@injections.inject(get_user_info=get_user_info)
class AuthComponent(object):
"""Some authentication component."""
def __init__(self, get_user_info):
"""Initializer."""
self.get_user_info = get_user_info
def authenticate_user(self, token):
"""Authenticate user by token."""
user_info = self.get_user_info(user_id=token + '1')
return user_info
print AuthComponent
print get_user_info
@providers.override(get_user_info)
@providers.DelegatedCallable
def get_user_info(user_id):
"""Return user info."""
return {'user_id': user_id}
print AuthComponent().authenticate_user(token='abc')
# {'user_id': 'abc1'}
UPDATED
Some time passed and Dependency Injector is a bit different now. It's better to start from Dependency Injector GitHub page for getting actual examples - https://github.com/ets-labs/python-dependency-injector
回答11:
I made a lib to do this https://github.com/ettoreleandrotognoli/python-cdi I hope that helps
It's available on pypi: https://pypi.python.org/pypi/pycdi
With it you can make injections with python2
import logging
from logging import Logger
from pycdi import Inject, Singleton, Producer
from pycdi.shortcuts import call
@Producer(str, _context='app_name')
def get_app_name():
return 'PyCDI'
@Singleton(produce_type=Logger)
@Inject(app_name=str, _context='app_name')
def get_logger(app_name):
return logging.getLogger(app_name)
@Inject(name=(str, 'app_name'), logger=Logger)
def main(name, logger):
logger.info('I\'m starting...')
print('Hello World!!!\nI\'m a example of %s' % name)
logger.debug('I\'m finishing...')
call(main)
And using type hints from python3
import logging
from logging import Logger
from pycdi import Inject, Singleton, Producer
from pycdi.shortcuts import call
@Producer(_context='app_name')
def get_app_name() -> str:
return 'PyCDI'
@Singleton()
@Inject(logger_name='app_name')
def get_logger(logger_name: str) -> Logger:
return logging.getLogger(logger_name)
@Inject(name='app_name')
def main(name: str, logger: Logger):
logger.info('I\'m starting...')
print('Hello World!!!\nI\'m a example of %s' % name)
logger.debug('I\'m finishing...')
call(main)
回答12:
If you prefer a really tiny solution there's a little function, it is just a dependency setter.
https://github.com/liuggio/Ultra-Lightweight-Dependency-Injector-Python
回答13:
There's dyject (http://dyject.com), a lightweight framework for both Python 2 and Python 3 that uses the built-in ConfigParser
回答14:
If you want a guice like (the new new like they say), I recently made something close in Python 3 that best suited my simple needs for a side project.
All you need is an @inject on a method (__init__ included of course). The rest is done through annotations.
from py3njection import inject
from some_package import ClassToInject
class Demo:
@inject
def __init__(self, object_to_use: ClassToInject):
self.dependency = object_to_use
demo = Demo()
https://pypi.python.org/pypi/py3njection
回答15:
I recently released a neat (IMHO) micro library for DI in python:
https://github.com/suned/serum
回答16:
Simpler than a framework is the @autowired
decorator.
This decorator provides clean dependency injection and lazy initialization support.
It turns code like this:
def __init__(self, *, model: Model = None, service: Service = None):
if model is None:
model = Model()
if service is None:
service = Service()
self.model = model
self.service = service
# actual code
into this:
@autowired
def __init__(self, *, model: Model, service: Service):
self.model = model
self.service = service
# actual code
It isn't a framework, so you there is zero setup and enforced workflows, though it doesn't provide injection contexts manipulation.
Disclosure: I'm the project maintainer.