在Python包中,我有文件结构
package/
__init__.py
import_me.py
文件import_me.py
被认为提供了功能片段:
import re
import sys
def hello():
pass
以便package.import_me.hello
可以通过imp
动态导入re
。不幸的是,这也允许分别将sys
和package.import_me.re
导入package.import.sys
和import_me.py
。
有没有办法阻止$uibModalInstance.close(JSON.stringify(ar))
中导入的模块再次重新导出?最好这应该超出名称修改或下划线前缀导入的模块,因为在我的情况下,它可能会在某些情况下造成安全问题。
答案 0 :(得分:13)
没有简单的方法可以禁止从模块导入全局名称; Python根本就不是这样构建的。
如果您编写了自己的__import__
函数并隐藏了内置函数,那么您可能会达到令人生畏的目标,但我怀疑时间和测试的成本是值得的还是完全有效的。
您可以做的是使用前导下划线导入依赖模块,这是用于沟通&#34; 实现细节的标准Python习惯用法,使用风险自负&#34;:< / p>
import re as _re
import sys as _sys
def hello():
pass
注意强>
虽然只是删除导入的模块作为不允许导入它们的方式似乎可能有用,但它实际上不会:
import re
import sys
def hello():
sys
print('hello')
del re
del sys
然后导入并使用hello
:
>>> import del_mod
>>> del_mod.hello()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "del_mod.py", line 5, in hello
sys
NameError: global name 'sys' is not defined
答案 1 :(得分:4)
没有简单的方法可以禁止从模块导入全局名称;但事实上,你并不需要。 Python允许使用本地导入而不是全局导入:
def foo():
import sys
print(sys.copyright)
sys.copyright # Throws NameError
整洁而简单。
实际上,我认为使用本地进口应该是一种很好的做法,而全球性进口只是对C或其遗产的致敬。
UPD :明显的缺点是每次调用此函数时都会执行import sys
语句,这可能是无法承受的。
但您可以改为创建一个可调用对象:
class Callable(object):
import sys as _sys
def __call__(self):
print(self._sys.copyright)
foo = Callable()
foo()
虽然我个人不喜欢这种方法,但它可以更好地使用泛型类。
答案 2 :(得分:3)
有几种选择:
将None
放入sys.modules
模块中:
>>> import sys
>>> import re
>>> del re
>>> sys.modules['re'] = None
>>> import re
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named re
答案 3 :(得分:2)
另一种方法可能是将定义包装到初始化函数中。
## --- exporttest.py ---
def _init():
import os # effectively hidden
global get_ext # effectively exports it
def get_ext(filename):
return _pointless_subfunc(filename)
# underscore optional, but good
def _pointless_subfunc(filename): # for the sake of documentation
return os.path.splitext(filename)[1]
if __name__ == '__main__': # for interactive debugging (or doctest)
globals().update(locals()) # we want all definitions accessible
import doctest
doctest.testmod()
_init()
print('is ``get_ext`` accessible? ', 'get_ext' in globals())
print('is ``_pointless_subfunc`` accessible?', '_pointless_subfunc' in globals())
print('is ``os`` accessible? ', 'os' in globals())
进行比较:
>>> python3 -m exporttest
is ``get_ext`` accessible? True
is ``_pointless_subfunc`` accessible? True
is ``os`` accessible? True
>>> python3 -c "import exporttest"
is ``get_ext`` accessible? True
is ``_pointless_subfunc`` accessible? False
is ``os`` accessible? False
dir(exporttest)
没有杂乱。可悲的是,与import MODULE as _MODULE
模式不同,它不起作用
与pylint很好。
C: 4, 4: Invalid constant name "get_ext" (invalid-name)
W: 4, 4: Using global for 'get_ext' but no assignment is done (global-variable-not-assigned)
W: 5, 4: Unused variable 'get_ext' (unused-variable)
__all__
进一步阅读后,我发现 pythonic方法是依靠__all__
。它不仅控制from MODULE import *
上导出的内容,还控制help(MODULE)
中显示的内容,根据“我们都是这里的成年人”的口号,如果用户不使用任何内容,则是用户自己的错记录为公开。
工具对此方法提供了最佳支持(例如,通过 importmagic 库通过编辑器支持自动导入)。
就我个人而言,我发现整个“我们都是成年人”的口头禅很天真,但它是的pythonic方式。
答案 4 :(得分:2)
解决方案可能是重新考虑您的文件结构并创建一个子模块。
使用__init__.py
之类的文件来显示所需的变量。
package/
__init__.py
import_me/
__init__.py
code.py
'''
import_me/code.py
'''
# imports that you do not want to expose
import re
import sys
def hello():
re.doSomething()
sys.doSomething()
print('hello')
'''
import_me/__init__.py
'''
from code import hello
答案 5 :(得分:0)
我知道这是一个已有4年历史的问题,但是我发现自己最近不得不处理同样的问题,并提出了一个似乎可行的解决方案。
这是我们将要使用的文件结构:
package/
__init__.py
import_me.py
import_me_no_re_export.py
package/import_me.py
的内容(仅用于比较)根据问题:
import re
import sys
def hello():
pass
package/import_me_no_re_export.py
的那些是:
def _():
global hello
import re
import sys
def hello():
pass
_()
del _
以下python
CLI会话(Python 3.8.5)显示了此方法的结果:
>>> import package.import_me
>>> import package.import_me_no_re_export
>>> dir(package.import_me)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'hello', 're', 'sys']
>>> dir(package.import_me_no_re_export)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'hello']
>>> set(dir(package.import_me)) - set(dir(package.import_me_no_re_export))
{'sys', 're'}
如您所见,import_me_no_re_export
模块不会重新导出sys
和re
模块。
优点:
mypy
和flake8
似乎都喜欢这种方法。缺点:
_
函数用于如此更改的模块)。正如其他答案所指出的那样,拥抱__all__
可能是最好的选择,尽管实际上并不能解决问题。除此之外,可能处理这些事情一定会发生的事实。
答案 6 :(得分:-2)
编辑:在大多数情况下,这不起作用。请参阅其他答案。
我知道这个问题很老,但如果你只是把
select * from (select rownum as rn, t.* from test_table t) where rn > 3
那么您不能从import re
import sys
def hello():
pass
del re
del sys
导入re
或sys
,这样您就不必从一开始就移动您的导入文件。