如何检测 class / 变量是否在 Python 3 中导入?
How do I detect if a class / variable was imported in Python 3?
这是script_one.py
的内容:
x = "Hello World"
这是script_two.py
的内容:
from script_one import x
print(x)
现在,如果我 运行 script_two.py
输出将是:
>>> Hello World
我需要的是检测 x
是否被导入的方法。
这就是我想象的 script_one.py
的源代码的样子:
x = "Hello World"
if x.has_been_imported:
print("You've just imported \"x\"!")
然后如果我 运行 script_two.py
输出 "should" 是:
>>> Hello World
>>> You've just imported "x"!
这叫什么,Python3中有这个功能吗?如何使用?
你不能。恐怕花在检测上的努力是浪费时间。
Python 导入包括以下步骤:
- 通过查看
sys.modules
检查模块是否已加载。
- 如果模块还没有加载,加载它。这将创建一个新的模块对象,添加到
sys.modules
,包含执行顶级代码产生的所有对象。
- 在导入命名空间中绑定名称。名称的绑定方式取决于所选择的确切
import
变体。
import module
将名称 module
绑定到 sys.modules[module]
对象
import module as othername
将名称 othername
绑定到 sys.modules[module]
对象
from module import attribute
将名称 attribute
绑定到 sys.modules[module].attribute
对象
from module import attribute as othername
将名称 othername
绑定到 sys.modules[module].attribute
对象
在这种情况下,重要的是要认识到 Python 名称只是引用;所有 Python 对象(包括模块)都存在于堆中,并随着对它们的引用数量的增加而下降。如果您需要了解其工作原理,请参阅此 great article by Ned Batchelder on Python names。
你的问题可以有两种解释:
- 您想知道模块已经导入。执行模块中的代码时(如
x = "Hello World"
),它已被导入。所有的。 Python这里不加载只是x
,全有或全无。
- 您想知道其他代码是否正在使用特定名称。您必须跟踪该对象存在哪些其他引用。这是一项艰巨的任务,涉及递归检查
gc.get_referrers()
object chain 以查看其他 Python 对象现在可能引用 x
.
在以下任何情况下,后一个目标变得更加困难:
import script_one
,然后使用script_one.x
;此类引用可能存在时间太短,您无法检测到。
from script_one import x
,然后 del x
。除非其他东西仍然在导入的命名空间中引用相同的字符串对象,否则该引用现在已经消失并且无法再被检测到。
import sys; sys.modules['script_one'].x
是引用相同字符串对象的合法方式,但这算作导入吗?
import script_one
,然后 list(vars(script_one).values())
将创建模块中定义的所有对象的列表,但这些引用是列表中的索引,未命名。这算进口吗?
以前好像是不可能的。但是自从 python 3.7+ 在模块级别引入 __getattr__
以来,现在看起来是可能的。至少我们可以区分一个变量是from module import varable
还是import module; module.variable
导入的。
思路是检测上一帧的AST节点,是否是一个Attribute
:
script_one.py
def _variables():
# we have to define the variables
# so that it dosen't bypass __getattr__
return {'x': 'Hello world!'}
def __getattr__(name):
try:
out = _variables()[name]
except KeyError as kerr:
raise ImportError(kerr)
import ast, sys
from executing import Source
frame = sys._getframe(1)
node = Source.executing(frame).node
if node is None:
print('`x` is imported')
else:
print('`x` is accessed via `script_one.x`')
return out
script_two.py
from script_one import x
print(x)
# `x` is imported
# 'Hello world!'
import script_one
print(script_one.x)
# `x` is accessed via `script_one.x`
# 'Hello world!'
这是script_one.py
的内容:
x = "Hello World"
这是script_two.py
的内容:
from script_one import x
print(x)
现在,如果我 运行 script_two.py
输出将是:
>>> Hello World
我需要的是检测 x
是否被导入的方法。
这就是我想象的 script_one.py
的源代码的样子:
x = "Hello World"
if x.has_been_imported:
print("You've just imported \"x\"!")
然后如果我 运行 script_two.py
输出 "should" 是:
>>> Hello World
>>> You've just imported "x"!
这叫什么,Python3中有这个功能吗?如何使用?
你不能。恐怕花在检测上的努力是浪费时间。
Python 导入包括以下步骤:
- 通过查看
sys.modules
检查模块是否已加载。- 如果模块还没有加载,加载它。这将创建一个新的模块对象,添加到
sys.modules
,包含执行顶级代码产生的所有对象。
- 如果模块还没有加载,加载它。这将创建一个新的模块对象,添加到
- 在导入命名空间中绑定名称。名称的绑定方式取决于所选择的确切
import
变体。import module
将名称module
绑定到sys.modules[module]
对象import module as othername
将名称othername
绑定到sys.modules[module]
对象from module import attribute
将名称attribute
绑定到sys.modules[module].attribute
对象from module import attribute as othername
将名称othername
绑定到sys.modules[module].attribute
对象
在这种情况下,重要的是要认识到 Python 名称只是引用;所有 Python 对象(包括模块)都存在于堆中,并随着对它们的引用数量的增加而下降。如果您需要了解其工作原理,请参阅此 great article by Ned Batchelder on Python names。
你的问题可以有两种解释:
- 您想知道模块已经导入。执行模块中的代码时(如
x = "Hello World"
),它已被导入。所有的。 Python这里不加载只是x
,全有或全无。 - 您想知道其他代码是否正在使用特定名称。您必须跟踪该对象存在哪些其他引用。这是一项艰巨的任务,涉及递归检查
gc.get_referrers()
object chain 以查看其他 Python 对象现在可能引用x
.
在以下任何情况下,后一个目标变得更加困难:
import script_one
,然后使用script_one.x
;此类引用可能存在时间太短,您无法检测到。from script_one import x
,然后del x
。除非其他东西仍然在导入的命名空间中引用相同的字符串对象,否则该引用现在已经消失并且无法再被检测到。import sys; sys.modules['script_one'].x
是引用相同字符串对象的合法方式,但这算作导入吗?import script_one
,然后list(vars(script_one).values())
将创建模块中定义的所有对象的列表,但这些引用是列表中的索引,未命名。这算进口吗?
以前好像是不可能的。但是自从 python 3.7+ 在模块级别引入 __getattr__
以来,现在看起来是可能的。至少我们可以区分一个变量是from module import varable
还是import module; module.variable
导入的。
思路是检测上一帧的AST节点,是否是一个Attribute
:
script_one.py
def _variables():
# we have to define the variables
# so that it dosen't bypass __getattr__
return {'x': 'Hello world!'}
def __getattr__(name):
try:
out = _variables()[name]
except KeyError as kerr:
raise ImportError(kerr)
import ast, sys
from executing import Source
frame = sys._getframe(1)
node = Source.executing(frame).node
if node is None:
print('`x` is imported')
else:
print('`x` is accessed via `script_one.x`')
return out
script_two.py
from script_one import x
print(x)
# `x` is imported
# 'Hello world!'
import script_one
print(script_one.x)
# `x` is accessed via `script_one.x`
# 'Hello world!'