Python中的动态类实例化

Eug*_*gen 5 python introspection

我在一个模块中有一堆类.让我们说:

'''players.py'''

class Player1:
    def __init__(self, name='Homer'):
        self.name = name

class Player2:
    def __init__(self, name='Barney'):
        self.name = name

class Player3:
    def __init__(self, name='Moe'):
        self.name = name
...
Run Code Online (Sandbox Code Playgroud)


现在,在另一个模块中,我想动态加载所有类players.py并实例化它们.我使用python inspect模块.

'''main.py'''
import inspect
import players

ai_players = inspect.getmembers(players, inspect.isclass)
# ai_players is now a list like: [('Player1',<class instance>),(...]
ai_players = [x[1] for x in ai_players]
# ai_players is now a list like: [<class instance>, <class...]

# now let's try to create a list of initialized objects
ai_players = [x() for x in ai_players]
Run Code Online (Sandbox Code Playgroud)

ai_players希望是一个像这样的对象实例的列表(让我们假设__str__返回名称):['Homer', 'Barney...]

但是,我收到以下错误

TypeError: __init__() takes exactly 2 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)


有趣的是,当我没有在列表理解或for循环中实例化类对象时,一切正常.

# this does not throw an error
ai_player1 = ai_players[0]()
print ai_player1
# >> 'Homer'
Run Code Online (Sandbox Code Playgroud)


那么为什么Python不允许我在列表comprehensions/for循环中实例化类(我也在for循环中试过它)?

或者更好:您如何动态加载模块中的所有类并在列表中实例化它们?

*注意,我使用的是Python 2.6

编辑

事实证明我过度简化了我的问题,上面的代码就好了.但是,如果我players.py改为

'''players.py'''

class Player():
    """This class is intended to be subclassed"""
    def __init__(self, name):
        self.name = name

class Player1(Player):
    def __init__(self, name='Homer'):
        Player.__init__(self, name)

class Player2(Player):
    def __init__(self, name='Barney'):
        Player.__init__(self, name)

class Player3(Player):
    def __init__(self, name='Moe'):
        Player.__init__(self, name)
Run Code Online (Sandbox Code Playgroud)

并将第5行更改main.py

ai_players = inspect.getmembers(players, 
             lambda x: inspect.isclass(x) and issubclass(x, players.Player))
Run Code Online (Sandbox Code Playgroud)

我遇到了所描述的问题.这也不起作用(当我在repl上测试时它工作)

ai_player1 = ai_players[0]()
Run Code Online (Sandbox Code Playgroud)

它似乎与继承和默认参数有关.如果我将基类更改Player

class Player():
    """This class is intended to be subclassed"""
    def __init__(self, name='Maggie'):
        self.name = name
Run Code Online (Sandbox Code Playgroud)

然后我没有得到错误,但球员的名字总是'Maggie'.

EDIT2:

我玩了一下,事实证明getmembers函数以某种方式"吃掉"默认参数.从repl看一下这个日志:

>>> import players
>>> import inspect
>>> ai_players = inspect.getmembers(players, 
...              lambda x: inspect.isclass(x) and issubclass(x, players.Player))
>>> ai_players = [x[1] for x in ai_players]
>>> ai_players[0].__init__.func_defaults
>>> print ai_players[0].__init__.func_defaults
None
>>> players.Player1.__init__.func_defaults
('Homer',)
Run Code Online (Sandbox Code Playgroud)

您是否知道来自检查模块的任何替代方案?

EDIT3:

请注意,如果给SAME类两次,则issubclass()返回True.(Tryptich)

这是恶人

Tri*_*ych 2

我运行了你的测试代码,它对我来说效果很好。

该错误表明您实际上并未在所有类上设置默认的“name”参数。

我会仔细检查。

编辑:

请注意,如果两次给出相同的类,则issubclass()返回。True

>>> class Foo: pass
>>> issubclass(Foo, Foo)
True
Run Code Online (Sandbox Code Playgroud)

因此,您的代码尝试Player在没有名称参数的情况下实例化并终止。

看来你把事情变得有点过于复杂了。我建议更详细地解释您的程序,也许在另一个问题中,以获得有关这种方法是否必要(可能不需要)的一些反馈。