3

I am writing a simple chess program to practice my OOP in python 3 and was wondering how to dynamically change (before class creation) the base class for a class definition. My class structure is this.

  • abstract Piece class -> various derived pieces
  • Board class, has a composite of derived Pieces, and 8x8 matrix, and some methods
  • abstract Interface class -> CLI or
  • abstract Interface class -> GUI (also subclassing Tkinter)
  • Game class (for processing the game logic and main loop), which currently has a Board class member.

I initially implemented the Game class as having an interface data member that is defined during init but I'm finding myself sending a lot of the other internal Game data to the Interface composite member. I feel it would be more elegant to have the Game class be a subclass of either Interface subclass so the it could access their methods directly (and make them abstract).

However I want a version of the Game class that can do this dynamically so that I don't have to code it twice or inherit from both and make runtime decisions on which base class to use. I've currently done this by nesting the Game class inside a function like so.

def Game(ui):
    class Game(ui):
        ...
    return Game()

The crummy naming is part of the reason I don't like this solution. I want to be able to call the Game class on its own without explicitly using or acknowledging that I'm doing anything out of the ordinary.

Is there a way to do this with a metaclass or a class decorator? I have only been able to get them to affect class attributes, not the parent classes.

2 Answers 2

4

The class statement is "syntactic sugar" for

type(name, bases, dict)

You can create such a dynamic class using type like this

>>> class ui():
...     def start(self): print("Started!")
... 
>>> Game = type("Game", (ui,), {})
>>> game = Game()
>>> game.start()
Started!
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks @gnibbler, but I had to modify this a little to keep any of the new attributes that the Game class introduced by using Game = type("Game", (ui,), dict(Game.__dict__)) instead. Also, I hadn't realized the syntactic sugar of the class statement though, so thanks for that!
3

You could use a very simple metclass here, but that's overkill. You can just swap out which class you're using as the base class based on whatever condition you want:

>>> class Foo: pass
... 
>>> class Bar: pass
... 
>>> x = 3
>>> class Game(Foo if x < 3 else Bar):pass
... 
>>> Game.__bases__
(<class '__main__.Bar'>,)

Note that this isn't really any different than the formalism you have. However, if I was to use your code, I wouldn't create the Game class and the instance all in the function. I would do something like:

def Game_Factory(base):
    class Game(base):
         ...
    return Game

Game1 = Game_Factory(base1)
Game2 = Game_Factory(base2)

game1_instance = Game1()
game2_instance = Game2()

This gives you much easier access to the Game class (rather than needing to inspect an instance to get it).

1 Comment

This is probably the cleanest way of doing this outside of refactoring my class setup.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.