Python 中的动态类实例化

发布于 2024-09-12 11:06:29 字数 3136 浏览 3 评论 0原文

我的模块中有很多类。比方说:

'''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 不允许我在列表推导/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

Then,我不会收到错误,但玩家的名字始终是“Maggie”。

编辑2:

我玩了一下,结果发现 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',)

您知道从检查模块获取成员的任何替代方法吗?

编辑3:

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

那是作恶者

I have a bunch of classes in a module. Let's say:

'''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
...

Now, in another module, I want to dynamically load all classes in players.py and instantiate them. I use the python inspect module for this.

'''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]

I would ai_players expect to be a list of object instances like so (let's suppose __str__ returns the name): ['Homer', 'Barney...]

However, I get the following error

TypeError: __init__() takes exactly 2 arguments (1 given)

The funny thing is that when I don't instantiate the class objects in a list comprehension or a for loop everything works fine.

# this does not throw an error
ai_player1 = ai_players[0]()
print ai_player1
# >> 'Homer'

So why doesn't Python allow me to instantiate the classes in a list comprehensions/for loop (I tried it in a for loop, too)?

Or better: How would you go about dynamically loading all classes in a module and instantiating them in a list?

* Note, I'm using Python 2.6

EDIT

Turns out I oversimplified my problem and the above code is just fine.
However if I change players.py to

'''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)

and change the 5th line in main.py to

ai_players = inspect.getmembers(players, 
             lambda x: inspect.isclass(x) and issubclass(x, players.Player))

I encounter the described problem. Also that doesn't work either (it worked when I tested it on the repl)

ai_player1 = ai_players[0]()

It seems to have something to do with inheritance and default arguments. If I change the base class Player to

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

Then I don't get the error but the players' names are always 'Maggie'.

EDIT2:

I played around a bit and it turns out the getmembers function somehow "eats" the default parameters. Have a look at this log from the 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',)

Do you know of any alternative to getmembers from the inspect module?

EDIT3:

Note that issubclass() returns True if given the SAME class twice. (Tryptich)

That's been the evildoer

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

絕版丫頭 2024-09-19 11:06:29

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

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

我会仔细检查。

编辑:

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

>>> class Foo: pass
>>> issubclass(Foo, Foo)
True

因此,您的代码尝试实例化没有名称参数的 Player 并死亡。

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

I ran your test code and it worked fine for me.

That error is indicating that you are not actually setting the default "name" parameter on ALL of your classes.

I'd double check.

Edit:

Note that issubclass() returns True if given the SAME class twice.

>>> class Foo: pass
>>> issubclass(Foo, Foo)
True

So your code tries to instantiate Player with no name argument and dies.

Seems like you're over-complicating things a bit. I'd suggest explaining your program in a bit more detail, perhaps in a different question, to get some feedback on whether this approach is even necessary (probably not).

可是我不能没有你 2024-09-19 11:06:29
ai_players = inspect.getmembers(players, inspect.isclass())

此行尝试不带参数调用 inform.isclass ,并将调用 getmembers 的结果作为第二个参数。您想要传递函数 inspect.isclass,所以就这样做(编辑:为了更清楚,您需要 inspect.getmembers(players, inform.isclass))。你认为这些括号有什么作用?

ai_players = inspect.getmembers(players, inspect.isclass())

This line tries to calls inspect.isclass with no arguments and gives the result of the call to getmembers as second argument. You want to pass the function inspect.isclass, so just do that (edit: to be clearer, you want inspect.getmembers(players, inspect.isclass)). What do you think these parentheses do?

不如归去 2024-09-19 11:06:29

以下是做你想做的事的更好方法。

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]

请注意,您想要定义一个类来保存玩家的详细信息,然后您可以根据需要创建该类的任意多个实例。

The following is a better way of doing what you want.

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]

Note that you want to define a single class to hold the details of a player, then you can create as many instances of this class as required.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文