Python:使用compile()时 - 如何创建find classname&创造它?

时间:2014-07-22 12:52:00

标签: python python-3.x

我有一个问题需要实例化一个类,但我不确定最佳方法是什么。

想象一下以下代码:

# loadstuff.py

class LoadSomething:
    def load(self, filename):
        compiled = compile(open(filename).read(), filename, 'exec')

        # The part I am stuck on
        # How do I get the class name, and how do I instantiate it? 
        # This is assuming the file name is the same as the class name, only starting with capital letter, and minus file extension
        module = compiled.  # instantiate class 'Printstuff'

        return module 

loader = LoadSomething()
module = loader.load("printstuff.py")
module.printSomething()  # Should print "Something!"

# printstuff.py

class Printstuff:
    def printSomething(self):
        print("Something!")

我认为代码(以及问题)主要是为自己说话,如何使用compile(..)返回并实例化一个新类,以便我可以调用它的方法?

2 个答案:

答案 0 :(得分:1)

无需手动编译。使用importlib.import_module()动态导入模块。

然后,您可以将inspect.getmembers()inspect.isclass() predicate一起使用来查找所有类,包括可能与模块名称匹配的任何类:

import importlib
import inspect

class LoadSomething:
    def load(self, modulename):
        module = importlib.import_module(modulename)
        modname = modulename.rpartition('.')[-1]  # support packages too
        for clsname, cls in inspect.getmembers(module, inspect.isclass):
            if clsname == modname.title():
                return cls()

这将返回第一个类的实例,该实例与模块具有相同的名称,已标记。

答案 1 :(得分:0)

基本问题是代码对象(您使用compile()生成的东西)可以包含任何 Python代码 - 例如它可以定义多个类。因此,您必须指定您正在加载的文件应该如何指示要使用的类。

例如,一个选项是要求它定义一个具有众所周知名称的类。例如:

codeobj = compile(open(filename).read(), filename, 'exec')
globs = {}
locs = {}
exec(codeobj, globs, locs)
cls = globs['Foobar']
obj = cls()

您可以使用execfile()代替compile()exec()来简化此操作:

globals = {}
locals = {}
execfile(filename, globs, locs)
cls = globs['Foobar']
obj = cls()

很容易想出更复杂的方案。

FWIW,这样做而不是使用impimportlib__import__的原因是基于导入的选项使用模块系统。如果这是用于加载插件,您可能不希望这样,所以execfile()等更合适。