简体   繁体   English

Python:如何使用包含在包外的修改版本覆盖包中的一个模块?

[英]Python: How can I override one module in a package with a modified version that lives outside the package?

I would like to update one module in a python package with my own version of the module, with the following conditions: 我想用我自己的模块版本更新python包中的一个模块,具有以下条件:

  • I want my updated module to live outside of the original package (either because I don't have access to the package source, or because I want to keep my local modifications in a separate repo, etc). 我希望我更新的模块存在于原始包之外(因为我无法访问包源,或者因为我想将我的本地修改保存在单独的repo中等)。
  • I want import statements that refer to original package/module to resolve to my local module 我想要引用原始包/模块的import语句来解析我的本地模块

Here's an example of what I'd like to do using specifics from django, because that's where this problem has arisen for me: 这是我想用django的细节做的一个例子,因为这就是我出现这个问题的地方:

Say this is my project structure 说这是我的项目结构

django/
  ... the original, unadulterated django package ...
local_django/
  conf/
    settings.py
myproject/
  __init__.py
  myapp/
    myfile.py

And then in myfile.py 然后在myfile.py中

# These imports should fetch modules from the original django package
from django import models
from django.core.urlresolvers import reverse

# I would like this following import statement to grab a custom version of settings 
# that I define in local_django/conf/settings.py 
from django.conf import settings

def foo():
  return settings.some_setting

Can I do some magic with the __import__ statement in myproject/__init__.py to accomplish this? 我可以使用myproject/__init__.py__import__语句来完成这个吗? Is there a more "pythonic" way to achieve this? 是否有更“pythonic”的方法来实现这一目标?

Update - Why do I want to do this 更新 - 为什么我要这样做

Here's the scenario where I think this makes sense. 这是我觉得这很有意义的场景。

  • I am launching a django powered website on a server that has django pre-installed globally. 我正在全球预装django的服务器上启动一个django支持的网站。 I can't modify the actual django source, in this case. 在这种情况下,我无法修改实际的django源。
  • My django project uses 3rd party reusable apps, and I don't want to change imports in all of those apps to import, for instance mycustomsettings . 我的Django项目使用第三方应用程序重复使用,而且我也不想改变imports在所有这些应用的导入,例如mycustomsettings I want to leave the reusable apps blissfully ignorant that I have changed the implementation of django.conf.settings. 我想让可重用的应用程序幸福地无知我已经改变了django.conf.settings的实现。

Just set the entry in sys.modules before anything else imports it: 只需在其他任何内容导入之前在sys.modules中设置条目:

import sys
import myreplacement
sys.modules["original"] = myreplacement

Then, when someone does "import original", they'll get your version instead. 然后,当某人“导入原始”时,他们将获得您的版本。

If you want to replace a submodule, you can do it like this: 如果要替换子模块,可以这样做:

import sys
import thepackage
sys.modules["thepackage"].submodule = myreplacement
sys.modules["thepackage.submodule"] = myreplacement

Then "from thepackage import submodule" or "import thepackage.submodule" will give "myreplacement". 然后“from thepackage import submodule”或“import thepackage.submodule”将给出“myreplacement”。

Perhaps you can make use of the django-values project, which provides a dbsettings app, which ... 也许你可以使用django-values项目,它提供了一个dbsettings应用程序,它...

... allows placeholders for settings to be defined in Python, while their values are set by staff using an editor while the server is up and running. ...允许在Python中定义设置占位符,而在服务器启动和运行时,工作人员使用编辑器设置它们的值。 Many value types are available, and they each map to a native Python type, so model methods and other Python code can access them as standard class attributes. 许多值类型都可用,它们每个都映射到本机Python类型,因此模型方法和其他Python代码可以作为标准类属性访问它们。

Much effort has also been made to reduce the overhead of this feature, so that the database is only queried once during each server restart, and only updated when the values themselves are updated. 为减少此功能的开销也付出了很多努力,因此在每次服务器重新启动期间仅查询数据库一次,并且仅在更新值本身时更新。

NOTE: This is not intended as a replacement for settings.py. 注意:这不是用来替代settings.py。 This is designed for values that are expected to change based on the needs of the site or its users, so that such changes don't require so much as a restart. 这是针对预期会根据站点或其用户的需求而更改的值而设计的,因此这些更改不需要重启。 settings.py is still the place to go for settings that will only vary by project. settings.py仍然是设置的地方,只会因项目而异。

One way of looking at it is that settings.py is for those things that are required from a technical perspective (database connections, installed applications, avaialble middleware, etc), while dbsettings is best for those things that are required due to organizational policy (quotas, minimum requirements, etc). 查看它的一种方法是settings.py用于从技术角度(数据库连接,已安装的应用程序,可用中间件等)所需的那些东西,而dbsettings最适合那些由于组织策略而需要的东西(配额,最低要求等)。 That way, programmers maintain the technical requirements, while administrators maintain organizational policy. 这样,程序员可以维护技术要求,而管理员则可以维护组织策略。

The project is by Marty Alchin (who wrote the Pro Django book) and does not require any changes to Django code - it's a standard Django application. 该项目由Marty Alchin(编写Pro Django书籍)并且不需要对Django代码进行任何更改 - 它是标准的Django应用程序。

import local_django.conf
import django.conf
django.conf.settings = local_django.conf.settings

Modules are singletons. 模块是单身人士。 Modules are only initialized/loaded once. 模块仅初始化/加载一次。 You need to do this before importing the modules that use django.conf.settings for them to pick up the change. 在导入使用django.conf.settings的模块之前,您需要执行此操作以获取更改。

Read this link for more info to see if there is a more standard approach with django as the docs specifically recommend against doing it the way I show above for the settings object. 阅读此链接以获取更多信息,以了解是否有更标准的方法使用django,因为文档特别建议不要按照我在上面显示的设置对象的方式进行操作。 http://docs.djangoproject.com/en/dev/topics/settings/ It should work fine for other objects and modules. http://docs.djangoproject.com/en/dev/topics/settings/它应该适用于其他对象和模块。

I was introduced to this about two or three days ago, but one technique of doing this very thing is to use a Python Virtual Environment. 大约两三天前,我被介绍过这个,但是这样做的一种方法是使用Python虚拟环境。 This allows you to designate the version of Python you are using, as well as the versions of the modules you want to install, and to be able to swap between different versions and projects relatively easy; 这允许您指定您正在使用的Python版本,以及您要安装的模块的版本,并且能够相对容易地在不同版本和项目之间进行交换; it also allows you to install a Python system where you might not otherwise have the permissions needed to install something. 它还允许您安装Python系统,否则您可能无法获得安装所需的权限。

You can learn more about virtualenv from virtualenv info . 您可以从virtualenv info了解更多关于virtualenv的信息

There's also a "virtualenvwrapper" package, that provides tools to more easily swap between environments. 还有一个“virtualenvwrapper”软件包,它提供了更容易在环境之间交换的工具。

Admittedly, I don't have much experience with this, and I found this question in an attempt to understand how to override a Python Standard Library with a custom-built version--so it's not perfect. 不可否认,我对此没有多少经验,我发现这个问题试图了解如何使用自定义版本覆盖Python标准库 - 所以它并不完美。 But I am nonetheless impressed with its ability to specify what you install, down to the version of an individual module! 但是我对它能够指定你安装的内容印象深刻,直到单个模块的版本!

In this particular case, 'twould be best to follow the prescribed mechanism for creating your own settings . 在这种特殊情况下,'最好遵循规定的机制来创建自己的设置

In the general case, mucking with imports is guaranteed to confuse your reader (who may be you). 在一般情况下,使用进口产品可能会使您的读者(可能是您)感到困惑。 The pythonic way to alter class behavior is to sub-class and override. 改变类行为的pythonic方法是sub-class和override。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM