在 Python 中,如何获取在特定文件中定义的 类 的列表?
In Python, how do I get the list of classes defined within a particular file?
如果文件 myfile.py
包含:
class A(object):
# Some implementation
class B (object):
# Some implementation
如何定义一个方法,以便在给定 myfile.py
的情况下 returns
[甲乙]?
此处,A 和 B 的返回值可以是 类 的名称或 类 的类型。
(i.e. type(A) = type(str) or type(A) = type(type))
有点啰嗦,但您首先需要将文件作为模块加载,然后检查其方法以查看哪些是 类:
import inspect
import importlib.util
# Load the module from file
spec = importlib.util.spec_from_file_location("foo", "foo.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
# Return a list of all attributes of foo which are classes
[x for x in dir(foo) if inspect.isclass(getattr(foo, x))]
你可以同时获得:
import importlib, inspect
for name, cls in inspect.getmembers(importlib.import_module("myfile"), inspect.isclass):
您可能还想检查:
if cls.__module__ == 'myfile'
以防对别人有帮助。这是我使用的最终解决方案。此方法 returns 所有 类 在特定包中定义。
我将 X 的所有子类 保存在特定文件夹(包)中,然后使用此方法,我可以加载 X 的所有子类,即使它们没有尚未导入。 (如果尚未导入,则无法通过 __all__
访问;否则事情会容易得多)。
import importlib, os, inspect
def get_modules_in_package(package_name: str):
files = os.listdir(package_name)
for file in files:
if file not in ['__init__.py', '__pycache__']:
if file[-3:] != '.py':
continue
file_name = file[:-3]
module_name = package_name + '.' + file_name
for name, cls in inspect.getmembers(importlib.import_module(module_name), inspect.isclass):
if cls.__module__ == module_name:
yield cls
只是建立在上面的答案之上。
如果您需要模块(文件)中定义的 类 的列表,即不仅仅是模块名称空间中存在的列表,并且您想要该模块中的列表 ,即使用反射,那么下面将在 __name__ == __main__
和 __name__ == <module>
两种情况下工作。
import sys, inspect
# You can pass a lambda function as the predicate for getmembers()
[name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(x) and (x.__module__ == __name__))]
在我将 类 注册到调用框架的非常具体的用例中,我使用如下:
def register():
myLogger.info(f'Registering classes defined in module {__name__}')
for name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(x) and (x.__module__ == __name__)):
myLogger.debug(f'Registering class {cls} with name {name}')
<framework>.register_class(cls)
如果文件 myfile.py
包含:
class A(object):
# Some implementation
class B (object):
# Some implementation
如何定义一个方法,以便在给定 myfile.py
的情况下 returns
[甲乙]?
此处,A 和 B 的返回值可以是 类 的名称或 类 的类型。
(i.e. type(A) = type(str) or type(A) = type(type))
有点啰嗦,但您首先需要将文件作为模块加载,然后检查其方法以查看哪些是 类:
import inspect
import importlib.util
# Load the module from file
spec = importlib.util.spec_from_file_location("foo", "foo.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
# Return a list of all attributes of foo which are classes
[x for x in dir(foo) if inspect.isclass(getattr(foo, x))]
你可以同时获得:
import importlib, inspect
for name, cls in inspect.getmembers(importlib.import_module("myfile"), inspect.isclass):
您可能还想检查:
if cls.__module__ == 'myfile'
以防对别人有帮助。这是我使用的最终解决方案。此方法 returns 所有 类 在特定包中定义。
我将 X 的所有子类 保存在特定文件夹(包)中,然后使用此方法,我可以加载 X 的所有子类,即使它们没有尚未导入。 (如果尚未导入,则无法通过 __all__
访问;否则事情会容易得多)。
import importlib, os, inspect
def get_modules_in_package(package_name: str):
files = os.listdir(package_name)
for file in files:
if file not in ['__init__.py', '__pycache__']:
if file[-3:] != '.py':
continue
file_name = file[:-3]
module_name = package_name + '.' + file_name
for name, cls in inspect.getmembers(importlib.import_module(module_name), inspect.isclass):
if cls.__module__ == module_name:
yield cls
只是建立在上面的答案之上。
如果您需要模块(文件)中定义的 类 的列表,即不仅仅是模块名称空间中存在的列表,并且您想要该模块中的列表 ,即使用反射,那么下面将在 __name__ == __main__
和 __name__ == <module>
两种情况下工作。
import sys, inspect
# You can pass a lambda function as the predicate for getmembers()
[name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(x) and (x.__module__ == __name__))]
在我将 类 注册到调用框架的非常具体的用例中,我使用如下:
def register():
myLogger.info(f'Registering classes defined in module {__name__}')
for name, cls in inspect.getmembers(sys.modules[__name__], lambda x: inspect.isclass(x) and (x.__module__ == __name__)):
myLogger.debug(f'Registering class {cls} with name {name}')
<framework>.register_class(cls)