我在模块中有很多类。让我们说:
'''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
...
现在,在另一个模块中,我想动态加载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]
我希望ai_players
期望成为对象实例的列表(假设__str__
返回名称):['Homer', 'Barney...]
但是,我收到以下错误
TypeError: __init__() takes exactly 2 arguments (1 given)
有趣的是,当我没有在列表理解或for循环中实例化类对象时,一切正常。
# this does not throw an error
ai_player1 = ai_players[0]()
print ai_player1
# >> 'Homer'
那么为什么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)
并将main.py
中的第5行更改为
ai_players = inspect.getmembers(players,
lambda x: inspect.isclass(x) and issubclass(x, players.Player))
我遇到了所描述的问题。这也不起作用(当我在repl上测试它时它起作用了)
ai_player1 = ai_players[0]()
它似乎与继承和默认参数有关。如果我将基类Player
更改为
class Player():
"""This class is intended to be subclassed"""
def __init__(self, name='Maggie'):
self.name = name
然后我没有得到错误,但球员的名字总是'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',)
您是否知道来自检查模块的任何替代方案?
EDIT3:
请注意,如果给SAME类两次,则issubclass()返回True。 (Tryptich)
那是恶人
答案 0 :(得分:2)
我运行了你的测试代码,它对我来说很好。
该错误表明您实际上并未在所有类上设置默认的“name”参数。
我要仔细检查。
请注意,如果给SAME课程两次,issubclass()
会返回True
。
>>> class Foo: pass
>>> issubclass(Foo, Foo)
True
因此,您的代码尝试在没有名称参数的情况下实例化Player
并死亡。
好像你过分复杂了一些事情。我建议您更详细地解释一下您的程序,也许是另一个问题,以获得关于这种方法是否有必要(可能不是)的反馈。
答案 1 :(得分:1)
ai_players = inspect.getmembers(players, inspect.isclass())
此行尝试调用不带参数的inspect.isclass,并将getmembers的调用结果作为第二个参数。你想传递函数inspect.isclass
,所以就这样做(编辑:更清楚,你想要inspect.getmembers(players, inspect.isclass)
)。你觉得这些括号怎么办?
答案 2 :(得分:0)
以下是做你想做的更好的方法。
player.py:
class Player:
def __init__(self, name):
self.name = name
main.py:
import player
names = ['Homer', 'Barney', 'Moe']
players = [player.Player(name) for name in names]
请注意,您要定义一个类来保存播放器的详细信息,然后您可以根据需要创建此类的多个实例。