Python:在个人Python包中包含第三方库

时间:2016-03-07 16:52:15

标签: python python-2.7 path environment-variables pythonpath

我想在我的Python脚本文件夹中包含第三方库以将其全部分发给我(我对分发许可证感到厌烦,这个库可以分发)。这是为了避免将库安装在另一台机器上。

说我有一个脚本(my_script.py),它调用这个外部库。我试图将这个库从Python目录的site-packages子目录复制到我拥有文件的目录中,但似乎还不够(我认为原因在于此库的__init__.py可能需要该文件夹位于PYTHONPATH)。

my_script.py中插入一些代码行以临时将其文件夹附加到sys.path以使所有内容正常工作是否合理?

例如,如果我有类似的结构:

Main_folder
my_script.py
  /external_lib_folder
   __init__.py
   external_lib.py

external_lib_folder是我从网站包中复制并插入我的Main_folder的外部库,如果我在my_script.py中写下这些行(例如),会没用吗?

import os,sys
main_dir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(main_dir)

修改

我最终选择了sys.path.append解决方案。我将这些行添加到my_script.py

import os, sys

# temporarily appends the folder containing this file into sys.path
main_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),'functions')
sys.path.append(main_dir)

无论如何,我选择在我的问题中插入这个作为编辑并接受Torxed的答案,因为他花了很多时间帮助我(当然因为他的解决方案也有效)。

2 个答案:

答案 0 :(得分:5)

Python3

import importlib.machinery, imp
namespace = 'external_lib'
loader = importlib.machinery.SourceFileLoader(namespace, '/home/user/external_lib_folder/external_lib.py')
external_lib = loader.load_module(namespace)

# How to use it:
external_lib.function(data_or_something)

这将是在Python 3中加载自定义路径的理想方式。
不完全确定这是你想要的,但它足以发布添加到sys.path的替代方案。

Python2

在python 2中你可以这样做(如果我没有弄错,因为我使用旧版本的Python已经有一段时间了):

external_lib = __import__('external_lib_folder')

但是,这需要您在悲伤脚本中保留__init__.py和正确的功能声明,否则会失败。
**同样重要的是,您尝试导入的文件夹名称与sad文件夹中的__init__.py脚本尝试从其导入其子库的名称相同例如geopy将是:

./myscript.py
./geopy/
./geopy/__init__.py
./geopy/compat.py
...

myscript.py的代码如下所示:

handle = __import__('geopy')
print(handle)

哪会产生以下输出:

[user@machine project]$ python2 myscript.py 
<module 'geopy' from '/home/user/project/geopy/__init__.pyc'>

[user@machine project]$ tree -L 2
.
├── geopy
│   ├── compat.py
│   ├── compat.pyc
│   ├── distance.py
│   ├── distance.pyc
│   ├── exc.py
│   ├── exc.pyc
│   ├── format.py
│   ├── format.pyc
│   ├── geocoders
│   ├── __init__.py
│   ├── __init__.pyc
│   ├── location.py
│   ├── location.pyc
│   ├── point.py
│   ├── point.pyc
│   ├── units.py
│   ├── units.pyc
│   ├── util.py
│   ├── util.pyc
│   └── version.pyc
└── myscript.py

2 directories, 20 files

因为在__init__.py的{​​{1}}中,它定义了geopy等导入需要名称空间或from geopy.point import Point文件夹的导入。 /> 在那里,您无法将文件夹重命名为geopy,并在其中放置一个名为functions的文件夹,因为它不会起作用,也不会将geopy的内容放入其中一个名为geopy的文件夹,因为它不是functions所寻找的内容。

将路径添加到geopy(Py2 + 3)

如评论中所述,您还可以在导入之前将文件夹添加到sys.path变量。

sys.path

为什么这是一个坏主意:它会起作用,并被许多人使用。可能出现的问题是,可能替换系统功能,或者如果您不小心从哪里导入内容,可能会从其他文件夹加载其他模块。大多数情况下都可以使用import sys sys.path.insert(0, './functions') import geopy print(geopy) >>> <module 'geopy' from './functions/geopy/__init__.pyc'> ,并确保您确实希望冒险使用&#34; shady&#34;替换系统内置插件。路径名称。

答案 1 :(得分:1)

你的建议是不好的做法,这是一种薄弱的安排。最好的解决方案(这也很容易)是正确打包并添加显式依赖,如下所示:

来自setuptools导入设置

setup(name='funniest',
      version='0.1',
      description='The funniest joke in the world',
      url='http://github.com/storborg/funniest',
      author='Flying Circus',
      author_email='flyingcircus@example.com',
      license='MIT',
      packages=['funniest'],
      install_requires=[
          'markdown',
      ],
      zip_safe=False)

如果第三方库处于pipy状态,这将有效。如果不是,请使用:

setup(
    ...
    dependency_links=['http://github.com/user/repo/tarball/master#egg=package-1.0']
    ...
)

(有关包装,请参阅this explanation。)