标签归档:python-import

列出所有属于python软件包的模块吗?

问题:列出所有属于python软件包的模块吗?

有没有一种直接的方法来查找python软件包中的所有模块?我已经找到了这个旧的讨论,这并不是真正的结论,但是我很想在我基于os.listdir()推出自己的解决方案之前有一个明确的答案。

Is there a straightforward way to find all the modules that are part of a python package? I’ve found this old discussion, which is not really conclusive, but I’d love to have a definite answer before I roll out my own solution based on os.listdir().


回答 0

是的,您需要某种基于pkgutil或相似的东西-这样,您可以将所有软件包都视为相同,而不管它们是放在鸡蛋还是拉链中(在os.listdir都不起作用的地方)。

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)

如何导入它们呢?您可以__import__照常使用:

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
prefix = package.__name__ + "."
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)
    module = __import__(modname, fromlist="dummy")
    print "Imported", module

Yes, you want something based on pkgutil or similar — this way you can treat all packages alike regardless if they are in eggs or zips or so (where os.listdir won’t help).

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)

How to import them too? You can just use __import__ as normal:

import pkgutil

# this is the package we are inspecting -- for example 'email' from stdlib
import email

package = email
prefix = package.__name__ + "."
for importer, modname, ispkg in pkgutil.iter_modules(package.__path__, prefix):
    print "Found submodule %s (is a package: %s)" % (modname, ispkg)
    module = __import__(modname, fromlist="dummy")
    print "Imported", module

回答 1

这项工作的正确工具是pkgutil.walk_packages。

要列出系统上的所有模块:

import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=None, onerror=lambda x: None):
    print(modname)

请注意,walk_packages会导入所有子包,但不会导入子模块。

如果您希望列出某个程序包的所有子模块,则可以使用如下代码:

import pkgutil
import scipy
package=scipy
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__,
                                                      prefix=package.__name__+'.',
                                                      onerror=lambda x: None):
    print(modname)

iter_modules仅列出一级深度的模块。walk_packages获取所有子模块。例如,对于scipy,walk_packages返回

scipy.stats.stats

而iter_modules仅返回

scipy.stats

pkgutil的文档(http://docs.python.org/library/pkgutil.html)没有列出/usr/lib/python2.6/pkgutil.py中定义的所有有趣功能。

也许这意味着功能不是“公共”界面的一部分,并且可能会发生变化。

但是,至少从Python 2.6起(也许是早期版本?),pkgutil带有walk_packages方法,该方法递归地遍历所有可用模块。

The right tool for this job is pkgutil.walk_packages.

To list all the modules on your system:

import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=None, onerror=lambda x: None):
    print(modname)

Be aware that walk_packages imports all subpackages, but not submodules.

If you wish to list all submodules of a certain package then you can use something like this:

import pkgutil
import scipy
package=scipy
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__,
                                                      prefix=package.__name__+'.',
                                                      onerror=lambda x: None):
    print(modname)

iter_modules only lists the modules which are one-level deep. walk_packages gets all the submodules. In the case of scipy, for example, walk_packages returns

scipy.stats.stats

while iter_modules only returns

scipy.stats

The documentation on pkgutil (http://docs.python.org/library/pkgutil.html) does not list all the interesting functions defined in /usr/lib/python2.6/pkgutil.py.

Perhaps this means the functions are not part of the “public” interface and are subject to change.

However, at least as of Python 2.6 (and perhaps earlier versions?) pkgutil comes with a walk_packages method which recursively walks through all the modules available.


回答 2

这对我有用:

import types

for key, obj in nltk.__dict__.iteritems():
    if type(obj) is types.ModuleType: 
        print key

This works for me:

import types

for key, obj in nltk.__dict__.iteritems():
    if type(obj) is types.ModuleType: 
        print key

回答 3

我一直在寻找一种方法来重新加载我正在编辑的程序包中的所有子模块。它是上述答案/评论的组合,因此我决定将其发布在此处,作为答案而不是评论。

package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
    try:
        modulesource = importlib.import_module(modname)
        reload(modulesource)
        print("reloaded: {}".format(modname))
    except Exception as e:
        print('Could not load {} {}'.format(modname, e))

I was looking for a way to reload all submodules that I’m editing live in my package. It is a combination of the answers/comments above, so I’ve decided to post it here as an answer rather than a comment.

package=yourPackageName
import importlib
import pkgutil
for importer, modname, ispkg in pkgutil.walk_packages(path=package.__path__, prefix=package.__name__+'.', onerror=lambda x: None):
    try:
        modulesource = importlib.import_module(modname)
        reload(modulesource)
        print("reloaded: {}".format(modname))
    except Exception as e:
        print('Could not load {} {}'.format(modname, e))

回答 4

这是我的头上的一种方法:

>>> import os
>>> filter(lambda i: type(i) == type(os), [getattr(os, j) for j in dir(os)])
[<module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'errno' (built-in)>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'sys' (built-in)>]

它肯定可以清理和改进。

编辑:这是一个稍微更好的版本:

>>> [m[1] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
[<module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'errno' (built-in)>, <module 'sys' (built-in)>]
>>> [m[0] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
['_copy_reg', 'UserDict', 'path', 'errno', 'sys']

注意:如果将模块拉入__init__.py文件中,它们也将找到不一定位于包子目录中的模块,因此取决于您“包的一部分”的含义。

Here’s one way, off the top of my head:

>>> import os
>>> filter(lambda i: type(i) == type(os), [getattr(os, j) for j in dir(os)])
[<module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'errno' (built-in)>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'sys' (built-in)>]

It could certainly be cleaned up and improved.

EDIT: Here’s a slightly nicer version:

>>> [m[1] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
[<module 'copy_reg' from '/usr/lib/python2.5/copy_reg.pyc'>, <module 'UserDict' from '/usr/lib/python2.5/UserDict.pyc'>, <module 'posixpath' from '/usr/lib/python2.5/posixpath.pyc'>, <module 'errno' (built-in)>, <module 'sys' (built-in)>]
>>> [m[0] for m in filter(lambda a: type(a[1]) == type(os), os.__dict__.items())]
['_copy_reg', 'UserDict', 'path', 'errno', 'sys']

NOTE: This will also find modules that might not necessarily be located in a subdirectory of the package, if they’re pulled in in its __init__.py file, so it depends on what you mean by “part of” a package.


何时使用os.name,sys.platform或platform.system?

问题:何时使用os.name,sys.platform或platform.system?

据我所知,Python有3种方法来找出运行什么操作系统:

  1. os.name
  2. sys.platform
  3. platform.system()

知道此信息对于有条件导入或使用不同平台之间的功能(例如,time.clock()在Windows和time.time()UNIX上)通常很有用。

我的问题是,为什么要使用3种不同的方法?什么时候应该使用一种方法而不是另一种方法?哪种方法是“最佳”的(最好是面向未来的,或者最不可能偶然排除程序可以实际运行的特定系统)?

好像sys.platform是更具体的比os.name,让您区分win32来自cygwin(而不是只nt),并linux2darwin(而不是只posix)。但是,如果是这样,那sys.platform和之间的区别platform.system()呢?

例如,这更好:

import sys
if sys.platform == 'linux2':
    # Do Linux-specific stuff

或这个?:

import platform
if platform.system() == 'Linux':
    # Do Linux-specific stuff

现在,我将继续坚持sys.platform下去,因此这个问题并不是特别紧迫,但我将非常感谢您对此进行的澄清。

As far as I know, Python has 3 ways of finding out what operating system is running on:

  1. os.name
  2. sys.platform
  3. platform.system()

Knowing this information is often useful in conditional imports, or using functionality that differs between platforms (e.g. time.clock() on Windows v.s. time.time() on UNIX).

My question is, why 3 different ways of doing this? When should one way be used and not another? Which way is the ‘best’ (most future-proof or least likely to accidentally exclude a particular system which your program can actually run on)?

It seems like sys.platform is more specific than os.name, allowing you to distinguish win32 from cygwin (as opposed to just nt), and linux2 from darwin (as opposed to just posix). But if that’s so, that what about the difference between sys.platform and platform.system()?

For example, which is better, this:

import sys
if sys.platform == 'linux2':
    # Do Linux-specific stuff

or this? :

import platform
if platform.system() == 'Linux':
    # Do Linux-specific stuff

For now I’ll be sticking to sys.platform, so this question isn’t particularly urgent, but I would be very grateful for some clarification regarding this.


回答 0

深入研究源代码。

的输出sys.platformos.name在编译时被确定。platform.system()确定运行时的系统类型。

  • sys.platform 在构建配置期间被指定为编译器定义。
  • os.name检查是否某些操作系统特定模块可供选择(例如posixnt,…)
  • platform.system()实际运行uname以及可能在运行时确定系统类型的其他几个功能。

我的建议:

  • 使用os.name来检查它是否是一个POSIX兼容的系统。
  • 使用sys.platform来检查它是否是一个linux,cygwin的,达尔文,atheos等。
  • 使用platform.system(),如果你不相信的其他来源。

Dived a bit into the source code.

The output of sys.platform and os.name are determined at compile time. platform.system() determines the system type at run time.

  • sys.platform is specified as a compiler define during the build configuration.
  • os.name checks whether certain os specific modules are available (e.g. posix, nt, …)
  • platform.system() actually runs uname and potentially several other functions to determine the system type at run time.

My suggestion:

  • Use os.name to check whether it’s a posix-compliant system.
  • Use sys.platform to check whether it’s a linux, cygwin, darwin, atheos, etc.
  • Use platform.system() if you don’t believe the other sources.

回答 1

有一线之隔差platform.system()sys.platform,有趣的大多数情况下 platform.system()退化为sys.platform

这是消息人士Python2.7\Lib\Platform.py\system说的

def system():

    """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.

        An empty string is returned if the value cannot be determined.

    """
    return uname()[0]

def uname():
    # Get some infos from the builtin os.uname API...
    try:
        system,node,release,version,machine = os.uname()
    except AttributeError:
        no_os_uname = 1

    if no_os_uname or not filter(None, (system, node, release, version, machine)):
        # Hmm, no there is either no uname or uname has returned
        #'unknowns'... we'll have to poke around the system then.
        if no_os_uname:
            system = sys.platform
            release = ''
            version = ''
            node = _node()
            machine = ''

同样根据文档

os.uname()

返回一个5元组,其中包含标识当前操作系统的信息。元组包含5个字符串:(系统名称,节点名称,发行版,版本,计算机)。某些系统将节点名截断为8个字符或开头部分;获得主机名的更好方法是socket.gethostname()甚至socket.gethostbyaddr(socket.gethostname())。

Availability: recent flavors of Unix.

There is a thin line difference between platform.system() and sys.platform and interestingly for most cases platform.system() degenerates to sys.platform

Here is what the Source Python2.7\Lib\Platform.py\system says

def system():

    """ Returns the system/OS name, e.g. 'Linux', 'Windows' or 'Java'.

        An empty string is returned if the value cannot be determined.

    """
    return uname()[0]

def uname():
    # Get some infos from the builtin os.uname API...
    try:
        system,node,release,version,machine = os.uname()
    except AttributeError:
        no_os_uname = 1

    if no_os_uname or not filter(None, (system, node, release, version, machine)):
        # Hmm, no there is either no uname or uname has returned
        #'unknowns'... we'll have to poke around the system then.
        if no_os_uname:
            system = sys.platform
            release = ''
            version = ''
            node = _node()
            machine = ''

Also per the documentation

os.uname()

Return a 5-tuple containing information identifying the current operating system. The tuple contains 5 strings: (sysname, nodename, release, version, machine). Some systems truncate the nodename to 8 characters or to the leading component; a better way to get the hostname is socket.gethostname() or even socket.gethostbyaddr(socket.gethostname()).

Availability: recent flavors of Unix.

回答 2

sys.platform文档

通常,测试某些功能是否可用的“最好的”面向未来的方法只是尝试使用它,并在失败时使用备用。

sys.platform和platform.system()之间的区别如何?

platform.system()返回的标准值,它可能从多个来源获得:os.uname()sys.platformver命令(在Windows上)。

From sys.platform docs:

  • os.name has a coarser granularity
  • os.uname() gives system-dependent version information
  • The platform module provides detailed checks for the system’s identity

Often the “best” future-proof way to test whether some functionality is available is just to try to use it and use a fallback if it fails.

what about the difference between sys.platform and platform.system()?

platform.system() returns a normalized value that it might get from several sources: os.uname(), sys.platform, ver command (on Windows).


回答 3

这取决于您是希望在未测试的系统上引发异常还是尝试任何操作,以及您的代码是否如此高级或如此之低,以至于它在类似的未经测试的系统(例如未经测试的Mac-‘posix’或嵌入式ARM系统)。更多的pythonic方法不是枚举所有已知系统,而是测试可能的相关属性。(例如,重要的是系统的持久性,但不重要的多处理属性。)

  • os.name是正确使用os模块的足够分辨率。可能的值为Python 2.7中的’posix’,’nt’,’os2’,’ce’,’java’或’riscos’,而自Python 3.4起仅使用’posix’,’nt’和’java’。

  • sys.platform是更好的解决方案。建议使用if sys.platform.startswith('linux')成语,因为“ linux2”表示Linux内核版本为2.xx或3。目前从未使用过较早的内核。在Python 3.3中,所有Linux系统都是简单的“ Linux”。

我不知道“ Mac”和“ Java”系统的详细信息,因此我不能使用非常好的方法platform.system()的结果进行分支,但是我将利用platform模块的优势进行消息和错误记录。

It depends on whether you prefer raising exception or trying anything on an untested system and whether your code is so high level or so low level that it can or can’t work on a similar untested system (e.g. untested Mac – ‘posix’ or on embedded ARM systems). More pythonic is to not enumerate all known systems but to test possible relevant properties. (e.g. it is considered important the endianess of the system but unimportant multiprocessing properties.)

  • os.name is a sufficient resolution for the correct usage of os module. Possible values are ‘posix’, ‘nt’, ‘os2’, ‘ce’, ‘java’ or ‘riscos’ in Python 2.7, while only the ‘posix’, ‘nt’ and ‘java’ are used since Python 3.4.

  • sys.platform is a finer resolution. It is recommended to use if sys.platform.startswith('linux') idiom because “linux2” means a Linux kernel version 2.xx or 3. Older kernels are currently never used. In Python 3.3 are all Linux systems simple ‘linux’.

I do not know the specifics of “Mac” and “Java” systems and so I can not use the results of very good method platform.system() for branching, but I would use advantages of the platform module for messages and error logging.


回答 4

我相信平台模块可能是新代码的首选。其他人在此之前存在。这是一个演变,其余的则是为了向后兼容。

I believe the platform module is probably preferred for new code. The others existed before it. It is an evolution, and the others remain for backwards compatibility.


排序Python`import x`和`from x import y`语句的正确方法是什么?

问题:排序Python`import x`和`from x import y`语句的正确方法是什么?

Python风格指南建议对进口组这样的:

导入应按以下顺序分组:

  1. 标准库导入
  2. 相关第三方进口
  3. 本地应用程序/特定于库的导入

但是,它没有提及应如何布置两种不同的进口方式的内容:

from foo import bar
import foo

对它们进行排序有多种方法(假设所有这些导入都属于同一组):

  • 首先from..import,然后import

    from g import gg
    from x import xx
    import abc
    import def
    import x
    
  • 首先import,然后from..import

    import abc
    import def
    import x
    from g import gg
    from x import xx
    
  • 按模块名称的字母顺序,忽略导入的类型

    import abc
    import def
    from g import gg
    import x
    from xx import xx
    

PEP8没有提到此命令的首选顺序,某些IDE的“清除导入”功能可能只是该工具的开发人员所做的任何事情。

我正在寻找另一个PEP来澄清这一点,或从BDFL(或另一个Python核心开发人员)那里获得相关的评论/电子邮件请不要发布主观答案来说明您的个人偏好。

The python style guide suggests to group imports like this:

Imports should be grouped in the following order:

  1. standard library imports
  2. related third party imports
  3. local application/library specific imports

However, it does not mention anything how the two different ways of imports should be laid out:

from foo import bar
import foo

There are multiple ways to sort them (let’s assume all those import belong to the same group):

  • first from..import, then import

    from g import gg
    from x import xx
    import abc
    import def
    import x
    
  • first import, then from..import

    import abc
    import def
    import x
    from g import gg
    from x import xx
    
  • alphabetic order by module name, ignoring the kind of import

    import abc
    import def
    from g import gg
    import x
    from xx import xx
    

PEP8 does not mention the preferred order for this and the “cleanup imports” features some IDEs have probably just do whatever the developer of that feature preferred.

I’m looking for another PEP clarifying this or a relevant comment/email from the BDFL (or another Python core developer). Please don’t post subjective answers stating your own preference.


回答 0

进口商品通常按字母顺序排序,并在PEP 8的不同位置进行描述。

按字母顺序排序的模块更易于阅读和搜索。毕竟python都是关于可读性的。另外,更容易验证是否导入了某些内容,并避免了重复的导入

PEP 8中没有关于排序的任何信息,因此所有关于选择所用内容的信息都是如此。

根据知名站点和存储库中也很少使用的参考文献,按字母顺序排序是这种方式。

例如:

import httplib
import logging
import random
import StringIO
import time
import unittest
from nova.api import openstack
from nova.auth import users
from nova.endpoint import cloud

要么

import a_standard
import b_standard

import a_third_party
import b_third_party

from a_soc import f
from a_soc import g
from b_soc import d

Reddit官方存储库还指出,通常应使用PEP-8导入顺序。但是有一些补充是

for each imported group the order of imports should be:
import <package>.<module> style lines in alphabetical order
from <package>.<module> import <symbol> style in alphabetical order

参考文献:

PS:isort实用程序会自动对您的导入进行排序。

Imports are generally sorted alphabetically and described in various places beside PEP 8.

Alphabetically sorted modules are quicker to read and searchable. After all python is all about readability. Also It is easier to verify that something is imported, and avoids duplicated imports

There is nothing available in PEP 8 regarding sorting.So its all about choice what you use.

According to few references from reputable sites and repositories also popularity, Alphabetical ordering is the way.

for eg like this:

import httplib
import logging
import random
import StringIO
import time
import unittest
from nova.api import openstack
from nova.auth import users
from nova.endpoint import cloud

OR

import a_standard
import b_standard

import a_third_party
import b_third_party

from a_soc import f
from a_soc import g
from b_soc import d

Reddit official repository also states that, In general PEP-8 import ordering should be used. However there are a few additions which is

for each imported group the order of imports should be:
import <package>.<module> style lines in alphabetical order
from <package>.<module> import <symbol> style in alphabetical order

References:

PS: the isort utility automatically sorts your imports.


回答 1

根据CIA的内部编码约定(WikiLeaks Vault 7泄漏的一部分),python导入应分为三类:

  1. 标准库导入
  2. 第三方进口
  3. 特定于应用程序的导入

在这些组中,应按字典顺序对导入进行排序,而忽略大小写:

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

According to the CIA’s internal coding conventions (part of the WikiLeaks Vault 7 leak), python imports should be grouped into three groups:

  1. Standard library imports
  2. Third-party imports
  3. Application-specific imports

Imports should be ordered lexicographically within these groups, ignoring case:

import foo
from foo import bar
from foo.bar import baz
from foo.bar import Quux
from Foob import ar

回答 2

PEP 8对此一无所获。关于这一点,没有约定,这并不意味着Python社区需要绝对定义一个。对于一个项目而言,选择可能会更好,而对于另一个项目而言,则是最糟糕的……这是一个偏好设置的问题,因为每种解决方案都有其优缺点。但是,如果要遵循约定,则必须遵守引用的主要顺序:

  1. 标准库导入
  2. 相关第三方进口
  3. 本地应用程序/特定于库的导入

例如,Google在此页面建议导入应按字典类别在每个类别(标准/第三方/您的)中进行排序。但是在Facebook,Yahoo和其他地方,这可能是另一种惯例…

The PEP 8 says nothing about it indeed. There’s no convention for this point, and it doesn’t mean the Python community need to define one absolutely. A choice can be better for a project but the worst for another… It’s a question of preferences for this, since each solutions has pro and cons. But if you want to follow conventions, you have to respect the principal order you quoted:

  1. standard library imports
  2. related third party imports
  3. local application/library specific imports

For example, Google recommend in this page that import should be sorted lexicographically, in each categories (standard/third parties/yours). But at Facebook, Yahoo and whatever, it’s maybe another convention…


回答 3

我强烈建议reorder-python-imports。它遵循已接受答案的第二个选项,并且还集成到pre-commit中,这非常有帮助。

I highly recommend reorder-python-imports. It follows the 2nd option of the accepted answer and also integrates into pre-commit, which is super helpful.


回答 4

所有import x语句应按的值排序x,所有from x import y语句应按的值x按字母顺序排序,并且已排序的from x import y语句组必须遵循已排序的import x语句组。

import abc
import def
import x
from g import gg
from x import xx
from z import a

All import x statements should be sorted by the value of x and all from x import y statements should be sorted by the value of x in alphabetical order and the sorted groups of from x import y statements must follow the sorted group of import x statements.

import abc
import def
import x
from g import gg
from x import xx
from z import a

回答 5

我觉得已接受的答案有点太冗长。这是TLDR:

在每个分组中,应按照每个模块的完整包装路径,按字典顺序对导入进行排序,而忽略大小写

Google代码样式指南

因此,第三个选项是正确的:

import abc
import def
from g import yy  # changed gg->yy for illustrative purposes
import x
from xx import xx

I feel like the accepted answer is a bit too verbose. Here is TLDR:

Within each grouping, imports should be sorted lexicographically, ignoring case, according to each module’s full package path

Google code style guide

So, the third option is correct:

import abc
import def
from g import yy  # changed gg->yy for illustrative purposes
import x
from xx import xx

如何动态加载Python类

问题:如何动态加载Python类

给定一个Python类的字符串,例如my_package.my_module.MyClass,最好的加载方式是什么?

换句话说,我正在寻找Class.forName()Java中等效的Python函数。它需要在Google App Engine上工作。

最好是一个函数,该函数接受类的FQN作为字符串,并返回对该类的引用:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

Given a string of a Python class, e.g. my_package.my_module.MyClass, what is the best possible way to load it?

In other words I am looking for a equivalent Class.forName() in Java, function in Python. It needs to work on Google App Engine.

Preferably this would be a function that accepts the FQN of the class as a string, and returns a reference to the class:

my_class = load_class('my_package.my_module.MyClass')
my_instance = my_class()

回答 0

在python文档中,这是您想要的功能:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

一个简单的方法__import__不起作用的原因是,任何超出包字符串中第一个点的导入都是您要导入的模块的属性。因此,类似这样的方法将不起作用:

__import__('foo.bar.baz.qux')

您必须像这样调用上述函数:

my_import('foo.bar.baz.qux')

或以您的示例为例:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

编辑:我对此有些反对。您基本上想做的是这样的:

from my_package.my_module import my_class

仅当您的发件人列表为空时,才需要上述功能。因此,适当的调用将如下所示:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

From the python documentation, here’s the function you want:

def my_import(name):
    components = name.split('.')
    mod = __import__(components[0])
    for comp in components[1:]:
        mod = getattr(mod, comp)
    return mod

The reason a simple __import__ won’t work is because any import of anything past the first dot in a package string is an attribute of the module you’re importing. Thus, something like this won’t work:

__import__('foo.bar.baz.qux')

You’d have to call the above function like so:

my_import('foo.bar.baz.qux')

Or in the case of your example:

klass = my_import('my_package.my_module.my_class')
some_object = klass()

EDIT: I was a bit off on this. What you’re basically wanting to do is this:

from my_package.my_module import my_class

The above function is only necessary if you have a empty fromlist. Thus, the appropriate call would be like this:

mod = __import__('my_package.my_module', fromlist=['my_class'])
klass = getattr(mod, 'my_class')

回答 1

如果您不想自己动手,则pydoc模块中有一个函数可以完全执行此操作:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

与此处列出的其他方法相比,此方法的优势在于,locate它将在提供的虚线路径中找到任何 python对象,而不仅仅是直接在模块内的对象。例如my_package.my_module.MyClass.attr

如果您想知道他们的食谱是什么,请使用以下功能:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

它依赖pydoc.safeimport功能。这是该文档:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

If you don’t want to roll your own, there is a function available in the pydoc module that does exactly this:

from pydoc import locate
my_class = locate('my_package.my_module.MyClass')

The advantage of this approach over the others listed here is that locate will find any python object at the provided dotted path, not just an object directly within a module. e.g. my_package.my_module.MyClass.attr.

If you’re curious what their recipe is, here’s the function:

def locate(path, forceload=0):
    """Locate an object by name or dotted path, importing as necessary."""
    parts = [part for part in split(path, '.') if part]
    module, n = None, 0
    while n < len(parts):
        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
        if nextmodule: module, n = nextmodule, n + 1
        else: break
    if module:
        object = module
    else:
        object = __builtin__
    for part in parts[n:]:
        try:
            object = getattr(object, part)
        except AttributeError:
            return None
    return object

It relies on pydoc.safeimport function. Here are the docs for that:

"""Import a module; handle errors; return None if the module isn't found.

If the module *is* found but an exception occurs, it's wrapped in an
ErrorDuringImport exception and reraised.  Unlike __import__, if a
package path is specified, the module at the end of the path is returned,
not the package at the beginning.  If the optional 'forceload' argument
is 1, we reload the module from disk (unless it's a dynamic extension)."""

回答 2

import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()
import importlib

module = importlib.import_module('my_package.my_module')
my_class = getattr(module, 'MyClass')
my_instance = my_class()

回答 3

def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)
def import_class(cl):
    d = cl.rfind(".")
    classname = cl[d+1:len(cl)]
    m = __import__(cl[0:d], globals(), locals(), [classname])
    return getattr(m, classname)

回答 4

如果您使用的是Django,则可以使用它。是的,我知道OP并没有要求使用django,但是我遇到了一个问题,寻找Django解决方案,没有找到一个解决方案,并将其放在这里供下一个寻找它的下一个男孩/女孩使用。

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

请记住,如果您要导入不带.re或的东西,请argparse使用:

re = __import__('re')

If you’re using Django you can use this. Yes i’m aware OP did not ask for django, but i ran across this question looking for a Django solution, didn’t find one, and put it here for the next boy/gal that looks for it.

# It's available for v1.7+
# https://github.com/django/django/blob/stable/1.7.x/django/utils/module_loading.py
from django.utils.module_loading import import_string

Klass = import_string('path.to.module.Klass')
func = import_string('path.to.module.func')
var = import_string('path.to.module.var')

Keep in mind, if you want to import something that doesn’t have a ., like re or argparse use:

re = __import__('re')

回答 5

这里是分享我在__import__和发现的东西importlib试图解决这个问题。

我正在使用Python 3.7.3。

当我尝试进入d模块中的类时a.b.c

mod = __import__('a.b.c')

mod变量引用顶部命名空间a

所以要上课d,我需要

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

如果我们尝试去做

mod = __import__('a.b.c')
d = getattr(mod, 'd')

我们实际上是在寻找a.d

使用时importlib,我想该库已getattr为我们完成了递归操作。因此,当我们使用时importlib.import_module,我们实际上得到了最深模块的句柄。

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

Here is to share something I found on __import__ and importlib while trying to solve this problem.

I am using Python 3.7.3.

When I try to get to the class d in module a.b.c,

mod = __import__('a.b.c')

The mod variable refer to the top namespace a.

So to get to the class d, I need to

mod = getattr(mod, 'b') #mod is now module b
mod = getattr(mod, 'c') #mod is now module c
mod = getattr(mod, 'd') #mod is now class d

If we try to do

mod = __import__('a.b.c')
d = getattr(mod, 'd')

we are actually trying to look for a.d.

When using importlib, I suppose the library has done the recursive getattr for us. So, when we use importlib.import_module, we actually get a handle on the deepest module.

mod = importlib.import_module('a.b.c') #mod is module c
d = getattr(mod, 'd') #this is a.b.c.d

回答 6

好的,对我来说,这就是它的工作方式(我正在使用Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

然后,b是类’MyClass’的实例

OK, for me that is the way it worked (I am using Python 2.7):

a = __import__('file_to_import', globals(), locals(), ['*'], -1)
b = a.MyClass()

Then, b is an instance of class ‘MyClass’


回答 7

如果您碰巧已经有了所需类的实例,则可以使用’type’函数提取其类类型,并使用它来构造新的实例:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

If you happen to already have an instance of your desired class, you can use the ‘type’ function to extract its class type and use this to construct a new instance:

class Something(object):
    def __init__(self, name):
        self.name = name
    def display(self):
        print(self.name)

one = Something("one")
one.display()
cls = type(one)
two = cls("two")
two.display()

回答 8

module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()
module = __import__("my_package/my_module")
the_class = getattr(module, "MyClass")
obj = the_class()

回答 9

在Google App Engine中,有一个webapp2名为的函数import_string。有关更多信息,请参见此处: https //webapp-improved.appspot.com/api/webapp2.html

所以,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

例如,webapp2.Route在可以使用处理程序或字符串的地方使用它。

In Google App Engine there is a webapp2 function called import_string. For more info see here:https://webapp-improved.appspot.com/api/webapp2.html

So,

import webapp2
my_class = webapp2.import_string('my_package.my_module.MyClass')

For example this is used in the webapp2.Route where you can either use a handler or a string.


从__future__导入absolute_import实际起什么作用?

问题:从__future__导入absolute_import实际起什么作用?

我已经回答了有关Python中绝对导入的问题,我认为通过阅读Python 2.5 changelog和随附的PEP可以理解。但是,在安装Python 2.5并尝试制作一个正确使用的示例时from __future__ import absolute_import,我意识到事情还不清楚。

直接从上面链接的更改日志,此语句准确总结了我对绝对导入更改的理解:

假设您有一个像这样的包目录:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

这定义了一个名为的包,pkg其中包含pkg.mainpkg.string子模块。

考虑main.py模块中的代码。如果执行该语句会import string怎样?在Python 2.4和更早的版本,它会先看看在包的目录进行相对进口,发现包装/ string.py,进口该文件的内容pkg.string模块,并且该模块被绑定到名字"string"pkg.main模块的命名空间。

所以我创建了这个确切的目录结构:

$ ls -R
.:
pkg/

./pkg:
__init__.py  main.py  string.py

__init__.py并且string.py是空的。main.py包含以下代码:

import string
print string.ascii_uppercase

不出所料,使用Python 2.5运行此命令失败,并显示AttributeError

$ python2.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

但是,在2.5更新日志中,我们发现了这一点(添加了重点):

在Python 2.5中,您可以import使用from __future__ import absolute_import指令将的行为切换为绝对导入。在将来的版本(可能是Python 2.7)中,此绝对导入行为将成为默认设置。一旦将绝对导入设置为默认设置,import string就将始终找到标准库的版本。

因此pkg/main2.py,我创建了,main.py但与将来的import指令相同。现在看起来像这样:

from __future__ import absolute_import
import string
print string.ascii_uppercase

但是,使用Python 2.5运行它会失败AttributeError

$ python2.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

这个漂亮的断然反驳该语句import string始终找到STD-库版本绝对进口启用。而且,尽管警告了绝对导入已计划成为“新的默认”行为,但无论使用还是不使用__future__指令,我都使用Python 2.7遇到了相同的问题:

$ python2.7 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

$ python2.7 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

以及Python 3.5(有无)(假设print两个文件中的语句均已更改):

$ python3.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

$ python3.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

我已经测试了其他变化。相反的string.py,我已经创建了一个空的模块-一个新的目录string仅包含一个空的__init__.py-而不是从发放的进口main.py,我有cd“d到pkg并直接从REPL运行的进口。这些变体(或它们的组合)都没有改变上面的结果。我无法将其与我已阅读的有关__future__指令和绝对导入的内容相协调。

在我看来,这很容易通过以下方式进行解释(这是来自Python 2文档,但该语句在适用于Python 3的同一文档中保持不变):

系统路径

(…)

在程序启动时进行初始化,该列表的第一项path[0]是包含用于调用Python解释器的脚本的目录。如果脚本目录不可用(例如,如果解释器是交互式调用的,或者从标准输入中读取了脚本),path[0]则为空字符串,字符串将Python首先引导到当前目录中的搜索模块。

那我想念什么呢?为什么该__future__声明似乎不按其要求行事?在文档的这两部分之间以及所描述的行为与实际行为之间,这种矛盾的解决方案是什么?

I have answered a question regarding absolute imports in Python, which I thought I understood based on reading the Python 2.5 changelog and accompanying PEP. However, upon installing Python 2.5 and attempting to craft an example of properly using from __future__ import absolute_import, I realize things are not so clear.

Straight from the changelog linked above, this statement accurately summarized my understanding of the absolute import change:

Let’s say you have a package directory like this:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

This defines a package named pkg containing the pkg.main and pkg.string submodules.

Consider the code in the main.py module. What happens if it executes the statement import string? In Python 2.4 and earlier, it will first look in the package’s directory to perform a relative import, finds pkg/string.py, imports the contents of that file as the pkg.string module, and that module is bound to the name "string" in the pkg.main module’s namespace.

So I created this exact directory structure:

$ ls -R
.:
pkg/

./pkg:
__init__.py  main.py  string.py

__init__.py and string.py are empty. main.py contains the following code:

import string
print string.ascii_uppercase

As expected, running this with Python 2.5 fails with an AttributeError:

$ python2.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

However, further along in the 2.5 changelog, we find this (emphasis added):

In Python 2.5, you can switch import‘s behaviour to absolute imports using a from __future__ import absolute_import directive. This absolute-import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default, import string will always find the standard library’s version.

I thus created pkg/main2.py, identical to main.py but with the additional future import directive. It now looks like this:

from __future__ import absolute_import
import string
print string.ascii_uppercase

Running this with Python 2.5, however… fails with an AttributeError:

$ python2.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

This pretty flatly contradicts the statement that import string will always find the std-lib version with absolute imports enabled. What’s more, despite the warning that absolute imports are scheduled to become the “new default” behavior, I hit this same problem using both Python 2.7, with or without the __future__ directive:

$ python2.7 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

$ python2.7 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

as well as Python 3.5, with or without (assuming the print statement is changed in both files):

$ python3.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

$ python3.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

I have tested other variations of this. Instead of string.py, I have created an empty module — a directory named string containing only an empty __init__.py — and instead of issuing imports from main.py, I have cd‘d to pkg and run imports directly from the REPL. Neither of these variations (nor a combination of them) changed the results above. I cannot reconcile this with what I have read about the __future__ directive and absolute imports.

It seems to me that this is easily explicable by the following (this is from the Python 2 docs but this statement remains unchanged in the same docs for Python 3):

sys.path

(…)

As initialized upon program startup, the first item of this list, path[0], is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input), path[0] is the empty string, which directs Python to search modules in the current directory first.

So what am I missing? Why does the __future__ statement seemingly not do what it says, and what is the resolution of this contradiction between these two sections of documentation, as well as between described and actual behavior?


回答 0

变更日志的字眼很草率。from __future__ import absolute_import并不关心某些东西是否是标准库的一部分,import string也不会总是为您提供启用绝对导入的标准库模块。

from __future__ import absolute_import表示如果您愿意import string,Python将始终寻找顶级string模块,而不是current_package.string。但是,它不会影响Python用于确定string模块文件的逻辑。当你做

python pkg/script.py

pkg/script.py看起来不像是Python软件包的一部分。按照正常步骤,将pkg目录添加到路径,.py目录中的所有文件pkg看起来都像顶级模块。import string发现pkg/string.py不是因为它正在执行相对导入,而是因为它pkg/string.py似乎是顶级模块string。这不是标准库string模块的事实并没有出现。

要将文件作为pkg软件包的一部分运行,您可以

python -m pkg.script

在这种情况下,该pkg目录将不会添加到路径中。但是,当前目录将被添加到路径中。

您还可以添加一些样板,pkg/script.py以使Python pkg即使在作为文件运行时也将其视为包的一部分:

if __name__ == '__main__' and __package__ is None:
    __package__ = 'pkg'

但是,这不会影响sys.path。您需要进行一些其他处理才能pkg从路径中删除目录,并且如果pkg的父目录不在路径中,则也需要将其粘贴在路径中。

The changelog is sloppily worded. from __future__ import absolute_import does not care about whether something is part of the standard library, and import string will not always give you the standard-library module with absolute imports on.

from __future__ import absolute_import means that if you import string, Python will always look for a top-level string module, rather than current_package.string. However, it does not affect the logic Python uses to decide what file is the string module. When you do

python pkg/script.py

pkg/script.py doesn’t look like part of a package to Python. Following the normal procedures, the pkg directory is added to the path, and all .py files in the pkg directory look like top-level modules. import string finds pkg/string.py not because it’s doing a relative import, but because pkg/string.py appears to be the top-level module string. The fact that this isn’t the standard-library string module doesn’t come up.

To run the file as part of the pkg package, you could do

python -m pkg.script

In this case, the pkg directory will not be added to the path. However, the current directory will be added to the path.

You can also add some boilerplate to pkg/script.py to make Python treat it as part of the pkg package even when run as a file:

if __name__ == '__main__' and __package__ is None:
    __package__ = 'pkg'

However, this won’t affect sys.path. You’ll need some additional handling to remove the pkg directory from the path, and if pkg‘s parent directory isn’t on the path, you’ll need to stick that on the path too.


回答 1

绝对导入和相对导入之间的差异仅在您从包中导入一个模块并且该模块从该包中导入另一个子模块时才起作用。看到不同:

$ mkdir pkg
$ touch pkg/__init__.py
$ touch pkg/string.py
$ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pkg/main1.py", line 1, in <module>
    import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
>>> 
$ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 

特别是:

$ python2 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 1, in <module>
    from __future__ import absolute_import;import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 
$ python2 -m pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ

请注意,python2 pkg/main2.py启动python2和导入后的行为不同pkg.main2(等同于使用-m开关)。

如果要运行程序包的子模块,请始终使用该-m开关,该开关可防止解释器链接sys.path列表并正确处理子模块的语义。

另外,我更喜欢对包子模块使用显式相对导入,因为它们在失败的情况下提供了更多的语义和更好的错误消息。

The difference between absolute and relative imports come into play only when you import a module from a package and that module imports an other submodule from that package. See the difference:

$ mkdir pkg
$ touch pkg/__init__.py
$ touch pkg/string.py
$ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pkg/main1.py", line 1, in <module>
    import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
>>> 
$ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 

In particular:

$ python2 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 1, in <module>
    from __future__ import absolute_import;import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 
$ python2 -m pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ

Note that python2 pkg/main2.py has a different behaviour then launching python2 and then importing pkg.main2 (which is equivalent to using the -m switch).

If you ever want to run a submodule of a package always use the -m switch which prevents the interpreter for chaining the sys.path list and correctly handles the semantics of the submodule.

Also, I much prefer using explicit relative imports for package submodules since they provide more semantics and better error messages in case of failure.


为什么“导入*”不好?

问题:为什么“导入*”不好?

建议不要import *在Python中使用。

任何人都可以分享原因,以便下次可以避免吗?

It is recommended to not to use import * in Python.

Can anyone please share the reason for that, so that I can avoid it doing next time?


回答 0

  • 因为它在命名空间中放入了很多东西(可能会遮盖以前导入的其他对象,所以您将一无所知)。

  • 因为您不完全知道要导入的内容,而且不容易找到从哪个模块导入的内容(可读性)。

  • 因为您不能使用像pyflakes静态检测代码中的错误之类的出色工具。

  • Because it puts a lot of stuff into your namespace (might shadow some other object from previous import and you won’t know about it).

  • Because you don’t know exactly what is imported and can’t easily find from which module a certain thing was imported (readability).

  • Because you can’t use cool tools like pyflakes to statically detect errors in your code.


回答 1

根据Python禅宗

显式胜于隐式。

…不能肯定地说吗?

According to the Zen of Python:

Explicit is better than implicit.

… can’t argue with that, surely?


回答 2

您不传递**locals()给函数,是吗?

因为Python缺少“包括”语句,并且self参数是明确的,而且范围规则相当简单,它通常很容易在一个变量指向一个手指,告诉哪里该对象来自-没有阅读其他模块,无任何IDE(由于语言是非常动态的,因此反省自省的方式)。

import *休息了这一切。

而且,它有隐藏错误的具体可能性。

import os, sys, foo, sqlalchemy, mystuff
from bar import *

现在,如果bar模块具有“ os”,“ mystuff”等属性中的任何一个,它们将覆盖显式导入的属性,并可能指向非常不同的事物。__all__在bar中定义通常是很明智的-这说明了要隐式导入的内容-但是,如果不读取和解析bar模块并跟随导入,仍然很难跟踪对象的来源。import *获得项目所有权时,首先要解决的网络问题。

不要误会我:如果import *丢失了,我会哭着拥有它。但是必须谨慎使用。一个好的用例是在另一个模块上提供Facade接口。同样,使用条件导入语句或在函数/类命名空间中进行导入也需要一些纪律。

我认为在大中型项目或具有多个贡献者的小型项目中,就静态分析而言,至少需要保持卫生(至少运行pyflakes甚至更好地配置正确的pylint)才能捕获多种错误。他们发生了。

当然,由于这是python-可以随意打破规则并进行探索-但要警惕可能增长十倍的项目,如果源代码缺少规范,那将是一个问题。

You don’t pass **locals() to functions, do you?

Since Python lacks an “include” statement, and the self parameter is explicit, and scoping rules are quite simple, it’s usually very easy to point a finger at a variable and tell where that object comes from — without reading other modules and without any kind of IDE (which are limited in the way of introspection anyway, by the fact the language is very dynamic).

The import * breaks all that.

Also, it has a concrete possibility of hiding bugs.

import os, sys, foo, sqlalchemy, mystuff
from bar import *

Now, if the bar module has any of the “os“, “mystuff“, etc… attributes, they will override the explicitly imported ones, and possibly point to very different things. Defining __all__ in bar is often wise — this states what will implicitly be imported – but still it’s hard to trace where objects come from, without reading and parsing the bar module and following its imports. A network of import * is the first thing I fix when I take ownership of a project.

Don’t misunderstand me: if the import * were missing, I would cry to have it. But it has to be used carefully. A good use case is to provide a facade interface over another module. Likewise, the use of conditional import statements, or imports inside function/class namespaces, requires a bit of discipline.

I think in medium-to-big projects, or small ones with several contributors, a minimum of hygiene is needed in terms of statical analysis — running at least pyflakes or even better a properly configured pylint — to catch several kind of bugs before they happen.

Of course since this is python — feel free to break rules, and to explore — but be wary of projects that could grow tenfold, if the source code is missing discipline it will be a problem.


回答 3

可以from ... import *在交互式会话中进行。

It is OK to do from ... import * in an interactive session.


回答 4

那是因为您正在污染命名空间。您将在自己的命名空间中导入所有函数和类,这可能与您自己定义的函数冲突。

此外,我认为在维护任务中使用限定名称更为明确;您会在代码行本身上看到函数的来源,因此可以更轻松地签出文档。

在模块foo中:

def myFunc():
    print 1

在您的代码中:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2

That is because you are polluting the namespace. You will import all the functions and classes in your own namespace, which may clash with the functions you define yourself.

Furthermore, I think using a qualified name is more clear for the maintenance task; you see on the code line itself where a function comes from, so you can check out the docs much more easily.

In module foo:

def myFunc():
    print 1

In your code:

from foo import *

def doThis():
    myFunc() # Which myFunc is called?

def myFunc():
    print 2

回答 5

http://docs.python.org/tutorial/modules.html

请注意,通常不赞成*从模块或包进行导入的做法,因为这通常会导致可读性差的代码

http://docs.python.org/tutorial/modules.html

Note that in general the practice of importing * from a module or package is frowned upon, since it often causes poorly readable code.


回答 6

假设您在名为foo的模块中具有以下代码:

import ElementTree as etree

然后在您自己的模块中,您可以:

from lxml import etree
from foo import *

现在,您有了一个难以调试的模块,看起来其中包含lxml的etree,但实际上是ElementTree。

Say you have the following code in a module called foo:

import ElementTree as etree

and then in your own module you have:

from lxml import etree
from foo import *

You now have a difficult-to-debug module that looks like it has lxml’s etree in it, but really has ElementTree instead.


回答 7

这些都是很好的答案。我要补充一点,当教新人们使用Python进行编码时,处理import *非常困难。即使您或他们没有编写代码,它仍然是绊脚石。

我教孩子们(大约8岁)用Python编程来操纵Minecraft。我喜欢给他们一个有用的编码环境,以供他们使用(Atom Editor)并教授REPL驱动的开发(通过bpython)。在Atom中,我发现提示/完成与bpython一样有效。幸运的是,与其他一些统计分析工具不同,Atom并不受它的欺骗import *

但是,让我们举个例子…在这个包装器中,他们from local_module import *是一堆模块,其中包括这个块列表。让我们忽略命名空间冲突的风险。通过这样做,您from mcpi.block import *就可以使晦涩难懂的块的整个列表成为必需的东西,以便您了解可用的块。如果他们改用from mcpi import block,则可以键入walls = block.,然后会弹出一个自动完成列表。

These are all good answers. I’m going to add that when teaching new people to code in Python, dealing with import * is very difficult. Even if you or they didn’t write the code, it’s still a stumbling block.

I teach children (about 8 years old) to program in Python to manipulate Minecraft. I like to give them a helpful coding environment to work with (Atom Editor) and teach REPL-driven development (via bpython). In Atom I find that the hints/completion works just as effectively as bpython. Luckily, unlike some other statistical analysis tools, Atom is not fooled by import *.

However, lets take this example… In this wrapper they from local_module import * a bunch modules including this list of blocks. Let’s ignore the risk of namespace collisions. By doing from mcpi.block import * they make this entire list of obscure types of blocks something that you have to go look at to know what is available. If they had instead used from mcpi import block, then you could type walls = block. and then an autocomplete list would pop up.


回答 8

了解了人们在这里提出的有效观点。但是,我确实有一个论点,有时“星号导入”可能并不总是一个坏习惯:

  • 当我想以所有常量都进入名为的模块的方式构造代码时const.py
    • 如果我这样做import const,那么对于每个常量,我都必须将其称为const.SOMETHING,这可能不是最方便的方法。
    • 如果我这样做了from const import SOMETHING_A, SOMETHING_B ...,那么显然它太冗长而无法达到结构化的目的。
    • 因此,我觉得在这种情况下,执行a from const import *可能是更好的选择。

Understood the valid points people put here. However, I do have one argument that, sometimes, “star import” may not always be a bad practice:

  • When I want to structure my code in such a way that all the constants go to a module called const.py:
    • If I do import const, then for every constant, I have to refer it as const.SOMETHING, which is probably not the most convenient way.
    • If I do from const import SOMETHING_A, SOMETHING_B ..., then obviously it’s way too verbose and defeats the purpose of the structuring.
    • Thus I feel in this case, doing a from const import * may be a better choice.

回答 9

这是非常糟糕的做法,原因有两个:

  1. 代码可读性
  2. 覆盖变量/功能等的风险

对于第1点:让我们看一个例子:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

在这里,看到代码,没有人会得到关于从哪个模块的想法bc并且d实际上属于。

另一方面,如果您这样做,则:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

这对您来说更加清洁,加入团队的新人也会有更好的主意。

对于第2点:让两者都说出来,module1并将module2变量as设置为b。当我做:

from module1 import *
from module2 import *

print b  # will print the value from module2

此处的价值module1丢失。很难调试为什么即使b声明了module1并且我已经编写了期望我的代码使用的代码也无法正常工作的原因module1.b

如果不同模块中的变量相同,并且不想导入整个模块,则可以执行以下操作:

from module1 import b as mod1b
from module2 import b as mod2b

It is a very BAD practice for two reasons:

  1. Code Readability
  2. Risk of overriding the variables/functions etc

For point 1: Let’s see an example of this:

from module1 import *
from module2 import *
from module3 import *

a = b + c - d

Here, on seeing the code no one will get idea regarding from which module b, c and d actually belongs.

On the other way, if you do it like:

#                   v  v  will know that these are from module1
from module1 import b, c   # way 1
import module2             # way 2

a = b + c - module2.d
#            ^ will know it is from module2

It is much cleaner for you, and also the new person joining your team will have better idea.

For point 2: Let say both module1 and module2 have variable as b. When I do:

from module1 import *
from module2 import *

print b  # will print the value from module2

Here the value from module1 is lost. It will be hard to debug why the code is not working even if b is declared in module1 and I have written the code expecting my code to use module1.b

If you have same variables in different modules, and you do not want to import entire module, you may even do:

from module1 import b as mod1b
from module2 import b as mod2b

回答 10

作为测试,我创建了一个模块test.py,其中包含2个函数A和B,分别打印“ A 1”和“ B 1”。使用以下命令导入test.py之后:

import test

。。。我可以将两个函数分别作为test.A()和test.B()运行,并且“ test” 在命名空间中显示为模块,因此,如果我编辑test.py,可以使用以下命令重新加载它:

import importlib
importlib.reload(test)

但是,如果我执行以下操作:

from test import *

在命名空间中没有对“测试”的引用,因此在编辑后(据我所知),没有办法重新加载它,这在交互式会话中是一个问题。而以下任何一项:

import test
import test as tt

将在命名空间中分别添加“ test”或“ tt”作为模块名称,这将允许重新加载。

如果我做:

from test import *

名称“ A”和“ B”作为功能出现在命名空间中。如果我编辑test.py,并重复以上命令,则不会重新加载功能的修改版本。

并且以下命令引发错误消息。

importlib.reload(test)    # Error - name 'test' is not defined

如果有人知道如何重新加载加载有“ from module import *”的模块,请发布。否则,这是避免使用该表格的另一个原因:

from module import *

As a test, I created a module test.py with 2 functions A and B, which respectively print “A 1” and “B 1”. After importing test.py with:

import test

. . . I can run the 2 functions as test.A() and test.B(), and “test” shows up as a module in the namespace, so if I edit test.py I can reload it with:

import importlib
importlib.reload(test)

But if I do the following:

from test import *

there is no reference to “test” in the namespace, so there is no way to reload it after an edit (as far as I can tell), which is a problem in an interactive session. Whereas either of the following:

import test
import test as tt

will add “test” or “tt” (respectively) as module names in the namespace, which will allow re-loading.

If I do:

from test import *

the names “A” and “B” show up in the namespace as functions. If I edit test.py, and repeat the above command, the modified versions of the functions do not get reloaded.

And the following command elicits an error message.

importlib.reload(test)    # Error - name 'test' is not defined

If someone knows how to reload a module loaded with “from module import *”, please post. Otherwise, this would be another reason to avoid the form:

from module import *

回答 11

如文档中所建议,您(几乎)永远不要import *在生产代码中使用。

虽然*模块导入很不好,但是包中导入*更糟。默认情况下,from package import *导入包的定义的任何名称__init__.py,包括先前import语句加载的包的任何子模块。

但是,如果包的__init__.py代码定义了名为的列表__all__,则将其视为from package import *遇到时应导入的子模块名称的列表。

考虑以下示例(假设在中__all__未定义sound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

最后一条语句会将echosurround模块导入当前的命名空间(可能会覆盖先前的定义),因为它们是在执行语句sound.effects时在包中定义的import

As suggested in the docs, you should (almost) never use import * in production code.

While importing * from a module is bad, importing * from a package is probably even worse.

By default, from package import * imports whatever names are defined by the package’s __init__.py, including any submodules of the package that were loaded by previous import statements.

If a package’s __init__.py code defines a list named __all__, it is taken to be the list of submodule names that should be imported when from package import * is encountered.

Now consider this example (assuming there’s no __all__ defined in sound/effects/__init__.py):

# anywhere in the code before import *
import sound.effects.echo
import sound.effects.surround

# in your module
from sound.effects import *

The last statement will import the echo and surround modules into the current namespace (possibly overriding previous definitions) because they are defined in the sound.effects package when the import statement is executed.


如何模拟导入

问题:如何模拟导入

模块A包括import B在其顶部。然而在试验条件下,我想嘲笑 BA(模拟A.B)和进口完全避免B

实际上,B并不是故意在测试环境中安装的。

A是被测单元。我必须导入A所有功能。B是我需要模拟的模块。但是,如果第一件事就是导入,我该如何B在其中模拟A并停止A导入实数?BAB

(未安装B的原因是我使用pypy进行了快速测试,但不幸的是B尚未与pypy兼容。)

怎么办呢?

Module A includes import B at its top. However under test conditions I’d like to mock B in A (mock A.B) and completely refrain from importing B.

In fact, B isn’t installed in the test environment on purpose.

A is the unit under test. I have to import A with all its functionality. B is the module I need to mock. But how can I mock B within A and stop A from importing the real B, if the first thing A does is import B?

(The reason B isn’t installed is that I use pypy for quick testing and unfortunately B isn’t compatible with pypy yet.)

How could this be done?


回答 0

您可以sys.modules['B']在导入之前分配给以A获得所需的内容:

test.py

import sys
sys.modules['B'] = __import__('mock_B')
import A

print(A.B.__name__)

A.py

import B

注意B.py不存在,但是运行时test.py不会返回错误并显示print(A.B.__name__)print mock_B。您仍然必须mock_B.py在模拟B实际功能/变量/等的地方创建一个。或者,您可以直接分配一个Mock()

test.py

import sys
sys.modules['B'] = Mock()
import A

You can assign to sys.modules['B'] before importing A to get what you want:

test.py:

import sys
sys.modules['B'] = __import__('mock_B')
import A

print(A.B.__name__)

A.py:

import B

Note B.py does not exist, but when running test.py no error is returned and print(A.B.__name__) prints mock_B. You still have to create a mock_B.py where you mock B‘s actual functions/variables/etc. Or you can just assign a Mock() directly:

test.py:

import sys
sys.modules['B'] = Mock()
import A

回答 1

__import__可以使用’mock’库来模拟内置函数,以实现更多控制:

# Store original __import__
orig_import = __import__
# This will be the B module
b_mock = mock.Mock()

def import_mock(name, *args):
    if name == 'B':
        return b_mock
    return orig_import(name, *args)

with mock.patch('__builtin__.__import__', side_effect=import_mock):
    import A

A看起来像:

import B

def a():
    return B.func()

A.a()返回b_mock.func()也可以被嘲笑。

b_mock.func.return_value = 'spam'
A.a()  # returns 'spam'

Python 3的注意事项:3.0变更日志所述,__builtin__现名为builtins

将模块重命名__builtin__builtins(删除下划线,添加“ s”)。

如果更换这个答案的代码工作正常__builtin__通过builtins为Python 3。

The builtin __import__ can be mocked with the ‘mock’ library for more control:

# Store original __import__
orig_import = __import__
# This will be the B module
b_mock = mock.Mock()

def import_mock(name, *args):
    if name == 'B':
        return b_mock
    return orig_import(name, *args)

with mock.patch('__builtin__.__import__', side_effect=import_mock):
    import A

Say A looks like:

import B

def a():
    return B.func()

A.a() returns b_mock.func() which can be mocked also.

b_mock.func.return_value = 'spam'
A.a()  # returns 'spam'

Note for Python 3: As stated in the changelog for 3.0, __builtin__ is now named builtins:

Renamed module __builtin__ to builtins (removing the underscores, adding an ‘s’).

The code in this answer works fine if you replace __builtin__ by builtins for Python 3.


回答 2

如何模拟导入(模拟AB)?

模块A在其顶部包括导入B。

容易,只需在导入它之前在sys.modules中模拟该库:

if wrong_platform():
    sys.modules['B'] = mock.MagicMock()

然后,只要A不依赖于从B对象返回的特定类型的数据:

import A

应该工作。

您还可以嘲笑import A.B

即使您有子模块,此方法也有效,但是您将需要模拟每个模块。说你有这个:

from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink

要进行模拟,只需在导入包含以上内容的模块之前执行以下操作:

sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()

(我的经验:我有一个可以在一个平台Windows上运行的依赖项,但是在运行日常测试的Linux上却不起作用。所以我需要为我们的测试模拟该依赖项。幸运的是,这是一个黑盒子,所以我不需要进行很多互动。)

模拟副作用

附录:实际上,我需要模拟花费一些时间的副作用。所以我需要一个对象的方法来睡一秒钟。那会像这样工作:

sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
# setup the side-effect:
from time import sleep

def sleep_one(*args): 
    sleep(1)

# this gives us the mock objects that will be used
from foo.bar import MyObject 
my_instance = MyObject()
# mock the method!
my_instance.method_that_takes_time = mock.MagicMock(side_effect=sleep_one)

然后,就像真实方法一样,代码需要一些时间才能运行。

How to mock an import, (mock A.B)?

Module A includes import B at its top.

Easy, just mock the library in sys.modules before it gets imported:

if wrong_platform():
    sys.modules['B'] = mock.MagicMock()

and then, so long as A doesn’t rely on specific types of data being returned from B’s objects:

import A

should just work.

You can also mock import A.B:

This works even if you have submodules, but you’ll want to mock each module. Say you have this:

from foo import This, That, andTheOtherThing
from foo.bar import Yada, YadaYada
from foo.baz import Blah, getBlah, boink

To mock, simply do the below before the module that contains the above is imported:

sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()

(My experience: I had a dependency that works on one platform, Windows, but didn’t work on Linux, where we run our daily tests. So I needed to mock the dependency for our tests. Luckily it was a black box, so I didn’t need to set up a lot of interaction.)

Mocking Side Effects

Addendum: Actually, I needed to simulate a side-effect that took some time. So I needed an object’s method to sleep for a second. That would work like this:

sys.modules['foo'] = MagicMock()
sys.modules['foo.bar'] = MagicMock()
sys.modules['foo.baz'] = MagicMock()
# setup the side-effect:
from time import sleep

def sleep_one(*args): 
    sleep(1)

# this gives us the mock objects that will be used
from foo.bar import MyObject 
my_instance = MyObject()
# mock the method!
my_instance.method_that_takes_time = mock.MagicMock(side_effect=sleep_one)

And then the code takes some time to run, just like the real method.


回答 3

我意识到我在这里参加聚会有点晚了,但这是一种通过mock库自动执行此操作的疯狂方法:

(这是一个示例用法)

import contextlib
import collections
import mock
import sys

def fake_module(**args):
    return (collections.namedtuple('module', args.keys())(**args))

def get_patch_dict(dotted_module_path, module):
    patch_dict = {}
    module_splits = dotted_module_path.split('.')

    # Add our module to the patch dict
    patch_dict[dotted_module_path] = module

    # We add the rest of the fake modules in backwards
    while module_splits:
        # This adds the next level up into the patch dict which is a fake
        # module that points at the next level down
        patch_dict['.'.join(module_splits[:-1])] = fake_module(
            **{module_splits[-1]: patch_dict['.'.join(module_splits)]}
        )
        module_splits = module_splits[:-1]

    return patch_dict

with mock.patch.dict(
    sys.modules,
    get_patch_dict('herp.derp', fake_module(foo='bar'))
):
    import herp.derp
    # prints bar
    print herp.derp.foo

这是如此荒谬的原因是,当发生导入时,python基本上会这样做(例如from herp.derp import foo

  1. 是否sys.modules['herp']存在?否则导入。如果还没有ImportError
  2. 是否sys.modules['herp.derp']存在?否则导入。如果还没有ImportError
  3. 获取属性foosys.modules['herp.derp']。其他ImportError
  4. foo = sys.modules['herp.derp'].foo

这种被黑客入侵的解决方案有一些缺点:如果模块路径中的其他内容依赖于其他内容,则将其拧紧。而且,这适用于内联导入的内容,例如

def foo():
    import herp.derp

要么

def foo():
    __import__('herp.derp')

I realize I’m a bit late to the party here, but here’s a somewhat insane way to automate this with the mock library:

(here’s an example usage)

import contextlib
import collections
import mock
import sys

def fake_module(**args):
    return (collections.namedtuple('module', args.keys())(**args))

def get_patch_dict(dotted_module_path, module):
    patch_dict = {}
    module_splits = dotted_module_path.split('.')

    # Add our module to the patch dict
    patch_dict[dotted_module_path] = module

    # We add the rest of the fake modules in backwards
    while module_splits:
        # This adds the next level up into the patch dict which is a fake
        # module that points at the next level down
        patch_dict['.'.join(module_splits[:-1])] = fake_module(
            **{module_splits[-1]: patch_dict['.'.join(module_splits)]}
        )
        module_splits = module_splits[:-1]

    return patch_dict

with mock.patch.dict(
    sys.modules,
    get_patch_dict('herp.derp', fake_module(foo='bar'))
):
    import herp.derp
    # prints bar
    print herp.derp.foo

The reason this is so ridiculously complicated is when an import occurs python basically does this (take for example from herp.derp import foo)

  1. Does sys.modules['herp'] exist? Else import it. If still not ImportError
  2. Does sys.modules['herp.derp'] exist? Else import it. If still not ImportError
  3. Get attribute foo of sys.modules['herp.derp']. Else ImportError
  4. foo = sys.modules['herp.derp'].foo

There are some downsides to this hacked together solution: If something else relies on other stuff in the module path this kind of screws it over. Also this only works for stuff that is being imported inline such as

def foo():
    import herp.derp

or

def foo():
    __import__('herp.derp')

回答 4

亚伦·霍尔的答案对我有用。只想提一件事,

如果A.py你愿意

from B.C.D import E

然后test.py您必须模拟路径中的每个模块,否则会得到ImportError

sys.modules['B'] = mock.MagicMock()
sys.modules['B.C'] = mock.MagicMock()
sys.modules['B.C.D'] = mock.MagicMock()

Aaron Hall’s answer works for me. Just want to mention one important thing,

if in A.py you do

from B.C.D import E

then in test.py you must mock every module along the path, otherwise you get ImportError

sys.modules['B'] = mock.MagicMock()
sys.modules['B.C'] = mock.MagicMock()
sys.modules['B.C.D'] = mock.MagicMock()

回答 5

我找到了在Python中模拟导入的好方法。这是Eric的Zaadi解决方案,我在Django应用程序中使用该解决方案。

我有一个类SeatInterface,它是Seat模型类的接口。所以在我的seat_interface模块中,我有这样一个导入:

from ..models import Seat

class SeatInterface(object):
    (...)

我想为SeatInterface模拟Seat类创建隔离测试FakeSeat。问题是-在Django应用程序关闭的情况下,tu运行离线测试的方式。我有以下错误:

配置不正确:请求的设置为BASE_DIR,但未配置设置。您必须先定义环境变量DJANGO_SETTINGS_MODULE或调用settings.configure()才能访问设置。

在0.078秒内进行了1次测试

失败(错误= 1)

解决方案是:

import unittest
from mock import MagicMock, patch

class FakeSeat(object):
    pass

class TestSeatInterface(unittest.TestCase):

    def setUp(self):
        models_mock = MagicMock()
        models_mock.Seat.return_value = FakeSeat
        modules = {'app.app.models': models_mock}
        patch.dict('sys.modules', modules).start()

    def test1(self):
        from app.app.models_interface.seat_interface import SeatInterface

然后测试神奇地运行OK :)


在0.002秒内进行1次测试

I found fine way to mock the imports in Python. It’s Eric’s Zaadi solution found here which I just use inside my Django application.

I’ve got class SeatInterface which is interface to Seat model class. So inside my seat_interface module I have such an import:

from ..models import Seat

class SeatInterface(object):
    (...)

I wanted to create isolated tests for SeatInterface class with mocked Seat class as FakeSeat. The problem was – how tu run tests offline, where Django application is down. I had below error:

ImproperlyConfigured: Requested setting BASE_DIR, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.

Ran 1 test in 0.078s

FAILED (errors=1)

The solution was:

import unittest
from mock import MagicMock, patch

class FakeSeat(object):
    pass

class TestSeatInterface(unittest.TestCase):

    def setUp(self):
        models_mock = MagicMock()
        models_mock.Seat.return_value = FakeSeat
        modules = {'app.app.models': models_mock}
        patch.dict('sys.modules', modules).start()

    def test1(self):
        from app.app.models_interface.seat_interface import SeatInterface

And then test magically runs OK :)

.
Ran 1 test in 0.002s

OK


回答 6

如果这样做,import ModuleB您实际上是在__import__按以下方式调用内置方法:

ModuleB = __import__('ModuleB', globals(), locals(), [], -1)

您可以通过导入__builtin__模块并对该方法进行包装来覆盖此__builtin__.__import__方法。或者,您可以使用模块中的NullImporter挂钩imp。捕获异常并在except-block中模拟您的模块/类。

指向相关文档的指针:

docs.python.org: __import__

使用imp模块访问Import内部

我希望这有帮助。是HIGHLY劝你踏进Python编程的更神秘的周边和一)扎实的了解,你真正要实现和B)的影响的深入理解什么是重要的。

If you do an import ModuleB you are really calling the builtin method __import__ as:

ModuleB = __import__('ModuleB', globals(), locals(), [], -1)

You could overwrite this method by importing the __builtin__ module and make a wrapper around the __builtin__.__import__method. Or you could play with the NullImporter hook from the imp module. Catching the exception and Mock your module/class in the except-block.

Pointer to the relevant docs:

docs.python.org: __import__

Accessing Import internals with the imp Module

I hope this helps. Be HIGHLY adviced that you step into the more arcane perimeters of python programming and that a) solid understanding what you really want to achieve and b)thorough understanding of the implications is important.


您可以在Python中为导入的模块定义别名吗?

问题:您可以在Python中为导入的模块定义别名吗?

在Python中,是否可以为导入的模块定义别名?

例如:

import a_ridiculously_long_module_name

…因此具有别名“ short_name”。

In Python, is it possible to define an alias for an imported module?

For instance:

import a_ridiculously_long_module_name

…so that is has an alias of ‘short_name’.


回答 0

import a_ridiculously_long_module_name as short_name

也适用于

import module.submodule.subsubmodule as short_name
import a_ridiculously_long_module_name as short_name

also works for

import module.submodule.subsubmodule as short_name

回答 1

在这里检查

import module as name

要么

from relative_module import identifier as name

Check here

import module as name

or

from relative_module import identifier as name

回答 2

如果已经完成:

import long_module_name

您还可以通过以下方式为其命名:

lmn = long_module_name

没有理由在代码中以这种方式执行此操作,但有时我发现它在交互式解释器中很有用。

If you’ve done:

import long_module_name

you can also give it an alias by:

lmn = long_module_name

There’s no reason to do it this way in code, but I sometimes find it useful in the interactive interpreter.


回答 3

是的,可以使用别名导入模块。使用作为关键字。看到

import math as ilovemaths # here math module is imported under an alias name
print(ilovemaths.sqrt(4))  # Using the sqrt() function

Yes, modules can be imported under an alias name. using as keyword. See

import math as ilovemaths # here math module is imported under an alias name
print(ilovemaths.sqrt(4))  # Using the sqrt() function

回答 4

从MODULE导入TAGNAME作为ALIAS

from MODULE import TAGNAME as ALIAS


我应该使用`import os.path`还是`import os`?

问题:我应该使用`import os.path`还是`import os`?

根据官方文档os.path是一个模块。因此,导入它的首选方式是什么?

# Should I always import it explicitly?
import os.path

要么…

# Is importing os enough?
import os

请不要回答“ os为我导入作品”。我知道,它现在也对我有效(自python 2.6起)。我想知道的是有关此问题的任何官方建议。因此,如果您回答这个问题,请发表您的参考资料

According to the official documentation, os.path is a module. Thus, what is the preferred way of importing it?

# Should I always import it explicitly?
import os.path

Or…

# Is importing os enough?
import os

Please DON’T answer “importing os works for me”. I know, it works for me too right now (as of Python 2.6). What I want to know is any official recommendation about this issue. So, if you answer this question, please post your references.


回答 0

os.path以一种有趣的方式工作。看起来os应该是带有子模块的程序包path,但实际上os是一个普通的模块,sys.modules可以注入魔力os.path。这是发生了什么:

  • Python启动时,会将一堆模块加载到中sys.modules。它们没有绑定到脚本中的任何名称,但是以某种方式导入它们时,您可以访问已创建的模块。

    • sys.modules是在其中缓存模块的命令。导入模块时,如果已经将其导入到某处,则它将实例存储在中sys.modules
  • os是Python启动时加载的模块之一。它将其path属性分配给特定于os的路径模块。

  • 它会注入,sys.modules['os.path'] = path以便您可以像对待import os.path子模块一样进行“ ”操作。

我倾向于将其os.path看作是我要使用os模块,而不是模块中的任何东西,因此,即使它实际上不是被称为包的子模块os,我也可以像导入一个一样来导入它,并且我总是这样做import os.path。这与os.path记录方式一致。


顺便说一句,我认为这种结构导致很多Python程序员对模块和包以及代码组织产生了早期的困惑。这确实有两个原因

  1. 如果您将其os视为一个包并且知道可以执行import os并有权访问该子模块os.path,则稍后可能会感到惊讶,因为您无法执行import twisted并且twisted.spread无需导入即可自动访问。

  2. 令人困惑的是,这os.name是正常现象,字符串和os.path模块。我总是用空__init__.py文件来构造我的包,以便在同一级别上我总是有一种类型的东西:模块/包或其他东西。几个大型的Python项目都采用这种方法,这往往会使代码更加结构化。

os.path works in a funny way. It looks like os should be a package with a submodule path, but in reality os is a normal module that does magic with sys.modules to inject os.path. Here’s what happens:

  • When Python starts up, it loads a bunch of modules into sys.modules. They aren’t bound to any names in your script, but you can access the already-created modules when you import them in some way.

    • sys.modules is a dict in which modules are cached. When you import a module, if it already has been imported somewhere, it gets the instance stored in sys.modules.
  • os is among the modules that are loaded when Python starts up. It assigns its path attribute to an os-specific path module.

  • It injects sys.modules['os.path'] = path so that you’re able to do “import os.path” as though it was a submodule.

I tend to think of os.path as a module I want to use rather than a thing in the os module, so even though it’s not really a submodule of a package called os, I import it sort of like it is one and I always do import os.path. This is consistent with how os.path is documented.


Incidentally, this sort of structure leads to a lot of Python programmers’ early confusion about modules and packages and code organization, I think. This is really for two reasons

  1. If you think of os as a package and know that you can do import os and have access to the submodule os.path, you may be surprised later when you can’t do import twisted and automatically access twisted.spread without importing it.

  2. It is confusing that os.name is a normal thing, a string, and os.path is a module. I always structure my packages with empty __init__.py files so that at the same level I always have one type of thing: a module/package or other stuff. Several big Python projects take this approach, which tends to make more structured code.


回答 1

根据蒂姆·彼得斯(Tim Peters)撰写的PEP-20,“显式胜于隐式”和“可读性”。如果您需要从os模块中获得的全部在之下os.pathimport os.path则会更加明确,并让其他人知道您真正关心的是什么。

同样,PEP-20也说“简单胜于复杂”,因此,如果您还需要一些更笼统的资料osimport os则首选。

As per PEP-20 by Tim Peters, “Explicit is better than implicit” and “Readability counts”. If all you need from the os module is under os.path, import os.path would be more explicit and let others know what you really care about.

Likewise, PEP-20 also says “Simple is better than complex”, so if you also need stuff that resides under the more-general os umbrella, import os would be preferred.


回答 2

最终答案:import os并使用os.path。不要import os.path直接。

从模块本身的文档中:

>>> import os
>>> help(os.path)
...
Instead of importing this module directly, import os and refer to
this module as os.path.  The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Mac, Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. macpath, ntpath).
...

Definitive answer: import os and use os.path. do not import os.path directly.

From the documentation of the module itself:

>>> import os
>>> help(os.path)
...
Instead of importing this module directly, import os and refer to
this module as os.path.  The "os.path" name is an alias for this
module on Posix systems; on other systems (e.g. Mac, Windows),
os.path provides the same operations in a manner specific to that
platform, and is an alias to another module (e.g. macpath, ntpath).
...

回答 3

有趣的是,导入os.path将导入所有os。在交互式提示中尝试以下操作:

import os.path
dir(os)

结果与导入os相同。这是因为os.path将基于您拥有的操作系​​统引用不同的模块,因此python将导入os以确定要为路径加载哪个模块。

参考

对于某些模块,说import foo不会暴露foo.bar,所以我猜它确实取决于特定模块的设计。


通常,仅导入所需的显式模块应略快一些。在我的机器上:

import os.path 7.54285810068e-06

import os 9.21904878972e-06

这些时间非常接近,可以忽略不计。您的程序可能os现在或以后需要使用其他模块,因此通常只牺牲两个微秒并import os在以后避免该错误就可以了。我通常只将os整体导入,但是可以看到为什么有些人希望import os.path从技术上提高效率,并向代码读者传达这是os需要使用的模块的唯一部分。在我看来,它本质上可以归结为样式问题。

Interestingly enough, importing os.path will import all of os. try the following in the interactive prompt:

import os.path
dir(os)

The result will be the same as if you just imported os. This is because os.path will refer to a different module based on which operating system you have, so python will import os to determine which module to load for path.

reference

With some modules, saying import foo will not expose foo.bar, so I guess it really depends the design of the specific module.


In general, just importing the explicit modules you need should be marginally faster. On my machine:

import os.path: 7.54285810068e-06 seconds

import os: 9.21904878972e-06 seconds

These times are close enough to be fairly negligible. Your program may need to use other modules from os either now or at a later time, so usually it makes sense just to sacrifice the two microseconds and use import os to avoid this error at a later time. I usually side with just importing os as a whole, but can see why some would prefer import os.path to technically be more efficient and convey to readers of the code that that is the only part of the os module that will need to be used. It essentially boils down to a style question in my mind.


回答 4

常识在这里起作用:os是模块,os.path也是模块。因此,只需导入要使用的模块:

  • 如果要在os模块中使用功能,请导入os

  • 如果要在os.path模块中使用功能,请导入os.path

  • 如果要在两个模块中使用功能,则导入两个模块:

    import os
    import os.path

以供参考:

Common sense works here: os is a module, and os.path is a module, too. So just import the module you want to use:

  • If you want to use functionalities in the os module, then import os.

  • If you want to use functionalities in the os.path module, then import os.path.

  • If you want to use functionalities in both modules, then import both modules:

    import os
    import os.path
    

For reference:


回答 5

找不到任何明确的引用,但我看到os.walk的示例代码使用os.path,但仅导入os

Couldn’t find any definitive reference, but I see that the example code for os.walk uses os.path but only imports os


如何导入上面目录中的Python类?

问题:如何导入上面目录中的Python类?

我想从当前目录上方目录中的文件中的类继承。

是否可以相对导入该文件?

I want to inherit from a class in a file that lies in a directory above the current one.

Is it possible to relatively import that file?


回答 0

from ..subpkg2 import mod

根据Python文档:在包层次结构中,请使用两个点,如import语句 doc所述:

指定要导入的模块时,不必指定模块的绝对名称。当一个模块或程序包包含在另一个程序包中时,可以在同一顶部程序包中进行相对导入,而不必提及程序包名称。之后,通过在指定的模块或程序包中使用前导点,from可以指定在不指定确切名称的情况下遍历当前程序包层次结构的高度。一个前导点表示进行导入的模块所在的当前包。两点表示一个包装级别。三个点在两个级别上,依此类推。因此,如果from . import modpkg包中的模块执行,则最终将导入pkg.mod。如果from ..subpkg2 import mod从内部执行,pkg.subpkg1则将导入pkg.subpkg2.mod。相对进口的规范包含在PEP 328中

PEP 328处理绝对/相对进口。

from ..subpkg2 import mod

Per the Python docs: When inside a package hierarchy, use two dots, as the import statement doc says:

When specifying what module to import you do not have to specify the absolute name of the module. When a module or package is contained within another package it is possible to make a relative import within the same top package without having to mention the package name. By using leading dots in the specified module or package after from you can specify how high to traverse up the current package hierarchy without specifying exact names. One leading dot means the current package where the module making the import exists. Two dots means up one package level. Three dots is up two levels, etc. So if you execute from . import mod from a module in the pkg package then you will end up importing pkg.mod. If you execute from ..subpkg2 import mod from within pkg.subpkg1 you will import pkg.subpkg2.mod. The specification for relative imports is contained within PEP 328.

PEP 328 deals with absolute/relative imports.


回答 1

import sys
sys.path.append("..") # Adds higher directory to python modules path.
import sys
sys.path.append("..") # Adds higher directory to python modules path.

回答 2

如果您可以保证他提到的软件包层次结构, @gimel的答案是正确的。如果您不能-如果您的真正需要如您所表达的那样,完全与目录绑定,并且与打包没有任何必要的关系-那么您需要__file__继续寻找父目录(几个os.path.dirname调用即可; – ),然后(如果该目录尚未上sys.path)预先准备暂时插入说,在非常的启动目录sys.path__import__,除去上述再DIR -事实上杂乱的工作,但是,“当你必须,你必须”(和Pyhon努力永不停止程序员做必须做的事情做的事情-就像ISO C标准在其序言中“ C的精神”部分中所说!!)。

这是一个可能适合您的示例:

import sys
import os.path
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

import module_in_parent_dir

@gimel’s answer is correct if you can guarantee the package hierarchy he mentions. If you can’t — if your real need is as you expressed it, exclusively tied to directories and without any necessary relationship to packaging — then you need to work on __file__ to find out the parent directory (a couple of os.path.dirname calls will do;-), then (if that directory is not already on sys.path) prepend temporarily insert said dir at the very start of sys.path, __import__, remove said dir again — messy work indeed, but, “when you must, you must” (and Pyhon strives to never stop the programmer from doing what must be done — just like the ISO C standard says in the “Spirit of C” section in its preface!-).

Here is an example that may work for you:

import sys
import os.path
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

import module_in_parent_dir

回答 3

从当前目录正上方一层的目录中导入模块:

from .. import module

Import module from a directory which is exactly one level above the current directory:

from .. import module

回答 4

如何加载目录中的模块

前言:我对以前的答案进行了实质性的重写,希望能够帮助人们轻松地进入python的生态系统,并希望通过python的导入系统为每个人带来最大的成功改变。

这将涵盖软件包中的相对进口,我认为这是OP问题最可能的情况。

Python是一个模块化系统

这就是为什么我们编写import foo从根命名空间加载模块“ foo”而不是编写的原因:

foo = dict();  # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh:  # please avoid doing this
    exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo)  # please avoid doing this

Python未与文件系统耦合

这就是为什么我们可以在没有实际文件系统的环境中嵌入python而无需提供虚拟文件系统(例如Jython)的原因。

与文件系统脱钩,可以灵活地进行导入,该设计允许从存档/ zip文件导入,导入单例,字节码缓存,cffi扩展,甚至远程代码定义加载。

因此,如果导入未与文件系统耦合,“向上目录”是什么意思?我们挑选出一些启发,但一中工作时,我们能做到这一点,例如包装,一些启发式已经被定义,使得像相对进口.foo..foo在同一封装内的工作。凉!

如果您真诚地希望将源代码加载模式耦合到文件系统,则可以这样做。您必须选择自己的试探法,并使用某种导入机制,我建议使用importlib

Python的importlib示例如下所示:

import importlib.util
import sys

# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'

foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)

foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton

打包

这里有一个很好的官方示例项目:https//github.com/pypa/sampleproject

python软件包是有关您的源代码的信息的集合,该软件包可以告知其他工具如何将您的源代码复制到其他计算机,以及如何将源代码集成到该系统的路径中,从而import foo适用于其他计算机(无论解释器,主机操作系统等)

目录结构

让我们foo在某个目录(最好是空目录)中有一个包名。

some_directory/
    foo.py  # `if __name__ == "__main__":`  lives here

我的首选是创建setup.py与的兄弟姐妹foo.py,因为它使setup.py文件的编写更加简单,但是您可以编写配置来更改/重定向setuptools默认情况下愿意做的一切;例如放在foo.py“ src /”目录下比较流行,这里不做介绍。

some_directory/
    foo.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    py_modules=['foo'],
)

python3 -m pip install --editable ./  # or path/to/some_directory/

“可编辑” -e又将再次重定向导入机制,以将源文件加载到此目录中,而不是将当前的确切文件复制到安装环境的库中。这也可能导致开发人员机器上的行为差异,请务必测试您的代码!除了pip之外,还有其他工具,但是我建议您将pip用作入门工具:)

我还想制作foo一个“包”(包含的目录__init__.py)而不是一个模块(一个“ .py”文件),“包”和“模块”都可以加载到根命名空间中,模块允许嵌套命名空间,如果我们要进行“相对一个目录向上”导入,这将很有帮助。

some_directory/
    foo/
        __init__.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
)

我也喜欢做一个foo/__main__.py,这允许python将包作为模块python3 -m foo执行,例如将foo/__main__.py作为__main__

some_directory/
    foo/
        __init__.py
        __main__.py  # `if __name__ == "__main__":`  lives here, `def main():` too!
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
    ...
    entry_points={
        'console_scripts': [
            # "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
            'foo=foo.__main__:main',
        ]
    },
)

让我们用更多的模块充实一下:基本上,您可以拥有一个目录结构,如下所示:

some_directory/
    bar.py           # `import bar`
    foo/
        __init__.py  # `import foo`
        __main__.py
        baz.py       # `import foo.baz
        spam/           
            __init__.py  # `import foo.spam`
            eggs.py      # `import foo.spam.eggs`
    setup.py

setup.py 按照惯例,其中包含有关源代码的元数据信息,例如:

  • 安装名为“ install_requires”所需的依赖项
  • 软件包管理应使用什么名称(安装/卸载“名称”),在我们的案例中,建议与主python软件包名称匹配 foo,,尽管用下划线代替连字符很普遍
  • 许可信息
  • 成熟度标签(alpha / beta / etc),
  • 受众标签(用于开发人员,用于机器学习等),
  • 单页文档内容(如自述文件),
  • 外壳程序名称(您在用户外壳程序上键入的名称(如bash)或在图形用户外壳程序中找到的名称(如开始菜单)),
  • 该软件包将安装(和卸载)的python模块列表
  • 实际的“运行测试”入口点 python ./setup.py test

它非常广泛,如果在开发机器上安装了源模块,它甚至可以即时编译c扩展。对于每天的示例,我建议使用PYPA样本存储库的setup.py

如果要发布构建工件(例如,旨在运行几乎相同的计算机的代码副本),则requests.txt文件是用于快照确切的依赖项信息的一种流行方法,其中“ install_requires”是捕获最小数量和最小数量的好方法。最高兼容版本。但是,无论如何目标计算机几乎都是相同的,我强烈建议创建一个完整的python前缀的tarball。这可能很棘手,太详细了,无法在此处介绍。签出pip install--target签选项,或virtualenv aka venv寻找线索。

回到例子

如何在一个目录下导入文件:

在foo / spam / eggs.py中,如果需要foo / baz中的代码,我们可以通过其绝对命名空间来请求它:

import foo.baz

如果我们想保留将来通过其他一些相对baz实现将eggs.py移到其他目录的功能,可以使用相对导入,例如:

import ..baz

How to load a module that is a directory up

preface: I did a substantial rewrite of a previous answer with the hopes of helping ease people into python’s ecosystem, and hopefully give everyone the best change of success with python’s import system.

This will cover relative imports within a package, which I think is the most probable case to OP’s question.

Python is a modular system

This is why we write import foo to load a module “foo” from the root namespace, instead of writing:

foo = dict();  # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh:  # please avoid doing this
    exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo)  # please avoid doing this

Python isn’t coupled to a file-system

This is why we can embed python in environment where there isn’t a defacto filesystem without providing a virtual one, such as Jython.

Being decoupled from a filesystem lets imports be flexible, this design allows for things like imports from archive/zip files, import singletons, bytecode caching, cffi extensions, even remote code definition loading.

So if imports are not coupled to a filesystem what does “one directory up” mean? We have to pick out some heuristics but we can do that, for example when working within a package, some heuristics have already been defined that makes relative imports like .foo and ..foo work within the same package. Cool!

If you sincerely want to couple your source code loading patterns to a filesystem, you can do that. You’ll have to choose your own heuristics, and use some kind of importing machinery, I recommend importlib

Python’s importlib example looks something like so:

import importlib.util
import sys

# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'

foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)

foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton

Packaging

There is a great example project available officially here: https://github.com/pypa/sampleproject

A python package is a collection of information about your source code, that can inform other tools how to copy your source code to other computers, and how to integrate your source code into that system’s path so that import foo works for other computers (regardless of interpreter, host operating system, etc)

Directory Structure

Lets have a package name foo, in some directory (preferably an empty directory).

some_directory/
    foo.py  # `if __name__ == "__main__":`  lives here

My preference is to create setup.py as sibling to foo.py, because it makes writing the setup.py file simpler, however you can write configuration to change/redirect everything setuptools does by default if you like; for example putting foo.py under a “src/” directory is somewhat popular, not covered here.

some_directory/
    foo.py
    setup.py

.

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    py_modules=['foo'],
)

.

python3 -m pip install --editable ./  # or path/to/some_directory/

“editable” aka -e will yet-again redirect the importing machinery to load the source files in this directory, instead copying the current exact files to the installing-environment’s library. This can also cause behavioral differences on a developer’s machine, be sure to test your code! There are tools other than pip, however I’d recommend pip be the introductory one :)

I also like to make foo a “package” (a directory containing __init__.py) instead of a module (a single “.py” file), both “packages” and “modules” can be loaded into the root namespace, modules allow for nested namespaces, which is helpful if we want to have a “relative one directory up” import.

some_directory/
    foo/
        __init__.py
    setup.py

.

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
)

I also like to make a foo/__main__.py, this allows python to execute the package as a module, eg python3 -m foo will execute foo/__main__.py as __main__.

some_directory/
    foo/
        __init__.py
        __main__.py  # `if __name__ == "__main__":`  lives here, `def main():` too!
    setup.py

.

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
    ...
    entry_points={
        'console_scripts': [
            # "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
            'foo=foo.__main__:main',
        ]
    },
)

Lets flesh this out with some more modules: Basically, you can have a directory structure like so:

some_directory/
    bar.py           # `import bar`
    foo/
        __init__.py  # `import foo`
        __main__.py
        baz.py       # `import foo.baz
        spam/           
            __init__.py  # `import foo.spam`
            eggs.py      # `import foo.spam.eggs`
    setup.py

setup.py conventionally holds metadata information about the source code within, such as:

  • what dependencies are needed to install named “install_requires”
  • what name should be used for package management (install/uninstall “name”), I suggest this match your primary python package name in our case foo, though substituting underscores for hyphens is popular
  • licensing information
  • maturity tags (alpha/beta/etc),
  • audience tags (for developers, for machine learning, etc),
  • single-page documentation content (like a README),
  • shell names (names you type at user shell like bash, or names you find in a graphical user shell like a start menu),
  • a list of python modules this package will install (and uninstall)
  • a defacto “run tests” entry point python ./setup.py test

Its very expansive, it can even compile c extensions on the fly if a source module is being installed on a development machine. For a every-day example I recommend the PYPA Sample Repository’s setup.py

If you are releasing a build artifact, eg a copy of the code that is meant to run nearly identical computers, a requirements.txt file is a popular way to snapshot exact dependency information, where “install_requires” is a good way to capture minimum and maximum compatible versions. However, given that the target machines are nearly identical anyway, I highly recommend creating a tarball of an entire python prefix. This can be tricky, too detailed to get into here. Check out pip install‘s --target option, or virtualenv aka venv for leads.

back to the example

how to import a file one directory up:

From foo/spam/eggs.py, if we wanted code from foo/baz we could ask for it by its absolute namespace:

import foo.baz

If we wanted to reserve capability to move eggs.py into some other directory in the future with some other relative baz implementation, we could use a relative import like:

import ..baz

回答 5

Python是一个模块化系统

Python不依赖文件系统

为了可靠地加载python代码,请将该代码放在模块中,然后将该模块安装在python的库中。

已安装的模块始终可以通过以下方式从顶级命名空间加载: import <name>


这里有一个很好的示例项目正式可用:https : //github.com/pypa/sampleproject

基本上,您可以具有如下目录结构:

the_foo_project/
    setup.py  

    bar.py           # `import bar`
    foo/
      __init__.py    # `import foo`

      baz.py         # `import foo.baz`

      faz/           # `import foo.faz`
        __init__.py
        daz.py       # `import foo.faz.daz` ... etc.

一定要声明你setuptools.setup()setup.py

官方示例:https//github.com/pypa/sampleproject/blob/master/setup.py

在我们的例子中,我们可能想导出bar.pyfoo/__init__.py我的简短示例:

setup.py

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    ...
    py_modules=['bar'],
    packages=['foo'],
    ...
    entry_points={}, 
        # Note, any changes to your setup.py, like adding to `packages`, or
        # changing `entry_points` will require the module to be reinstalled;
        # `python3 -m pip install --upgrade --editable ./the_foo_project
)

现在我们可以将模块安装到python库中;使用pip,您可以the_foo_project在编辑模式下安装到python库中,因此我们可以实时对其进行处理

python3 -m pip install --editable=./the_foo_project

# if you get a permission error, you can always use 
# `pip ... --user` to install in your user python library

现在,从任何python上下文中,我们都可以加载共享的py_modules和包

foo_script.py

#!/usr/bin/env python3

import bar
import foo

print(dir(bar))
print(dir(foo))

Python is a modular system

Python doesn’t rely on a file system

To load python code reliably, have that code in a module, and that module installed in python’s library.

Installed modules can always be loaded from the top level namespace with import <name>


There is a great sample project available officially here: https://github.com/pypa/sampleproject

Basically, you can have a directory structure like so:

the_foo_project/
    setup.py  

    bar.py           # `import bar`
    foo/
      __init__.py    # `import foo`

      baz.py         # `import foo.baz`

      faz/           # `import foo.faz`
        __init__.py
        daz.py       # `import foo.faz.daz` ... etc.

.

Be sure to declare your setuptools.setup() in setup.py,

official example: https://github.com/pypa/sampleproject/blob/master/setup.py

In our case we probably want to export bar.py and foo/__init__.py, my brief example:

setup.py

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    ...
    py_modules=['bar'],
    packages=['foo'],
    ...
    entry_points={}, 
        # Note, any changes to your setup.py, like adding to `packages`, or
        # changing `entry_points` will require the module to be reinstalled;
        # `python3 -m pip install --upgrade --editable ./the_foo_project
)

.

Now we can install our module into the python library; with pip, you can install the_foo_project into your python library in edit mode, so we can work on it in real time

python3 -m pip install --editable=./the_foo_project

# if you get a permission error, you can always use 
# `pip ... --user` to install in your user python library

.

Now from any python context, we can load our shared py_modules and packages

foo_script.py

#!/usr/bin/env python3

import bar
import foo

print(dir(bar))
print(dir(foo))