标签归档:python-import

如何在同一目录或子目录中导入类?

问题:如何在同一目录或子目录中导入类?

我有一个存储所有.py文件的目录。

bin/
   main.py
   user.py # where class User resides
   dir.py # where class Dir resides

我想从使用类user.pydir.pymain.py
如何将这些Python类导入main.py
此外,User如果user.py位于子目录中,如何导入类?

bin/
    dir.py
    main.py
    usr/
        user.py

I have a directory that stores all the .py files.

bin/
   main.py
   user.py # where class User resides
   dir.py # where class Dir resides

I want to use classes from user.py and dir.py in main.py.
How can I import these Python classes into main.py?
Furthermore, how can I import class User if user.py is in a sub directory?

bin/
    dir.py
    main.py
    usr/
        user.py

回答 0

Python 2

在与文件__init__.py相同的目录中创建一个名为的空文件。这将向Python表示“可以从此目录导入”。

然后做…

from user import User
from dir import Dir

如果文件位于子目录中,则同样适用-也将一个__init__.py放在子目录中,然后使用带点标记的常规import语句。对于每个级别的目录,您都需要添加到导入路径。

bin/
    main.py
    classes/
        user.py
        dir.py

因此,如果目录被命名为“ classes”,则可以这样做:

from classes.user import User
from classes.dir import Dir

Python 3

与上一个相同,但是.如果不使用子目录,则在模块名称前添加一个:

from .user import User
from .dir import Dir

Python 2

Make an empty file called __init__.py in the same directory as the files. That will signify to Python that it’s “ok to import from this directory”.

Then just do…

from user import User
from dir import Dir

The same holds true if the files are in a subdirectory – put an __init__.py in the subdirectory as well, and then use regular import statements, with dot notation. For each level of directory, you need to add to the import path.

bin/
    main.py
    classes/
        user.py
        dir.py

So if the directory was named “classes”, then you’d do this:

from classes.user import User
from classes.dir import Dir

Python 3

Same as previous, but prefix the module name with a . if not using a subdirectory:

from .user import User
from .dir import Dir

回答 1

我刚刚了解到(感谢martineau的评论),为了从同一目录中的文件导入类,您现在应该使用Python 3编写代码:

from .user import User
from .dir import Dir

I just learned (thanks to martineau’s comment) that, in order to import classes from files within the same directory, you would now write in Python 3:

from .user import User
from .dir import Dir

回答 2

在您的main.py

from user import Class

Class您要导入的类的名称在哪里。

如果要调用的方法Class,则可以使用以下方法调用它:

Class.method

请注意,__init__.py同一目录中应该有一个空文件。

In your main.py:

from user import Class

where Class is the name of the class you want to import.

If you want to call a method of Class, you can call it using:

Class.method

Note that there should be an empty __init__.py file in the same directory.


回答 3

如果不想将函数和类与模块混合使用,则可以导入模块并通过其名称进行访问

import util # imports util.py

util.clean()
util.setup(4)

或者您可以将函数和类导入代码中

from util import clean, setup
clean()
setup(4)

您可以使用wildchar *将模块中的所有内容导入代码

from util import *
clean()
setup(4)

You can import the module and have access through its name if you don’t want to mix functions and classes with yours

import util # imports util.py

util.clean()
util.setup(4)

or you can import the functions and classes to your code

from util import clean, setup
clean()
setup(4)

you can use wildchar * to import everything in that module to your code

from util import *
clean()
setup(4)

回答 4

在python3,__init__.py不再需要。如果控制台的当前目录是python脚本所在的目录,则一切正常

import user

但是,如果从不包含的其他目录中调用,则此方法将无效user.py
在这种情况下,请使用

from . import user

即使您要导入整个文件,而不是仅从那里导入一个类,也可以使用该方法。

In python3, __init__.py is no longer necessary. If the current directory of the console is the directory where the python script is located, everything works fine with

import user

However, this won’t work if called from a different directory, which does not contain user.py.
In that case, use

from . import user

This works even if you want to import the whole file instead of just a class from there.


回答 5

为了更容易理解:

第1步:转到一个目录,其中将包含所有目录

$ cd /var/tmp

步骤2:现在让我们制作一个class1.py文件,其文件名为Class1,并带有一些代码

$ cat > class1.py <<\EOF
class Class1:
    OKBLUE = '\033[94m'
    ENDC = '\033[0m'
    OK = OKBLUE + "[Class1 OK]: " + ENDC
EOF

步骤3:现在让我们制作一个class2.py文件,其文件名为Class2并带有一些代码

$ cat > class2.py <<\EOF
class Class2:
    OKBLUE = '\033[94m'
    ENDC = '\033[0m'
    OK = OKBLUE + "[Class2 OK]: " + ENDC
EOF

步骤4:现在让一个main.py可以执行一次以使用来自2个不同文件的Class1和Class2

$ cat > main.py <<\EOF
"""this is how we are actually calling class1.py and  from that file loading Class1"""
from class1 import Class1 
"""this is how we are actually calling class2.py and  from that file loading Class2"""
from class2 import Class2

print Class1.OK
print Class2.OK
EOF

步骤5:运行程序

$ python main.py

输出将是

[Class1 OK]: 
[Class2 OK]:

To make it more simple to understand:

Step 1: lets go to one directory, where all will be included

$ cd /var/tmp

Step 2: now lets make a class1.py file which has a class name Class1 with some code

$ cat > class1.py <<\EOF
class Class1:
    OKBLUE = '\033[94m'
    ENDC = '\033[0m'
    OK = OKBLUE + "[Class1 OK]: " + ENDC
EOF

Step 3: now lets make a class2.py file which has a class name Class2 with some code

$ cat > class2.py <<\EOF
class Class2:
    OKBLUE = '\033[94m'
    ENDC = '\033[0m'
    OK = OKBLUE + "[Class2 OK]: " + ENDC
EOF

Step 4: now lets make one main.py which will be execute once to use Class1 and Class2 from 2 different files

$ cat > main.py <<\EOF
"""this is how we are actually calling class1.py and  from that file loading Class1"""
from class1 import Class1 
"""this is how we are actually calling class2.py and  from that file loading Class2"""
from class2 import Class2

print Class1.OK
print Class2.OK
EOF

Step 5: Run the program

$ python main.py

The output would be

[Class1 OK]: 
[Class2 OK]:

回答 6

Python 3


一样directory

导入文件:log.py

导入类:SampleApp()

import log
if __name__ == "__main__":
    app = log.SampleApp()
    app.mainloop()

要么

目录是basic

导入文件:log.py

导入类:SampleApp()

from basic import log
if __name__ == "__main__":
    app = log.SampleApp()
    app.mainloop()

Python 3


Same directory.

import file:log.py

import class: SampleApp().

import log
if __name__ == "__main__":
    app = log.SampleApp()
    app.mainloop()

or

directory is basic.

import in file: log.py.

import class: SampleApp().

from basic import log
if __name__ == "__main__":
    app = log.SampleApp()
    app.mainloop()

回答 7

from user import User 
from dir import Dir 
from user import User 
from dir import Dir 

回答 8

如果user.py和dir.py不包含类,则

from .user import User
from .dir import Dir

不管用。然后,您应该导入为

from . import user
from . import dir

If user.py and dir.py are not including classes then

from .user import User
from .dir import Dir

is not working. You should then import as

from . import user
from . import dir

回答 9

我不确定为什么可以使用Pycharm build from file_in_same_dir import class_name

IDE对此有所抱怨,但似乎仍然可以使用。我正在使用Python 3.7

I’m not sure why this work but using Pycharm build from file_in_same_dir import class_name

The IDE complained about it but it seems it still worked. I’m using Python 3.7


回答 10

太简单了,创建一个文件__init__.py为classes目录,然后将其导入到脚本中,如下所示(全部导入)

from classes.myscript import *

仅导入选定的类

from classes.myscript import User
from classes.myscript import Dir

Just too brief, Create a file __init__.py is classes directory and then import it to your script like following (Import all case)

from classes.myscript import *

Import selected classes only

from classes.myscript import User
from classes.myscript import Dir

回答 11

从同一目录导入

from . import the_file_you_want_to_import 

从子目录导入目录应该包含

初始化 .py

档案以外的档案,然后

从目录导入your_file

to import from the same directory

from . import the_file_you_want_to_import 

to import from sub directory the directory should contain

init.py

file other than you files then

from directory import your_file


回答 12

Python3

采用

from .user import User inside dir.py file

use from class.dir import Dir inside main.py
or from class.usr import User inside main.py

像这样

Python3

use

from .user import User inside dir.py file

and

use from class.dir import Dir inside main.py
or from class.usr import User inside main.py

like so


从其他文件夹导入文件

问题:从其他文件夹导入文件

我有以下文件夹结构。

application/app/folder/file.py

我想从位于另一个Python文件中的file.py导入一些功能

application/app2/some_folder/some_file.py

我试过了

from application.app.folder.file import func_name

和其他一些尝试,但到目前为止,我无法正确导入。我怎样才能做到这一点?

I have the following folder structure.

application/app/folder/file.py

and I want to import some functions from file.py in another Python file which resides in

application/app2/some_folder/some_file.py

I’ve tried

from application.app.folder.file import func_name

and some other various attempts but so far I couldn’t manage to import properly. How can I do this?


回答 0

默认情况下,您不能这样做。导入文件时,Python仅搜索当前目录,入口点脚本运行sys.path所在的目录,并且包括诸如软件包安装目录之类的位置(实际上比这稍微复杂一点,但这涵盖了大多数情况) 。

但是,您可以在运行时添加到Python路径:

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

By default, you can’t. When importing a file, Python only searches the current directory, the directory that the entry-point script is running from, and sys.path which includes locations such as the package installation directory (it’s actually a little more complex than this, but this covers most cases).

However, you can add to the Python path at runtime:

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

回答 1

没错:

from application.app.folder.file import func_name

只要确保folder还包含一个__init__.py,就可以将其作为软件包包含在内。不知道为什么其他答案在谈论PYTHONPATH

Nothing wrong with:

from application.app.folder.file import func_name

Just make sure folder also contains an __init__.py, this allows it to be included as a package. Not sure why the other answers talk about PYTHONPATH.


回答 2

当模块处于并行位置时,如下所示:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

该简写使一个模块对另一模块可见:

import sys
sys.path.append('../')

When modules are in parallel locations, as in the question:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

This shorthand makes one module visible to the other:

import sys
sys.path.append('../')

回答 3

首先在name-file.py中导入sys

 import sys

第二个将文件夹路径附加到name-file.py中

sys.path.insert(0, '/the/folder/path/name-package/')

第三步在子目录中创建一个名为__ init __.py的空白文件(这告诉Python它是一个包)

  • 名称文件
  • 名称包
    • __初始化__.py
    • 名称模块

第四次将模块导入name-file.py文件夹内

from name-package import name-module

First import sys in name-file.py

 import sys

Second append the folder path in name-file.py

sys.path.insert(0, '/the/folder/path/name-package/')

Third Make a blank file called __ init __.py in your subdirectory (this tells Python it is a package)

  • name-file.py
  • name-package
    • __ init __.py
    • name-module.py

Fourth import the module inside the folder in name-file.py

from name-package import name-module

回答 4

我认为,一种临时方法是使用文档中所述的环境变量PYTHONPATHPython2Python3

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

I think an ad-hoc way would be to use the environment variable PYTHONPATH as described in the documentation: Python2, Python3

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

回答 5

这里的答案不够明确,已在Python 3.6上进行了测试

使用此文件夹结构:

main.py
|
---- myfolder/myfile.py

myfile.py内容在哪里:

def myfunc():
    print('hello')

中的导入语句main.py为:

from myfolder.myfile import myfunc
myfunc()

这将打印你好

The answers here are lacking in clarity, this is tested on Python 3.6

With this folder structure:

main.py
|
---- myfolder/myfile.py

Where myfile.py has the content:

def myfunc():
    print('hello')

The import statement in main.py is:

from myfolder.myfile import myfunc
myfunc()

and this will print hello.


回答 6

您的问题是Python正在Python目录中查找此文件,但找不到它。您必须指定所谈论的目录是您所在的目录,而不是Python目录。

为此,您可以更改以下内容:

from application.app.folder.file import func_name

对此:

from .application.app.folder.file import func_name

通过添加点,您说的是在此文件夹中查找应用程序文件夹,而不是在Python目录中查找。

Your problem is that Python is looking in the Python directory for this file and not finding it. You must specify that you are talking about the directory that you are in and not the Python one.

To do this you change this:

from application.app.folder.file import func_name

to this:

from .application.app.folder.file import func_name

By adding the dot you are saying look in this folder for the application folder instead of looking in the Python directory.


回答 7

据我所知,__init__.py直接在要导入的函数的文件夹中添加一个文件即可完成此工作。

From what I know, add an __init__.py file directly in the folder of the functions you want to import will do the job.


回答 8

在Python 3.4和更高版本中,您可以直接从源文件导入(链接到文档)。这不是最简单的解决方案,但出于完整性考虑,我将其包括在内。

这是一个例子。首先,要导入的文件名为foo.py

def announce():
    print("Imported!")

在文档中的示例的大力启发下,导入上述文件的代码:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

输出:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

请注意,变量名称,模块名称和文件名不必匹配。该代码仍然有效:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

输出:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Python 3.1中引入了以编程方式导入模块的功能,使您可以更好地控制模块的导入方式。有关更多信息,请参考文档。

In Python 3.4 and later, you can import from a source file directly (link to documentation). This is not the simplest solution, but I’m including this answer for completeness.

Here is an example. First, the file to be imported, named foo.py:

def announce():
    print("Imported!")

The code that imports the file above, inspired heavily by the example in the documentation:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

The output:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Note that the variable name, the module name, and the filename need not match. This code still works:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

The output:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

Programmatically importing modules was introduced in Python 3.1 and gives you more control over how modules are imported. Refer to the documentation for more information.


回答 9

在Linux上的python3中为我工作

import sys  
sys.path.append(pathToFolderContainingScripts)  
from scriptName import functionName #scriptName without .py extension  

Worked for me in python3 on linux

import sys  
sys.path.append(pathToFolderContainingScripts)  
from scriptName import functionName #scriptName without .py extension  

回答 10

尝试使用Python的相对导入:

from ...app.folder.file import func_name

从当前目录开始,每个前导点都是层次结构中的另一个更高级别。


问题?如果这对您不起作用,那么您可能会被很多陷阱的相对进口所困扰。阅读答案和评论以获取更多详细信息: 即使使用__init__.py,也如何解决“尝试以非软件包方式进行相对导入”

提示:__init__.py在每个目录级别都有。您可能需要python -m application.app2.some_folder.some_file从顶层目录运行(或删除.py),或者在PYTHONPATH中具有该顶层目录。

Try Python’s relative imports:

from ...app.folder.file import func_name

Every leading dot is another higher level in the hierarchy beginning with the current directory.


Problems? If this isn’t working for you then you probably are getting bit by the many gotcha’s relative imports has. Read answers and comments for more details: How to fix “Attempted relative import in non-package” even with __init__.py

Hint: have __init__.py at every directory level. You might need python -m application.app2.some_folder.some_file (leaving off .py) which you run from the top level directory or have that top level directory in your PYTHONPATH. Phew!


回答 11

我面临着同样的挑战,尤其是在导入多个文件时,这就是我设法克服的方式。

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name

I was faced with the same challenge, especially when importing multiple files, this is how I managed to overcome it.

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name

回答 12

考虑到application作为根目录为你的Python项目,创建一个空__init__.py文件applicationappfolder文件夹。然后在您some_file.py进行如下更改以获取func_name的定义:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()

Considering application as the root directory for your python project, create an empty __init__.py file in application, app and folder folders. Then in your some_file.py make changes as follows to get the definition of func_name:

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()

回答 13

将应用程序移至其他环境时,将sys.path.append与绝对路径一起使用并不理想。使用相对路径并不总是可行,因为当前工作目录取决于脚本的调用方式。

由于应用程序文件夹的结构是固定的,因此我们可以使用os.path来获取我们要导入的模块的完整路径。例如,如果这是结构:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

假设您要导入“ mango”模块。您可以在vanilla.py中执行以下操作:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

当然,您不需要mango_dir变量。

要了解其工作原理,请看以下交互式会话示例:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

并查看os.path文档。

Using sys.path.append with an absolute path is not ideal when moving the application to other environments. Using a relative path won’t always work because the current working directory depends on how the script was invoked.

Since the application folder structure is fixed, we can use os.path to get the full path of the module we wish to import. For example, if this is the structure:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

And let’s say that you want to import the “mango” module. You could do the following in vanilla.py:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

Of course, you don’t need the mango_dir variable.

To understand how this works look at this interactive session example:

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

And check the os.path documentation.


回答 14

这对我在Windows上有效

# some_file.py on mainApp/app2 
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file

This works for me on windows

# some_file.py on mainApp/app2 
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file

回答 15

我很特别:我在Windows上使用Python!

我只需填写信息:对于Windows和Linux,相对路径和绝对路径都可以 sys.path(我需要相对路径,因为我在多台PC上和不同主目录下使用脚本)。

而且,当同时使用Windows \和Windows时,它们/都可以用作文件名的分隔符,当然,您必须加倍使用\Python字符串作为
一些有效示例:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(注意:如果它不是’Windows-native’的话,我认为它/\事件更方便,因为它与Linux兼容并且更容易编写和复制到Windows资源管理器中)

I’m quite special : I use Python with Windows !

I just complete information : for both Windows and Linux, both relative and absolute path work into sys.path (I need relative paths because I use my scripts on the several PCs and under different main directories).

And when using Windows both \ and / can be used as separator for file names and of course you must double \ into Python strings,
some valid examples :

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(note : I think that / is more convenient than \, event if it is less ‘Windows-native’ because it is Linux-compatible and simpler to write and copy to Windows explorer)


回答 16

如果从特定路径加载模块的目的是在开发自定义模块的过程中为您提供帮助,则可以在测试脚本的同一文件夹中创建指向自定义模块根目录的符号链接。对于在该文件夹中运行的任何脚本,此模块引用将优先于安装的具有相同名称的任何其他模块。

我在Linux上进行了测试,但是它可以在任何支持符号链接的现代操作系统中使用。

这种方法的优点之一是,您可以指向位于您自己的本地SVC分支工作副本中的模块,这可以大大简化开发周期并减少管理模块不同版本的失败模式。

If the purpose of loading a module from a specific path is to assist you during the development of a custom module, you can create a symbolic link in the same folder of the test script that points to the root of the custom module. This module reference will take precedence over any other modules installed of the same name for any script run in that folder.

I tested this on Linux but it should work in any modern OS that supports symbolic links.

One advantage to this approach is that you can you can point to a module that’s sitting in your own local SVC branch working copy which can greatly simplify the development cycle time and reduce failure modes of managing different versions of the module.


回答 17

就我而言,我有一个要导入的类。我的文件如下所示:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

在我的主文件中,我通过以下方式包含了代码:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper

In my case I had a class to import. My file looked like this:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

In my main file I included the code via:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper

回答 18

我几次遇到相同的问题,所以我想分享我的解决方案。

Python版本:3.X

以下解决方案适用于使用Python 3.X版开发您的应用程序的人,因为自从Jan / 1/2020开始不支持Python 2

项目结构

在python 3中,__init__.py由于隐式命名空间包,您不需要在项目子目录中。见的init的.py不需要在Python包3.3+

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

问题陈述

file_b.py,我想进口类Afile_a.py的文件夹下。

解决方案

#1快速但肮脏的方式

无需像您当前正在开发新项目那样安装软件包

使用try catch检查错误。代码示例:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

#2安装软件包

一旦安装了应用程序(本文中不包含安装教程)

你可以简单地

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

编码愉快!

I bumped into the same question several times, so I would like to share my solution.

Python Version: 3.X

The following solution is for someone who develops your application in Python version 3.X because Python 2 is not supported since Jan/1/2020.

Project Structure

In python 3, you don’t need __init__.py in your project subdirectory due to the Implicit Namespace Packages. See Is init.py not required for packages in Python 3.3+

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

Problem Statement

In file_b.py, I would like to import a class A in file_a.py under the folder a.

Solutions

#1 A quick but dirty way

Without installing the package like you are currently developing a new project

Using the try catch to check if the errors. Code example:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

#2 Install your package

Once you installed your application (in this post, the tutorial of installation is not included)

You can simply

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

Happy coding!


回答 19

我正在研究a希望用户通过pip install a以下文件列表进行安装的项目:

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

清单

recursive-include b *.*

a / init .py

from __future__ import absolute_import

from a.a import cats
import a.b

a / a.py

cats = 0

a / b / init .py

from __future__ import absolute_import

from a.b.b import dogs

a / b / b.py

dogs = 1

我通过从目录运行以下命令来安装模块MANIFEST.in

python setup.py install

然后,从文件系统上一个完全不同的位置/moustache/armwrestle运行了:

import a
dir(a)

这证实了a.cats确实等于0且a.b.dogs确实等于1的意图。

I was working on project a that I wanted users to install via pip install a with the following file list:

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

MANIFEST.in

recursive-include b *.*

a/init.py

from __future__ import absolute_import

from a.a import cats
import a.b

a/a.py

cats = 0

a/b/init.py

from __future__ import absolute_import

from a.b.b import dogs

a/b/b.py

dogs = 1

I installed the module by running the following from the directory with MANIFEST.in:

python setup.py install

Then, from a totally different location on my filesystem /moustache/armwrestle I was able to run:

import a
dir(a)

Which confirmed that a.cats indeed equalled 0 and a.b.dogs indeed equalled 1, as intended.


回答 20

而不是只做一个import ...,这样做:

from <MySubFolder> import <MyFile>

MyFile在MySubFolder中。

Instead of just doing an import ..., do this :

from <MySubFolder> import <MyFile>

MyFile is inside the MySubFolder.


回答 21

您可以通过按f5刷新Python Shell,或转到“运行”->“运行模块”。这样,您无需更改目录即可从文件中读取内容。Python将自动更改目录。但是,如果您想使用Python Shell中不同目录中的不同文件,则可以像Cameron先前所说的那样在sys中更改目录。

You can refresh the Python shell by pressing f5, or go to Run-> Run Module. This way you don’t have to change the directory to read something from the file. Python will automatically change the directory. But if you want to work with different files from different directory in the Python Shell, then you can change the directory in sys, as Cameron said earlier.


回答 22

因此,我只是右键单击我的IDE,并添加了一个新的文件,folder并且想知道为什么我无法从中导入它。后来我意识到我必须右键单击并创建一个Python包,而不是经典的文件系统文件夹。或者在验尸方法中添加一个__init__.py(使python将文件系统文件夹视为一个包),如其他答案中所述。以防万一有人走这条路。

So I had just right clicked on my IDE, and added a new folder and was wondering why I wasn’t able to import from it. Later I realized I have to right click and create a Python Package, and not a classic file system folder. Or a post-mortem method being adding an __init__.py (which makes python treat the file system folder as a package) as mentioned in other answers. Adding this answer here just in case someone went this route.


回答 23

您可以使用importlib来导入模块,在该模块中,您可以使用如下所示的字符串从文件夹中导入模块:

import importlib

scriptName = 'Snake'

script = importlib.import_module('Scripts\\.%s' % scriptName)

这个示例有一个main.py,上面的代码是一个代码,然后是一个名为Scripts的文件夹,然后您可以通过更改scriptName变量从此文件夹中调用所需的任何内容。然后,您可以script用来引用该模块。例如,如果我Hello()在Snake模块中调用了一个函数,则可以通过以下方式运行此函数:

script.Hello()

我已经在Python 3.6中测试过

You can use importlib to import modules where you want to import a module from a folder using a string like so:

import importlib

scriptName = 'Snake'

script = importlib.import_module('Scripts\\.%s' % scriptName)

This example has a main.py which is the above code then a folder called Scripts and then you can call whatever you need from this folder by changing the scriptName variable. You can then use script to reference to this module. such as if I have a function called Hello() in the Snake module you can run this function by doing so:

script.Hello()

I have tested this in Python 3.6


回答 24

我已经遇到过这些问题很多次了。我经常来同一页。在上一个问题中,我必须server从固定目录运行,但是每次调试时,我都希望从不同的子目录运行。

import sys
sys.insert(1, /path) 

确实不是因为不同的模块,在为我工作,我不得不读不同*的.csv这都在同一个目录中的文件。

最后,我想对我有用的不是pythonic,而是:

在要调试的模块上使用了if __main__ 是从不同于通常的路径运行的。

所以:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')

I’ve had these problems a number of times. I’ve come to this same page a lot. In my last problem I had to run the server from a fixed directory, but whenever debugging I wanted to run from different sub-directories.

import sys
sys.insert(1, /path) 

did NOT work for me because at different modules I had to read different *.csv files which were all in the same directory.

In the end, what worked for me was not pythonic, I guess, but:

I used a if __main__ on top of the module I wanted to debug, that is run from a different than usual path.

So:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')

给定完整路径,如何导入模块?

问题:给定完整路径,如何导入模块?

给定完整路径,如何加载Python模块?请注意,该文件可以在文件系统中的任何位置,因为它是配置选项。

How can I load a Python module given its full path? Note that the file can be anywhere in the filesystem, as it is a configuration option.


回答 0

对于Python 3.5+,请使用:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

对于Python 3.3和3.4,请使用:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(尽管在Python 3.4中已弃用此功能。)

对于Python 2,请使用:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

编译后的Python文件和DLL具有等效的便捷功能。

另请参见http://bugs.python.org/issue21436

For Python 3.5+ use:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

For Python 3.3 and 3.4 use:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Although this has been deprecated in Python 3.4.)

For Python 2 use:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

There are equivalent convenience functions for compiled Python files and DLLs.

See also http://bugs.python.org/issue21436.


回答 1

(通过使用imp)向sys.path添加路径的好处是,当从单个包中导入多个模块时,它可以简化操作。例如:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch

The advantage of adding a path to sys.path (over using imp) is that it simplifies things when importing more than one module from a single package. For example:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch

回答 2

如果您的顶级模块不是文件,而是与__init__.py一起打包为目录,则可接受的解决方案几乎可以使用,但效果不佳。在Python 3.5+中,需要以下代码(请注意,添加的行以’sys.modules’开头):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

如果没有此行,则在执行exec_module时,它将尝试将顶级__init__.py中的相对导入绑定到顶级模块名称(在本例中为“ mymodule”)。但是“ mymodule”尚未加载,因此您将收到错误“ SystemError:父模块’mymodule’未加载,无法执行相对导入”。因此,在加载名称之前,需要先绑定名称。这样做的原因是相对导入系统的基本不变性:“不变性在于,如果您拥有sys.modules [‘spam’]和sys.modules [‘spam.foo’](就像在完成上述导入之后一样) ),后者必须显示为前者的foo属性” ,如此处所述

If your top-level module is not a file but is packaged as a directory with __init__.py, then the accepted solution almost works, but not quite. In Python 3.5+ the following code is needed (note the added line that begins with ‘sys.modules’):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

Without this line, when exec_module is executed, it tries to bind relative imports in your top level __init__.py to the top level module name — in this case “mymodule”. But “mymodule” isn’t loaded yet so you’ll get the error “SystemError: Parent module ‘mymodule’ not loaded, cannot perform relative import”. So you need to bind the name before you load it. The reason for this is the fundamental invariant of the relative import system: “The invariant holding is that if you have sys.modules[‘spam’] and sys.modules[‘spam.foo’] (as you would after the above import), the latter must appear as the foo attribute of the former” as discussed here.


回答 3

要导入模块,您需要将其目录临时或永久地添加到环境变量中。

暂时

import sys
sys.path.append("/path/to/my/modules/")
import my_module

永久性

.bashrc将以下行添加到您的文件(在Linux中)并source ~/.bashrc在终端中执行:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

信用/来源:saarrrr另一个stackexchange 问题

To import your module, you need to add its directory to the environment variable, either temporarily or permanently.

Temporarily

import sys
sys.path.append("/path/to/my/modules/")
import my_module

Permanently

Adding the following line to your .bashrc file (in linux) and excecute source ~/.bashrc in the terminal:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Credit/Source: saarrrr, another stackexchange question


回答 4

听起来您似乎不想专门导入配置文件(它具有很多副作用和其他复杂性),您只想运行它并能够访问生成的命名空间。标准库以runpy.run_path的形式专门提供了一个API :

from runpy import run_path
settings = run_path("/path/to/file.py")

该接口在Python 2.7和Python 3.2+中可用

It sounds like you don’t want to specifically import the configuration file (which has a whole lot of side effects and additional complications involved), you just want to run it, and be able to access the resulting namespace. The standard library provides an API specifically for that in the form of runpy.run_path:

from runpy import run_path
settings = run_path("/path/to/file.py")

That interface is available in Python 2.7 and Python 3.2+


回答 5

您还可以执行类似的操作,并将配置文件所在的目录添加到Python加载路径中,然后进行常规导入,前提是您事先知道文件名,在本例中为“ config”。

凌乱,但有效。

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

You can also do something like this and add the directory that the configuration file is sitting in to the Python load path, and then just do a normal import, assuming you know the name of the file in advance, in this case “config”.

Messy, but it works.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

回答 6

您可以使用

load_source(module_name, path_to_file) 

来自imp模块的方法。

You can use the

load_source(module_name, path_to_file) 

method from imp module.


回答 7

def import_file(full_path_to_module):
    try:
        import os
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)
        save_cwd = os.getcwd()
        os.chdir(module_dir)
        module_obj = __import__(module_name)
        module_obj.__file__ = full_path_to_module
        globals()[module_name] = module_obj
        os.chdir(save_cwd)
    except:
        raise ImportError

import_file('/home/somebody/somemodule.py')
def import_file(full_path_to_module):
    try:
        import os
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)
        save_cwd = os.getcwd()
        os.chdir(module_dir)
        module_obj = __import__(module_name)
        module_obj.__file__ = full_path_to_module
        globals()[module_name] = module_obj
        os.chdir(save_cwd)
    except:
        raise ImportError

import_file('/home/somebody/somemodule.py')

回答 8

这是一些适用于所有Python版本(从2.7-3.5,甚至其他版本)的代码。

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

我测试了 它可能很丑陋,但到目前为止,它是唯一可以在所有版本中使用的版本。

Here is some code that works in all Python versions, from 2.7-3.5 and probably even others.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

I tested it. It may be ugly but so far is the only one that works in all versions.


回答 9

我想出了@SebastianRittau的一个很好的答案的略微修改的版本(我认为是针对Python> 3.4),它允许您使用spec_from_loader而不是使用模块将具有任何扩展名的文件加载为模块spec_from_file_location

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

以显式SourceFileLoader方式对路径进行编码的优点在于,该机制不会尝试从扩展名中找出文件的类型。这意味着您可以.txt使用此方法加载类似文件的内容,但是如果spec_from_file_location不指定loader,.txt则无法进行加载,因为not in中importlib.machinery.SOURCE_SUFFIXES

I have come up with a slightly modified version of @SebastianRittau’s wonderful answer (for Python > 3.4 I think), which will allow you to load a file with any extension as a module using spec_from_loader instead of spec_from_file_location:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

The advantage of encoding the path in an explicit SourceFileLoader is that the machinery will not try to figure out the type of the file from the extension. This means that you can load something like a .txt file using this method, but you could not do it with spec_from_file_location without specifying the loader because .txt is not in importlib.machinery.SOURCE_SUFFIXES.


回答 10

您是指加载还是导入?

您可以操纵sys.path列表,指定模块的路径,然后导入模块。例如,给定一个模块位于:

/foo/bar.py

您可以这样做:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar

Do you mean load or import?

You can manipulate the sys.path list specify the path to your module, then import your module. For example, given a module at:

/foo/bar.py

You could do:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar

回答 11

我相信你可以使用imp.find_module()imp.load_module()加载指定的模块。您需要从路径中拆分模块名称,即,如果要加载/home/mypath/mymodule.py,则需要执行以下操作:

imp.find_module('mymodule', '/home/mypath/')

…但这应该可以完成工作。

I believe you can use imp.find_module() and imp.load_module() to load the specified module. You’ll need to split the module name off of the path, i.e. if you wanted to load /home/mypath/mymodule.py you’d need to do:

imp.find_module('mymodule', '/home/mypath/')

…but that should get the job done.


回答 12

您可以使用pkgutil模块(特别是walk_packages方法)来获取当前目录中软件包的列表。从那里开始,使用importlib机器导入所需的模块很简单:

import pkgutil
import importlib

packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
    mod = importlib.import_module(name)
    # do whatever you want with module now, it's been imported!

You can use the pkgutil module (specifically the walk_packages method) to get a list of the packages in the current directory. From there it’s trivial to use the importlib machinery to import the modules you want:

import pkgutil
import importlib

packages = pkgutil.walk_packages(path='.')
for importer, name, is_package in packages:
    mod = importlib.import_module(name)
    # do whatever you want with module now, it's been imported!

回答 13

创建python模块test.py

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

创建python模块test_check.py

from test import Client1
from test import Client2
from test import test3

我们可以从模块导入导入的模块。

Create python module test.py

import sys
sys.path.append("<project-path>/lib/")
from tes1 import Client1
from tes2 import Client2
import tes3

Create python module test_check.py

from test import Client1
from test import Client2
from test import test3

We can import the imported module from module.


回答 14

Python 3.4的这一领域似乎很难理解!但是,通过使用Chris Calloway的代码进行了一些黑客操作,我设法使某些东西起作用。这是基本功能。

def import_module_from_file(full_path_to_module):
    """
    Import a module given the full path/filename of the .py file

    Python 3.4

    """

    module = None

    try:

        # Get module name and path from full path
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)

        # Get module "spec" from filename
        spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)

        module = spec.loader.load_module()

    except Exception as ec:
        # Simple error printing
        # Insert "sophisticated" stuff here
        print(ec)

    finally:
        return module

这似乎使用了Python 3.4中不推荐使用的模块。我不假装理解为什么,但是它似乎可以在程序中运行。我发现克里斯的解决方案在命令行上有效,但不是在程序内部。

This area of Python 3.4 seems to be extremely tortuous to understand! However with a bit of hacking using the code from Chris Calloway as a start I managed to get something working. Here’s the basic function.

def import_module_from_file(full_path_to_module):
    """
    Import a module given the full path/filename of the .py file

    Python 3.4

    """

    module = None

    try:

        # Get module name and path from full path
        module_dir, module_file = os.path.split(full_path_to_module)
        module_name, module_ext = os.path.splitext(module_file)

        # Get module "spec" from filename
        spec = importlib.util.spec_from_file_location(module_name,full_path_to_module)

        module = spec.loader.load_module()

    except Exception as ec:
        # Simple error printing
        # Insert "sophisticated" stuff here
        print(ec)

    finally:
        return module

This appears to use non-deprecated modules from Python 3.4. I don’t pretend to understand why, but it seems to work from within a program. I found Chris’ solution worked on the command line but not from inside a program.


回答 15

我并不是说它更好,但是为了完整起见,我想建议该exec函数在python 2和3中都可用。 exec提供允许您在全局范围或内部范围内执行任意代码,作为字典提供。

例如,如果您"/path/to/module的函数中存储有一个模块,则foo()可以执行以下操作:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

这使您可以动态加载代码更加明确,并赋予您一些额外的功能,例如提供自定义内置函数的能力。

如果通过属性(而不是键)进行访问对您很重要,则可以为全局对象设计一个自定义dict类,它提供了这种访问,例如:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)

I’m not saying that it is better, but for the sake of completeness, I wanted to suggest the exec function, available in both python 2 and 3. exec allows you to execute arbitrary code in either the global scope, or in an internal scope, provided as a dictionary.

For example, if you have a module stored in "/path/to/module” with the function foo(), you could run it by doing the following:

module = dict()
with open("/path/to/module") as f:
    exec(f.read(), module)
module['foo']()

This makes it a bit more explicit that you’re loading code dynamically, and grants you some additional power, such as the ability to provide custom builtins.

And if having access through attributes, instead of keys is important to you, you can design a custom dict class for the globals, that provides such access, e.g.:

class MyModuleClass(dict):
    def __getattr__(self, name):
        return self.__getitem__(name)

回答 16

要从给定的文件名导入模块,可以临时扩展路径,并在finally块引用中恢复系统路径

filename = "directory/module.py"

directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]

path = list(sys.path)
sys.path.insert(0, directory)
try:
    module = __import__(module_name)
finally:
    sys.path[:] = path # restore

To import a module from a given filename, you can temporarily extend the path, and restore the system path in the finally block reference:

filename = "directory/module.py"

directory, module_name = os.path.split(filename)
module_name = os.path.splitext(module_name)[0]

path = list(sys.path)
sys.path.insert(0, directory)
try:
    module = __import__(module_name)
finally:
    sys.path[:] = path # restore

回答 17

这应该工作

path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
    basename = os.path.basename(infile)
    basename_without_extension = basename[:-3]

    # http://docs.python.org/library/imp.html?highlight=imp#module-imp
    imp.load_source(basename_without_extension, infile)

This should work

path = os.path.join('./path/to/folder/with/py/files', '*.py')
for infile in glob.glob(path):
    basename = os.path.basename(infile)
    basename_without_extension = basename[:-3]

    # http://docs.python.org/library/imp.html?highlight=imp#module-imp
    imp.load_source(basename_without_extension, infile)

回答 18

如果我们在同一项目中有脚本,但在不同的目录中有脚本,则可以通过以下方法解决此问题。

在这种情况下utils.pysrc/main/util/

import sys
sys.path.append('./')

import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method

If we have scripts in the same project but in different directory means, we can solve this problem by the following method.

In this situation utils.py is in src/main/util/

import sys
sys.path.append('./')

import src.main.util.utils
#or
from src.main.util.utils import json_converter # json_converter is example method

回答 19

imp为您准备了一个包装。我称呼它import_file,这就是它的用法:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

您可以在以下位置获得它:

http://pypi.python.org/pypi/import_file

http://code.google.com/p/import-file/

I made a package that uses imp for you. I call it import_file and this is how it’s used:

>>>from import_file import import_file
>>>mylib = import_file('c:\\mylib.py')
>>>another = import_file('relative_subdir/another.py')

You can get it at:

http://pypi.python.org/pypi/import_file

or at

http://code.google.com/p/import-file/


回答 20

在运行时导入软件包模块(Python配方)

http://code.activestate.com/recipes/223972/

###################
##                #
## classloader.py #
##                #
###################

import sys, types

def _get_mod(modulePath):
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError:
        # The last [''] is very important!
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    lastDot = fullFuncName.rfind(u".")
    funcName = fullFuncName[lastDot + 1:]
    modPath = fullFuncName[:lastDot]

    aMod = _get_mod(modPath)
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    assert callable(aFunc), u"%s is not callable." % fullFuncName

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


######################
##       Usage      ##
######################

class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass

def storage_object(aFullClassName, allOptions={}):
    aStoreClass = _get_class(aFullClassName, StorageManager)
    return aStoreClass(allOptions)

Import package modules at runtime (Python recipe)

http://code.activestate.com/recipes/223972/

###################
##                #
## classloader.py #
##                #
###################

import sys, types

def _get_mod(modulePath):
    try:
        aMod = sys.modules[modulePath]
        if not isinstance(aMod, types.ModuleType):
            raise KeyError
    except KeyError:
        # The last [''] is very important!
        aMod = __import__(modulePath, globals(), locals(), [''])
        sys.modules[modulePath] = aMod
    return aMod

def _get_func(fullFuncName):
    """Retrieve a function object from a full dotted-package name."""

    # Parse out the path, module, and function
    lastDot = fullFuncName.rfind(u".")
    funcName = fullFuncName[lastDot + 1:]
    modPath = fullFuncName[:lastDot]

    aMod = _get_mod(modPath)
    aFunc = getattr(aMod, funcName)

    # Assert that the function is a *callable* attribute.
    assert callable(aFunc), u"%s is not callable." % fullFuncName

    # Return a reference to the function itself,
    # not the results of the function.
    return aFunc

def _get_class(fullClassName, parentClass=None):
    """Load a module and retrieve a class (NOT an instance).

    If the parentClass is supplied, className must be of parentClass
    or a subclass of parentClass (or None is returned).
    """
    aClass = _get_func(fullClassName)

    # Assert that the class is a subclass of parentClass.
    if parentClass is not None:
        if not issubclass(aClass, parentClass):
            raise TypeError(u"%s is not a subclass of %s" %
                            (fullClassName, parentClass))

    # Return a reference to the class itself, not an instantiated object.
    return aClass


######################
##       Usage      ##
######################

class StorageManager: pass
class StorageManagerMySQL(StorageManager): pass

def storage_object(aFullClassName, allOptions={}):
    aStoreClass = _get_class(aFullClassName, StorageManager)
    return aStoreClass(allOptions)

回答 21

在Linux中,可以在python脚本所在的目录中添加符号链接。

即:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

/absolute/path/to/script/module.pyc如果您更改python 的内容,python将会创建并更新它/absolute/path/to/module/module.py

然后在mypythonscript.py中包含以下内容

from module import *

In Linux, adding a symbolic link in the directory your python script is located works.

ie:

ln -s /absolute/path/to/module/module.py /absolute/path/to/script/module.py

python will create /absolute/path/to/script/module.pyc and will update it if you change the contents of /absolute/path/to/module/module.py

then include the following in mypythonscript.py

from module import *

回答 22

我已经基于importlib模块编写了自己的全局和可移植导入函数,用于:

  • 既可以将两个模块都作为子模块导入,又可以将模块的内容导入父模块(如果没有父模块,则可以导入全局变量)。
  • 能够导入文件名中带有句点字符的模块。
  • 能够导入具有任何扩展名的模块。
  • 能够为子模块使用独立名称,而不是默认情况下不带扩展名的文件名。
  • 能够基于先前导入的模块来定义导入顺序,而不是依赖于sys.path或依赖于什么搜索路径存储。

示例目录结构:

<root>
 |
 +- test.py
 |
 +- testlib.py
 |
 +- /std1
 |   |
 |   +- testlib.std1.py
 |
 +- /std2
 |   |
 |   +- testlib.std2.py
 |
 +- /std3
     |
     +- testlib.std3.py

包含关系和顺序:

test.py
  -> testlib.py
    -> testlib.std1.py
      -> testlib.std2.py
    -> testlib.std3.py 

实现方式:

最新更改存储:https : //sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py

test.py

import os, sys, inspect, copy

SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("test::SOURCE_FILE: ", SOURCE_FILE)

# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl

tkl.tkl_init(tkl)

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

tkl_import_module(SOURCE_DIR, 'testlib.py')

print(globals().keys())

testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test()                             # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test()     # ... but reachable through the `globals` + `getattr`

tkl_import_module(SOURCE_DIR, 'testlib.py', '.')

print(globals().keys())

base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test()                                     # does not reachable directly ...
globals()['testlib.std3'].std3_test()                         # ... but reachable through the `globals` + `getattr`

testlib.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')

# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')

print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)

def base_test():
  print('base_test')

testlib.std1.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')

def std1_test():
  print('std1_test')

testlib.std2.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)

def std2_test():
  print('std2_test')

testlib.std3.py

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)

def std3_test():
  print('std3_test')

输出3.7.4):

test::SOURCE_FILE:  <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test

经测试在Python 3.7.43.2.52.7.16

优点

  • 可以将两个模块都作为子模块导入,也可以将模块的内容导入父模块(如果没有父模块,则可以导入全局变量)。
  • 可以导入文件名中带有句点的模块。
  • 可以从任何扩展模块导入任何扩展模块。
  • 可以为子模块使用独立名称,而不是默认情况下不带扩展名的文件名(例如,testlib.std.pyas testlibtestlib.blabla.pyas testlib_blabla等)。
  • 不依赖于sys.path搜索路径存储。
  • 不需要在调用之间SOURCE_FILESOURCE_DIR之间保存/恢复全局变量tkl_import_module
  • [用于3.4.x和较高]可以混合在嵌套的模块命名空间tkl_import_module的呼叫(例如:named->local->namedlocal->named->local此类推)。
  • [ 3.4.x及更高]可以将全局变量/函数/类从声明的位置自动导出到通过tkl_import_module(通过tkl_declare_global函数)导入的所有子模块。

缺点

  • [for 3.3.xand lower]要求tkl_import_module在所有要调用的模块中声明tkl_import_module(代码重复)

更新1,2(对于3.4.x仅限更高版本):

在Python 3.4及更高版本中,您可以tkl_import_module通过tkl_import_module在顶级模块中进行声明来绕过在每个模块中声明的要求,并且该函数将在一次调用中将自身注入所有子模块(这是一种自我部署导入)。

更新3

添加了tkl_source_module与bash类似的功能,source并在导入时提供了支持执行保护(通过模块合并而不是导入实现)。

更新4

添加tkl_declare_global了将模块全局变量自动导出到所有子模块的功能,这些模块由于不属于子模块而无法看到模块全局变量。

更新5

所有功能都已移入铲斗库,请参见上面的链接。

I have wrote my own global and portable import function, based on importlib module, for:

  • Be able to import both module as a submodule and to import content of a module to a parent module (or into a globals if has no parent module).
  • Be able to import modules with a period characters in a file name.
  • Be able to import modules with any extension.
  • Be able to use a standalone name for a submodule instead of a file name without extension which is by default.
  • Be able to define the import order based on previously imported module instead of dependent on sys.path or on a what ever search path storage.

The examples directory structure:

<root>
 |
 +- test.py
 |
 +- testlib.py
 |
 +- /std1
 |   |
 |   +- testlib.std1.py
 |
 +- /std2
 |   |
 |   +- testlib.std2.py
 |
 +- /std3
     |
     +- testlib.std3.py

Inclusion dependency and order:

test.py
  -> testlib.py
    -> testlib.std1.py
      -> testlib.std2.py
    -> testlib.std3.py 

Implementation:

Latest changes store: https://sourceforge.net/p/tacklelib/tacklelib/HEAD/tree/trunk/python/tacklelib/tacklelib.py

test.py:

import os, sys, inspect, copy

SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("test::SOURCE_FILE: ", SOURCE_FILE)

# portable import to the global space
sys.path.append(TACKLELIB_ROOT) # TACKLELIB_ROOT - path to the library directory
import tacklelib as tkl

tkl.tkl_init(tkl)

# cleanup
del tkl # must be instead of `tkl = None`, otherwise the variable would be still persist
sys.path.pop()

tkl_import_module(SOURCE_DIR, 'testlib.py')

print(globals().keys())

testlib.base_test()
testlib.testlib_std1.std1_test()
testlib.testlib_std1.testlib_std2.std2_test()
#testlib.testlib.std3.std3_test()                             # does not reachable directly ...
getattr(globals()['testlib'], 'testlib.std3').std3_test()     # ... but reachable through the `globals` + `getattr`

tkl_import_module(SOURCE_DIR, 'testlib.py', '.')

print(globals().keys())

base_test()
testlib_std1.std1_test()
testlib_std1.testlib_std2.std2_test()
#testlib.std3.std3_test()                                     # does not reachable directly ...
globals()['testlib.std3'].std3_test()                         # ... but reachable through the `globals` + `getattr`

testlib.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("1 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std1', 'testlib.std1.py', 'testlib_std1')

# SOURCE_DIR is restored here
print("2 testlib::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/std3', 'testlib.std3.py')

print("3 testlib::SOURCE_FILE: ", SOURCE_FILE)

def base_test():
  print('base_test')

testlib.std1.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std1::SOURCE_FILE: ", SOURCE_FILE)

tkl_import_module(SOURCE_DIR + '/../std2', 'testlib.std2.py', 'testlib_std2')

def std1_test():
  print('std1_test')

testlib.std2.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std2::SOURCE_FILE: ", SOURCE_FILE)

def std2_test():
  print('std2_test')

testlib.std3.py:

# optional for 3.4.x and higher
#import os, inspect
#
#SOURCE_FILE = os.path.abspath(inspect.getsourcefile(lambda:0)).replace('\\','/')
#SOURCE_DIR = os.path.dirname(SOURCE_FILE)

print("testlib.std3::SOURCE_FILE: ", SOURCE_FILE)

def std3_test():
  print('std3_test')

Output (3.7.4):

test::SOURCE_FILE:  <root>/test01/test.py
import : <root>/test01/testlib.py as testlib -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib'])
base_test
std1_test
std2_test
std3_test
import : <root>/test01/testlib.py as . -> []
1 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std1/testlib.std1.py as testlib_std1 -> ['testlib']
import : <root>/test01/std1/../std2/testlib.std2.py as testlib_std2 -> ['testlib', 'testlib_std1']
testlib.std2::SOURCE_FILE:  <root>/test01/std1/../std2/testlib.std2.py
2 testlib::SOURCE_FILE:  <root>/test01/testlib.py
import : <root>/test01/std3/testlib.std3.py as testlib.std3 -> ['testlib']
testlib.std3::SOURCE_FILE:  <root>/test01/std3/testlib.std3.py
3 testlib::SOURCE_FILE:  <root>/test01/testlib.py
dict_keys(['__name__', '__doc__', '__package__', '__loader__', '__spec__', '__annotations__', '__builtins__', '__file__', '__cached__', 'os', 'sys', 'inspect', 'copy', 'SOURCE_FILE', 'SOURCE_DIR', 'TackleGlobalImportModuleState', 'tkl_membercopy', 'tkl_merge_module', 'tkl_get_parent_imported_module_state', 'tkl_declare_global', 'tkl_import_module', 'TackleSourceModuleState', 'tkl_source_module', 'TackleLocalImportModuleState', 'testlib', 'testlib_std1', 'testlib.std3', 'base_test'])
base_test
std1_test
std2_test
std3_test

Tested in Python 3.7.4, 3.2.5, 2.7.16

Pros:

  • Can import both module as a submodule and can import content of a module to a parent module (or into a globals if has no parent module).
  • Can import modules with periods in a file name.
  • Can import any extension module from any extension module.
  • Can use a standalone name for a submodule instead of a file name without extension which is by default (for example, testlib.std.py as testlib, testlib.blabla.py as testlib_blabla and so on).
  • Does not depend on a sys.path or on a what ever search path storage.
  • Does not require to save/restore global variables like SOURCE_FILE and SOURCE_DIR between calls to tkl_import_module.
  • [for 3.4.x and higher] Can mix the module namespaces in nested tkl_import_module calls (ex: named->local->named or local->named->local and so on).
  • [for 3.4.x and higher] Can auto export global variables/functions/classes from where being declared to all children modules imported through the tkl_import_module (through the tkl_declare_global function).

Cons:

  • [for 3.3.x and lower] Require to declare tkl_import_module in all modules which calls to tkl_import_module (code duplication)

Update 1,2 (for 3.4.x and higher only):

In Python 3.4 and higher you can bypass the requirement to declare tkl_import_module in each module by declare tkl_import_module in a top level module and the function would inject itself to all children modules in a single call (it’s a kind of self deploy import).

Update 3:

Added function tkl_source_module as analog to bash source with support execution guard upon import (implemented through the module merge instead of import).

Update 4:

Added function tkl_declare_global to auto export a module global variable to all children modules where a module global variable is not visible because is not a part of a child module.

Update 5:

All functions has moved into the tacklelib library, see the link above.


回答 23

有一个专用于此的软件包

from thesmuggler import smuggle

# À la `import weapons`
weapons = smuggle('weapons.py')

# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')

# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')

它已经在Python版本(也包括Jython和PyPy)上进行了测试,但是根据项目的大小,它可能会显得过大。

There’s a package that’s dedicated to this specifically:

from thesmuggler import smuggle

# À la `import weapons`
weapons = smuggle('weapons.py')

# À la `from contraband import drugs, alcohol`
drugs, alcohol = smuggle('drugs', 'alcohol', source='contraband.py')

# À la `from contraband import drugs as dope, alcohol as booze`
dope, booze = smuggle('drugs', 'alcohol', source='contraband.py')

It’s tested across Python versions (Jython and PyPy too), but it might be overkill depending on the size of your project.


回答 24

将其添加到答案列表中,因为我找不到任何有效的方法。这将允许导入3.4中的已编译(pyd)python模块:

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()

Adding this to the list of answers as I couldn’t find anything that worked. This will allow imports of compiled (pyd) python modules in 3.4:

import sys
import importlib.machinery

def load_module(name, filename):
    # If the Loader finds the module name in this list it will use
    # module_name.__file__ instead so we need to delete it here
    if name in sys.modules:
        del sys.modules[name]
    loader = importlib.machinery.ExtensionFileLoader(name, filename)
    module = loader.load_module()
    locals()[name] = module
    globals()[name] = module

load_module('something', r'C:\Path\To\something.pyd')
something.do_something()

回答 25

很简单的方法:假设您要导入具有相对路径../../MyLibs/pyfunc.py的文件


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

但是,如果没有警卫就可以做到,那么您最终可以走很长的路

quite simple way: suppose you want import file with relative path ../../MyLibs/pyfunc.py


libPath = '../../MyLibs'
import sys
if not libPath in sys.path: sys.path.append(libPath)
import pyfunc as pf

But if you make it without a guard you can finally get a very long path


回答 26

一个简单的解决方案,importlib而不是使用imp包(已针对Python 2.7进行了测试,尽管它也适用于Python 3):

import importlib

dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")

现在,您可以直接使用导入模块的命名空间,如下所示:

a = module.myvar
b = module.myfunc(a)

该解决方案的优势在于,为了在我们的代码中使用它,我们甚至不需要知道我们想要导入的模块的实际名称。例如,在模块的路径是可配置参数的情况下,这很有用。

A simple solution using importlib instead of the imp package (tested for Python 2.7, although it should work for Python 3 too):

import importlib

dirname, basename = os.path.split(pyfilepath) # pyfilepath: '/my/path/mymodule.py'
sys.path.append(dirname) # only directories should be added to PYTHONPATH
module_name = os.path.splitext(basename)[0] # '/my/path/mymodule.py' --> 'mymodule'
module = importlib.import_module(module_name) # name space of defined module (otherwise we would literally look for "module_name")

Now you can directly use the namespace of the imported module, like this:

a = module.myvar
b = module.myfunc(a)

The advantage of this solution is that we don’t even need to know the actual name of the module we would like to import, in order to use it in our code. This is useful, e.g. in case the path of the module is a configurable argument.


回答 27

这个答案是塞巴斯蒂安·里陶(Sebastian Rittau)对评论的回答的补充:“但是,如果您没有模块名怎么办?” 这是一种在给定文件名的情况下获取可能的python模块名称的快速而肮脏的方法-它只是沿树走,直到找到没有__init__.py文件的目录,然后将其转换回文件名。对于Python 3.4+(使用pathlib),这很有意义,因为Py2人可以使用“ imp”或其他方式进行相对导入:

import pathlib

def likely_python_module(filename):
    '''
    Given a filename or Path, return the "likely" python module name.  That is, iterate
    the parent directories until it doesn't contain an __init__.py file.

    :rtype: str
    '''
    p = pathlib.Path(filename).resolve()
    paths = []
    if p.name != '__init__.py':
        paths.append(p.stem)
    while True:
        p = p.parent
        if not p:
            break
        if not p.is_dir():
            break

        inits = [f for f in p.iterdir() if f.name == '__init__.py']
        if not inits:
            break

        paths.append(p.stem)

    return '.'.join(reversed(paths))

当然存在改进的可能性,并且可选__init__.py文件可能需要进行其他更改,但是如果__init__.py总的来说,这可以解决问题。

This answer is a supplement to Sebastian Rittau’s answer responding to the comment: “but what if you don’t have the module name?” This is a quick and dirty way of getting the likely python module name given a filename — it just goes up the tree until it finds a directory without an __init__.py file and then turns it back into a filename. For Python 3.4+ (uses pathlib), which makes sense since Py2 people can use “imp” or other ways of doing relative imports:

import pathlib

def likely_python_module(filename):
    '''
    Given a filename or Path, return the "likely" python module name.  That is, iterate
    the parent directories until it doesn't contain an __init__.py file.

    :rtype: str
    '''
    p = pathlib.Path(filename).resolve()
    paths = []
    if p.name != '__init__.py':
        paths.append(p.stem)
    while True:
        p = p.parent
        if not p:
            break
        if not p.is_dir():
            break

        inits = [f for f in p.iterdir() if f.name == '__init__.py']
        if not inits:
            break

        paths.append(p.stem)

    return '.'.join(reversed(paths))

There are certainly possibilities for improvement, and the optional __init__.py files might necessitate other changes, but if you have __init__.py in general, this does the trick.


回答 28

我认为,最好的方法是从官方文档中获取(29.1。imp —访问import internals):

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()

The best way, I think, is from the official documentation (29.1. imp — Access the import internals):

import imp
import sys

def __import__(name, globals=None, locals=None, fromlist=None):
    # Fast path: see if the module has already been imported.
    try:
        return sys.modules[name]
    except KeyError:
        pass

    # If any of the following calls raises an exception,
    # there's a problem we can't handle -- let the caller handle it.

    fp, pathname, description = imp.find_module(name)

    try:
        return imp.load_module(name, fp, pathname, description)
    finally:
        # Since we may exit via an exception, close fp explicitly.
        if fp:
            fp.close()