Dynamically creating a class in Python

I have a bunch of classes in a module. Let them talk:

'''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.pyand create them. I use the python module for this 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 try to create a list of initialized objects
ai_players = [x() for x in ai_players]

I would ai_playersexpect that there will be a list of instances of objects like this (suppose it __str__returns a name):['Homer', 'Barney...]

However, I get the following error

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


The funny thing is that when I do not create class objects in a list comprehension or in 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 classes in list contexts / loops (did I try this in a for loop too?)

Or better: how could you dynamically load all classes into a module and create them in a list?

* Notice I'm using Python 2.6

EDIT

, , . , 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)

5- main.py

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

, "".

EDIT2:

, , getmembers - "" . :

>>> 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:

, issubclass() True, SAME. ()

+5
3

, .

, "name" .

.

Edit:

, issubclass() True, SAME.

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

, Player .

, . , , , , (, ).

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

inspect.isclass getmembers . inspect.isclass, (: , inspect.getmembers(players, inspect.isclass)). , ?

+1

Below is the best way to do 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]

Please note that you want to define one class for storing player parts, then you can create as many instances of this class as possible.

0
source

All Articles