为Python包创建别名?
我有一个文件夹,叫做 Storage
,里面放满了名字很长、很难记的包,比如 mypackage-xxyyzzww
。当然,Storage
这个文件夹在我的 PYTHONPATH
里。因为这些包的名字太长了,我把它们都链接成了更简单的名字,比如 mypackage
。
现在,我不想依赖文件系统的符号链接来实现这个功能,所以我试着在 sys.path
和 sys.modules
上做了一些调整。目前我做的事情大概是这样的:
import imp
imp.load_package('mypackage', 'Storage/mypackage-xxyyzzww')
这样做到底有多糟糕?将来会不会出问题?有趣的是,文档里甚至没有提到 imp.load_package
这个函数。
补充一下:除了不依赖符号链接,我也不能再使用 PYTHONPATH
变量了。
3 个回答
包其实就是命名空间里的条目。你在命名路径的时候,最好用合法的Python变量名,不要用其他不合规的名字。
你可以给导入的模块起不同的名字,而不是使用 imp
。
import mypackage_xxyyzzww as mypackage
如果你在 Storage
文件夹里创建一个 __init__.py
文件,你可以添加上面几行代码,这样导入的时候会更方便。
Storage/__init__.py:
import mypackage_xxyyzzww as mypackage
import otherpackage_xxyyzzww as otherpackage
解释器:
>>> from Storage import mypackage, otherpackage
importlib 可能更合适,因为它使用了PEP302机制。
可以参考 DictImporter 的例子,但要重写 find_module
方法,以找到真实的文件名并把它存储在字典里,然后重写 load_module
方法,从找到的文件中获取代码。
一旦你创建了你的 Storage 模块,就不需要再使用 sys.path 了。
#from importlib import abc
import imp
import os
import sys
import logging
logging.basicConfig(level=logging.DEBUG)
dprint = logging.debug
class MyImporter(object):
def __init__(self,path):
self.path=path
self.names = {}
def find_module(self,fullname,path=None):
dprint("find_module({fullname},{path})".format(**locals()))
ml = imp.find_module(fullname,path)
dprint(repr(ml))
raise ImportError
def load_module(self,fullname):
dprint("load_module({fullname})".format(**locals()))
return imp.load_module(fullname)
raise ImportError
def load_storage( path, modname=None ):
if modname is None:
modname = os.path.basename(path)
mod = imp.new_module(modname)
sys.modules[modname] = mod
assert mod.__name__== modname
mod.__path__=[path]
#sys.meta_path.append(MyImporter(path))
mod.__loader__= MyImporter(path)
return mod
if __name__=="__main__":
load_storage("arbitrary-path-to-code/Storage")
from Storage import plain
from Storage import mypkg
然后当你 import Storage.mypackage
时,Python 会立即使用你的导入器,而不需要去查找 sys.path
。
这不行。上面的代码确实可以在 Storage 下导入普通模块,而不需要 Storage 在 sys.path 上,但 3.1 和 2.6 似乎都忽略了 PEP302 中提到的 loader 属性。如果我取消注释 sys.meta_path 这一行,3.1 会出现 StackOverflow 错误,而 2.6 会出现 ImportError 错误。唔……我现在没时间了,但可能会稍后再看看。