Python 在导入_uinit__uuu.py中的所有内容时排除模块

Python 在导入_uinit__uuu.py中的所有内容时排除模块,python,python-import,Python,Python Import,问题 考虑以下布局: package/ main.py math_helpers/ mymath.py __init__.py mymath.py包含: import math def foo(): pass from .mymath import * 在main.py中,我希望能够使用mymath.py中的代码,如下所示: import math_helpers math_helpers.foo() 为此,包含以下内容: imp

问题

考虑以下布局:

package/
    main.py
    math_helpers/
        mymath.py
        __init__.py
mymath.py
包含:

import math

def foo():
    pass
from .mymath import *
main.py
中,我希望能够使用
mymath.py
中的代码,如下所示:

import math_helpers
math_helpers.foo()
为此,
包含以下内容:

import math

def foo():
    pass
from .mymath import *
但是,在
mymath.py
中导入的模块现在位于
math\u helpers
命名空间中,例如
math\u helpers.math
可以访问


当前方法

我在
mymath.py
的末尾添加了以下内容

import types
__all__ = [name for name, thing in globals().items()
          if not (name.startswith('_') or isinstance(thing, types.ModuleType))]

这似乎是可行的,但这是正确的方法吗?

一方面,有很多很好的理由不进行star导入,但另一方面,python适用于同意的成年人

\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。您的方法是正确的,完成后可以进一步清理命名空间:

import types
__all__ = [name for name, thing in globals().items()
          if not (name.startswith('_') or isinstance(thing, types.ModuleType))]
del types
虽然不太推荐,但您也可以直接从模块中清理元素,这样它们就不会出现。如果您需要在模块中定义的函数中使用它们,这将是一个问题,因为每个函数对象都有一个绑定到其父模块的
\uuuu dict\uuu
引用。但是,如果只导入
math\u helpers
以调用
math\u helpers.foo()
,并且不需要在模块中的其他位置对其进行持久引用,则只需在末尾取消链接即可:

del math_helpers
长版本

模块导入在模块的
\uuu dict\uuu
名称空间中运行模块的代码。在顶级绑定的任何名称,无论是通过类定义、函数定义、直接赋值还是其他方式,都存在于该词典中。有时,需要清理中间变量,正如我建议的那样,使用
类型

假设您的模块如下所示:

测试模块.py

import math
import numpy as np

def x(n):
    return math.sqrt(n)

class A(np.ndarray):
    pass

import types
__all__ = [name for name, thing in globals().items()
           if not (name.startswith('_') or isinstance(thing, types.ModuleType))]
value = 1

def x():
    return value
from a import x

value = 2
在这种情况下,
\uuuuuu all\uuuuuu
将是
['x','A']
。但是,模块本身将包含以下名称:
“数学”、“np”、“x”、“A”、“类型”、“全部”

如果最后运行
deltypes
,它将从名称空间中删除该名称。显然,这是安全的,因为一旦构建了
\uuuuu all\uuuuu
,就不会在任何地方引用
类型

类似地,如果您想通过添加
delnp
来删除
np
,也可以。类
A
完全由模块代码末尾构造,因此它不需要全局名称
np
来引用其父类

数学方面则不然。如果要在模块代码末尾执行
del math
,则函数
x
将不起作用。如果导入模块,您可以看到
x.\uuuu globals\uuuuuu
是模块的
\uuuu dict\uuuuu

import test_module

test_module.__dict__ is test_module.x.__globals__
如果从模块字典中删除
math
,并调用
test\u module.x
,您将获得

NameError: name 'math' is not defined
因此,在某些非常特殊的情况下,您可能能够清理
mymath.py
的名称空间,但这不是推荐的方法,因为它仅适用于某些情况

总之,坚持使用
\uuuuu all\uuuuu

一个相关的故事

有一次,我有两个模块实现了类似的功能,但针对不同类型的最终用户。有几个函数我想从模块
a
复制到模块
b
。问题是,我希望函数能够像在模块
b
中定义的那样工作。不幸的是,它们依赖于
a
中定义的常量<代码>b
定义了它自己的常量版本。例如:

a.py

import math
import numpy as np

def x(n):
    return math.sqrt(n)

class A(np.ndarray):
    pass

import types
__all__ = [name for name, thing in globals().items()
           if not (name.startswith('_') or isinstance(thing, types.ModuleType))]
value = 1

def x():
    return value
from a import x

value = 2
b.py

import math
import numpy as np

def x(n):
    return math.sqrt(n)

class A(np.ndarray):
    pass

import types
__all__ = [name for name, thing in globals().items()
           if not (name.startswith('_') or isinstance(thing, types.ModuleType))]
value = 1

def x():
    return value
from a import x

value = 2
我想要
b.x
访问
b.value
而不是
a.value
。我通过将以下内容添加到
b.py
(基于):

我为什么要告诉你这些?好的,您可以创建一个在名称空间中没有任何散乱名称的模块版本。不过,您将无法在函数中看到全局变量的更改。这只是将python推到正常使用之外的一个练习。我强烈不建议这样做,但这里有一个示例模块,它可以有效地冻结其
\uuuu dict\uuuu
函数。它的成员与上面的
test_module
相同,但在全局命名空间中没有模块:

import math
import numpy as np

def x(n):
    return math.sqrt(n)

class A(np.ndarray):
    pass

import functools, types, sys

def wrap(obj):
    """ Written this way to be able to handle classes """
    for name in dir(obj):
        if name.startswith('_'):
            continue
        thing = getattr(obj, name)
        if isinstance(thing, FunctionType) and thing.__module__ == __name__:
            setattr(obj, name,
                    functools.update_wrapper(types.FunctionType(thing.func_code, d, thing.__name__, thing.__defaults__, thing.__closure__), thing)
            getattt(obj, name).__kwdefaults__ = thing.__kwdefaults__
        elif isinstance(thing, type) and thing.__module__ == __name__:
            wrap(thing)

d = globals().copy()
wrap(sys.modules[__name__])
del d, wrap, sys, math, np, functools, types

所以,是的,请永远不要这样做!但是如果你这样做了,就把它放在一个实用类的某个地方。

是的,这正是它的用途。在定义了
\uuuu all\uuu
之后,别忘了做
删除类型。希望它能增加你已经发现的东西。我知道导入
*
是不受欢迎的,因为这样你就看不出名字是从哪里来的,但是把所有东西都放到
数学助手中有什么问题呢?2.del类型是什么?3.我不理解“因为每个函数对象都有一个绑定到其父模块的
\uuuu dict\uu.
\uuuu globals\uuuuuuuuuuuuuuuuuuuu>引用”部分-谢谢!当我到达一个新的位置时,我会更新一个插图desktop@actual_panda. 把所有东西都放在数学助手中没有什么错。你在问题中提出的解决方案肯定是推荐的。对不起,如果我在漫谈中不清楚的话。为了回答你的其他问题,我添加了比你想知道的更多的漫无边际的内容。