简体   繁体   English

在不同目录中创建共享部分包结构的多个Python模块

[英]Creating multiple Python modules in different directories that share a portion of the package structure

I'm working on a Django project that contains a single application. 我正在处理一个包含单个应用程序的Django项目。 The application will be released under the GPL so I want to develop it separately from the project - a personal site using the app. 该应用程序将根据GPL发布,因此我想与该项目分开开发-使用该应用程序的个人网站。 I'm attempting to use a package structure based on my domain name for both the project and the app, and that's where I'm running into problems. 我正在尝试将基于域名的包结构用于项目和应用程序,这就是我遇到问题的地方。

Here's my file structure (with __init__.py files where appropriate): 这是我的文件结构(在适当的地方带有__init__.py文件):

$HOME/django-sites/mydomain
$HOME/django-apps/mydomain/cms

And my PYTHONPATH: 而我的PYTHONPATH:

$HOME/django-sites:$HOME/django-apps

If I fire up a Python interpreter (from any directory on the filesystem) I can import classes from the site, but not the application. 如果我启动了Python解释器(从文件系统上的任何目录),则可以从站点而不是从应用程序导入类。 If I reverse the order of the two entries in the PYTHONPATH (apps first, then sites) I can import from the app but not the site. 如果我颠倒了PYTHONPATH中两个条目的顺序(首先是应用程序,然后是站点),则可以从应用程序而不是站点导入。

It looks like Python's only attempting to import from the first entry in the PYTHONPATH that contains the first portion of the package name. 看起来Python只是在尝试从PYTHONPATH中包含包名第一部分的第一个条目导入。 Is that correct? 那是对的吗? Is this expected behavior? 这是预期的行为吗? If so, I can only stick modules in package structures like domain/app1, domain/app2 if they live in the same directory structure - regardless of the PYTHONPATH. 如果是这样,我只能将模块粘贴在域/ app1,domain / app2之类的包结构中(如果它们位于相同的目录结构中),而与PYTHONPATH无关。

It's not show-stopper because I can rename the site, but it's much different than I was expecting. 这不是停下来的事,因为我可以重命名该站点,但是它与我期望的有很大不同。 The Python tutorial mentions __path__, but I have no idea how to use it: Python教程提到了__path__,但是我不知道如何使用它:

Packages support one more special attribute, __path__. 程序包支持另一个特殊属性__path__。 This is initialized to be a list containing the name of the directory holding the package's __init__.py before the code in that file is executed. 在执行该文件中的代码之前,将其初始化为包含目录的名称的列表,该目录包含软件包的__init__.py。 This variable can be modified; 这个变量可以修改; doing so affects future searches for modules and subpackages contained in the package. 这样做会影响以后对包中包含的模块和子包的搜索。

While this feature is not often needed, it can be used to extend the set of modules found in a package. 尽管通常不需要此功能,但可以使用它扩展软件包中的模块集。

Has anyone else come across this? 还有其他人遇到吗? Is there something I can do with __path__ to make this function as expected? 我可以用__path__做些什么使此功能按预期进行吗?

Here's how __path__ in a package's __init__.py is intended to be used: 打算使用包的__init__.py __path__的方法:

$ export PYTHONPATH=$HOME/django-sites
$ ls -d $HOME/django*
django-apps/  django-sites/ 
$ cat /tmp/django-sites/mydomain/__init__.py
import os

_components = __path__[0].split(os.path.sep)
if _components[-2] == 'django-sites':
  _components[-2] = 'django-apps'
  __path__.append(os.path.sep.join(_components))

$ python -c'import mydomain; import mydomain.foo'
foo here /tmp/django-apps/mydomain/foo.pyc
$ 

as you see, this makes the contents of django-apps/mydomain part of the mydomain package (whose __init__.py resides under django-sites/mydomain ) -- you don't need django-apps on sys.path for this purpose, either, if you use this approach. 如您所见,这使得django-apps/mydomain的内容成为mydomain软件包的一部分(其__init__.py位于django-sites/mydomain之下)-为此,您不需要sys.path上的django-apps ,如果您使用这种方法,也可以。

Whether this is a better arrangement than the one @defrex's answer suggests may be moot, but since a package's enriching its __path__ is a pretty important bit of a python programmer's bag of tools, I thought I had better illustrate it anyway;-). 这是否比@defrex的答案更好的安排尚无定论,但由于软件包充实了__path__是python程序员工具包中相当重要的一部分,所以我认为无论如何我还是要更好地说明它;-)。

Your analysis seems about right. 您的分析似乎正确。 The python path is used to locate modules to import; python路径用于定位要导入的模块; python imports the first one it finds. python导入它找到的第一个。 I'm not sure what you could do to work around this other than name your modules different things or put them in the same location in the search path. 除了将模块命名不同或将它们放在搜索路径中的相同位置之外,我不确定您可以做什么来解决此问题。

You basically have two modules named the same thing (mydomain). 基本上,您有两个名称相同的模块(mydomain)。 Why not set up your PYTHONPATH like so? 为什么不像这样设置您的PYTHONPATH?

$HOME/django-sites:$HOME/django-apps/mydomain

It would avoid your import problems. 这样可以避免您的导入问题。

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

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