Parallel Subclassing in Python? Using Subclasses in a Subclass - python

I'm trying to make my program extensible. It's for a generic card game that will play multiple types of games.
I have a generic server, let's call it class GenericServer. It imports classes like Cards, Players, Containers, etc.
I also have a game specific server class that is a subclass of GenericServer, let's call this one MagicServer.
What I'd like to do is have the MagicServer load game specific versions of the classes imported by GenericServer.
class GenericServer(object):
# imports Cards(object), Players(object), Containers(object)
class MagicServer(GenericServer):
# imports MagicCards(Cards), MagicPlayers(Players), MagicContainers(Containers)
The plan is to have multiple game specific servers all as subclasses of GenericServer but also with their own versions of Cards, Players, Containers etc. I've considered just breaking the servers up individually, but since they share so much of the same code I would like to subclass them from GenericServer.
Any suggestions on how to work this out?

is the server generating the cards, players, etc. or just serving/using them?
if the first... then the server class doesn't need to know what kind of card, player, etc. is used. Something else will create it and pass it to the server, who will use it using the standard Card (e.g.) API. This might be a lot easier to maintain and build.
But, if the second... then you could do it with class variables:
class Cards(object):
pass
class MagicCards(Cards):
pass
class GenericServer(object):
cards = Cards
def createCards(self):
return self.cards()
class MagicServer(GenericServer):
cards = MagicCards
gs = GenericServer()
ms = MagicServer()
gs.createCards()
<__main__.Cards at 0x3df6048>
ms.createCards()
<__main__.MagicCards at 0x3df6080>
These don't HAVE to be class variables - they could also be passed into the init function.
class GenericServer2(object):
def __init__(self, cards):
self.cards = cards
def createCards(self):
return self.cards()
gs2 = GenericServer2(Cards)
ms2 = GenericServer2(MagicCards)
gs2.createCards()
<__main__.Cards at 0x3ee5a58>
ms2.createCards()
<__main__.MagicCards at 0x3ee5470>
Which one to use? It really doesn't matter that much. The first is probably more straightforward if you are actually subclassing GenericServer a lot. If you are just using subclassing to differentiate the classes easily, the second is easier, and you can simulate the previous behaviour with factory functions:
def MagicServer2():
return GenericServer2(MagicCards)
etc.

You don't need to subclass everything, why not just subclass the generic server, then have instances of the other classes you need within magic server.
For example:
class MagicServer(GenericServer):
def __init__(self):
self.cards = Cards()
self.players = Players()
self.containers = Containers()
This way your magic server class has a unique Cards instance to use.

Related

Cleanest way to reset a class attribute

I have a class that looks like the following
class A:
communicate = set()
def __init__(self):
pass
...
def _some_func(self):
...some logic...
self.communicate.add(some_var)
The communicate variable is shared among the instances of the class. I use it to provide a convenient way for the instances of this class to communicate with one another (they have some mild orchestration needed and I don't want to force the calling object to serve as an intermediary of this communication). However, I realized this causes problems when I run my tests. If I try to test multiple aspects of my code, since the python interpreter is the same throughout all the tests, I won't get a "fresh" A class for the tests, and as such the communicate set will be the aggregate of all objects I add to that set (in normal usage this is exactly what I want, but for testing I don't want interactions between my tests). Furthermore, down the line this will also cause problems in my code execution if I want to loop over my whole process multiple times (because I won't have a way of resetting this class variable).
I know I can fix this issue where it occurs by having the creator of the A objects do something like
A.communicate = set()
before it creates and uses any instances of A. However, I don't really love this because it forces my caller to know some details about the communication pathways of the A objects, and I don't want that coupling. Is there a better way for me to to reset the communicate A class variable? Perhaps some method I could call on the class instead of an instance itself like (A.new_batch()) that would perform this resetting? Or is there a better way I'm not familiar with?
Edit:
I added a class method like
class A:
communicate = set()
def __init__(self):
pass
...
#classmethod
def new_batch(cls):
cls.communicate = set()
def _some_func(self):
...some logic...
self.communicate.add(some_var)
and this works with the caller running A.new_batch(). Is this the way it should be constructed and called, or is there a better practice here?

A good way to make classes for more complex playing card types than those found in a standard deck?

I am extremely new to object-oriented programming, and am trying to begin learning in python by making a simple card game (as seems to be traditional!). I have done the following example which works fine, and teaches me about making multiple instances of the PlayingCard() class to create an instance of the Deck() class:
class PlayingCard(object):
def __init__(self, suit, val):
self.suit = suit
self.value = val
def print_card(self):
print("{} of {}".format(self.value, self.suit))
class Deck(object):
def __init__(self):
self.playingcards = []
self.build()
def build(self):
for s in ["Spades", "Clubs", "Diamonds", "Hearts"]:
for v in range(1,14):
self.playingcards.append(PlayingCard(s,v))
deck = Deck()
I want to make something now with more complex cards, not just a standard 52 deck (which has nicely incrementing values). The deck I have in mind is the [Monopoly card game][1]:
There are 3 fundamental types of cards - ACTION cards, PROPERTY cards, and MONEY cards. The action cards perform different actions, the property cards belong to different colour sets, and the money cards can have different values. Additionally, the property cards can be "wildcards", and can be used as part of one of two sets. Finally, every card also has an equivalent money value (indicated in the top corner of each card). In the rent action cards, the card can only apply to the colour property indicated on the card.
My question is just generally how to handle a situation like this, and what would be a nice way to include these different cards in a class-based python program? Should I keep my single PlayingCard() class, and just have many inputs, such as PlayingCard(type="PROPERTY", value="3M"). Or would it be better to create seperate classes such as ActionPlayingCard(), PropertyPlayingCard(), etc ? Or is there a better way? As I say, I am at the beginning of my learning here, and how to organise these types of situations in terms of the higher level design.
Many thanks.
These are what we call "design decisions". Often the "correct" way is a matter of opinion. As a beginner, I think it would be instructive to try both implementations to see how they work. There will be trade offs no matter which one you pick. You have to decide which of those trade offs are most important. Making these kinds of decisions will be informed as you gain more experience.
When you are approaching a problem with OOP, you usually want to model behavior and properties in a reusable way, i.e., you should think of abstractions and organize your class hierarchy based on that.
I would write something like the following:
class Card:
def __init__(self, money_value=0):
self.money_value = money_value
class ActionCard(Card):
def __init__(self, action, money_value=0):
super().__init__(money_value=money_value)
self.action = action
class RentActionCard(ActionCard):
def __init__(self, action, color, money_value=0):
super().__init__(action, money_value=money_value)
self.color = color
def apply(self, property_card):
if property_card.color != self.color:
# Don't apply
# Apply
class PropertyCard(Card):
def __init__(self, color, money_value=0):
super().__init__(money_value=money_value)
self.color = color
class WildcardPropertyCard(PropertyCard):
def __init__(self, color, money_value=0):
super().__init__(color, money_value=money_value)
class MoneyCard(Card):
def __init__(self, money_value=0):
super().__init__(money_value=money_value)
Due to Python being a dynamically typed language, OOP is a little harder to justify in my opinion, since we can just rely on duck typing and dynamic binding,
the way you organize your hierarchy is less important.
If I were to model this problem in C# for example, I would without a doubt use the hierarchy showed above, because I could rely on polymorphism to represent different types and guide the flow of my logic based on what type of card is being analyzed.
A couple of final remarks:
Python has very powerful builtin types, but most of the time
using new custom types that build on them makes your life easier.
You don't have to inherit from object since types in Python 3 (which is
the only one maintained as of today) inherit from object by default.
But, at the end of the day, there isn't a perfect answer, the best way would be to try both of the approaches and see what you're more comfortable with.
You could use inheritance.
This is where you create a main class then have sub-classes which still contain functions and values from the mother class however can also have extra values and functions for that specific class.
class Apple:
def __init__(self, yearMade):
pass
def ring(self):
print('ring ring')
class iPhone(Apple):
def __init__(self, number)
number = number
def func():
pass
Now the iPhone class has the same functions as the Apple class and its own function.
If you wish to learn more about inheritance I recommend doing some research.
For monopoly, i would design the game landings point of view. Not cards. Cards simply represent the landings for real world.

Having mulitple classes inside a class python3?

I'd like to do something like this:
Robot.GyroController.getLatestMeasurement()
Is there a way to do this?
More specifically I wanted to do this:
robot = Robot.__init__(arguments)
latesMeasurement = robot.GyroController.getLatestMeasurement()
Is this valid python? And most importantly, is it possible to do so?
I need to do a LEGO competition. I can use whatever programming language that I want to and so I figured I'd write a library to get slightly better abstraction over the existent one (also to practice python as I want to get into tensorflow)
I have a class called robot. This class is initialized with references to all the motors/sensors the robot has.
From there, I want some subclasses (or maybe something else?) that can control motors, sensors, and do some other fancy stuff.
Instead of passing robot (that contains references to motors/sensors) every time I use motors/sensors, I figured that I could do something like this.
PS. I am coming from OOP, and still learning python, so please, it is my intention to improve the question as best as I can. Please give me a chance.
From what i read, you want to have a Robot Class that has multiple Motor's class or something like that, maybe this could work as a hint on how that could be done:
class Motor:
def __init__(self, motor):
self.motor = motor
def go_slow(self):
self.motor.setval = 100
def go_fast(self):
self.motor.setval = 255
class Robot:
def ___init___(self, reference_motor1, reference_motor2):
self.motor1 = Motor(reference_motor1)
self.motor2 = Motor(reference_motor1)
def go_straight_slow():
self.motor1.go_slow()
self.motor2.go_slow()
def go_straight_fast():
self.motor1.go_fast()
self.motor2.go_fast()
here's a dummy example on how your code maybe look like if you wanna do it object oriented.
Edit:
assuming that you already got the class that "MotorController"
class MotorController:
def __init__(self):
pass
def goStraight():
pass
class Robot:
def ___init___(self):
self.motor_controllers = [] #List for storing all motors
def add_motor_reference(self, reference):
self.motor_controllers.append(MotorController(reference))
#Appends new motors to the list
def go_straight(self):
for motor_controller in self.motor_controllers:
motor_controller.goStraight()
#Executes for the "goStraight" function on every motor in the list
Edit:
If you want to add the motors on the constructor of the class you could do something like:
class Robot:
def ___init___(self, *args):
self.motor_controllers = [] #List for storing all motors
for motor in args:
self.motor_controllers.append(MotorController(motor))
#Here every motor reference you pass will be automatically added in the list of motor controllers.

Implement same methods in different classes

I really don't know how to word this problem, so I'll try to explain it with an example.
Let's say I have three GUI classes:
Base Surface class
Detailed Surface Class
Sprite Class
All of them are independent of each other, no inheritance among them.
Now I have a function "drag()" that makes a surface/sprite dragable, and I want to implement this function as a method for all three of them.
Since it's the exact same code for all implementations I find it annoying, cumbersome and bad practice to rewrite the code.
The only thing I came up with so far was to make a saperate class for it and inherit this class. But that also doesn't seem to be the way to go.
I'd be very thankfull for some advice.
EDIT
Another example with a slightly different setup - I have the following classes:
BaseSurface
Dragable
Resizable
EventHandler
Only the first one is independent, the others depend on the first (must be inherited).
The end user should, without any effort, be able to choose between a simple BaseSurface, one with that implements dragable, one with resizable, one with eventHandler, and any combination. By "without any effort" I mean the end user should not have to make e custom Class and inherit the desired classes plus call the appropriate methods (init, update, ...) that some classes share.
So what I could do is make a class for every possible combination, eg.
"BaseSurfaceDrag", "BaseSurfaceDragResize", ...
which will get messy really quickly. Whats a different and better approach to this?
This is exactly the kind of case that you should use a parent class for. In both cases it looks like your parent class (logically) should be something like:
class Drawable(object):
def drag(self, *args, **kwargs):
"""Drag and drop behavior"""
# Your code goes here
Then each of your other classes inherits from that
class BaseSurface(Drawable):
# stuff
class DetailedSurface(Drawable):
# stuff
class Sprite(Drawable):
# stuff
In the second case what you have are interfaces, so you could logically do something like:
class DragInterface(object):
"""Implements a `drag` method"""
def drag(self):
"""Drag and drop behavior"""
# Your code goes here
class ResizeInterface(object):
"""Implements a `resize` method"""
def resize(self):
"""Drag and drop resize"""
# Code
class EventHandlerInterface(object):
"""Handles events"""
def handle(self, evt):
# Code
class MyNewSurface(BaseSurface, DragInterface, ResizeInterface):
"""Draggable, resizeable surface"""
# Implement here

Python inheritance: convert from Base class to Derived class

I'm still pretty new to Python, so bear with me. Here is my problem:
I have a base class, lets call it a sports game:
class Game:
def __init__(self):
self.home_team = None
self.away_team = None
and I have multiple derived classes for each sport, but lets use baseball as an example:
class BaseballGame(Game):
def __init__(self):
self.home_pitcher = None
self.away_pitcher = None
So far everything is good. However I have another utility function in a separate python module which will generate and populate a list of all the games being played on a given day for that sport.
def fetch_game_data:
games = []
games_found_online = code_that_fetches_online_games
for online_game in games_found_online:
new_game = Game()
new_game.home_team = ...
new_game.away_team = ...
games.append(new_game)
return games
Its obviously much more complicated than this with a lot of parsing using BeautifulSoup, but you get the point. My problem is that this function returns a list of the Base class, but I need a list of the Derived class. The derived classes will be the ones calling this function to populate a list and operate on it. The way I see it, I have two options:
I could implement a dreaded circular dependency and have the fetch_game_data function know about all of the derived classes and call the derived class constructors instead of the base class constructors. The derived classes already need to import the fetch_data module, but now the fetch_data module will have to import all of the derived classes to know about their constructors. And what makes it worse is that the fetch_data module won't have any need to touch any of the derived class fields - it only populates base class fields. The circular dependency is JUST so I can create the objects.
I could implement code that downcasts a Base class Game to a Derived class Game (like BaseballGame). Then, when the fetch_game_data function returns all of the games I can just convert them all to a Derived class object and continue on my way. Unfortunately I haven't seen much in the way of how to implement this. I tried just changing the class variable, but then the code complains because Derived class variables don't exist.
Another option I considered, but quickly fell apart, was to send an existing list of derived class objects into the fetch_game_data function, and instead of creating new Game objects it would just populate existing ones. The problem is that I won't know how many game objects I need. The fetch_game_data function determines how many games are needed by parsing the webpage. I suppose I could send in the max number of games but using number_of_teams/2, but what if there is a double-header in baseball? This quickly falls apart. I suppose I could write a function that will fetch the game data and just return the number of games for the day. Then I could populate a list of Derived games that size and send it in to be populated. But I would have to fetch all the webpage data AGAIN and parse it AGAIN to populate the list.
Nothing but bad options! I'm hoping there is a simple and elegant solution that has just eluded me thus far. I'm open to any suggestions, including a redesign if it makes sense.
Thanks!
I am porting existing code from c++ and I encountered a similar problem.
I have a generic class X and type specific classes e.g. XInt, XStr etc. There is more differences between these classes than just the type of the value. In c++ it was easy: I have virtual X::compare(X const& other).
It is overridden in XInt. Inside the overridden method I first handle cases where the 'other' is not XInt and then do static_cast<XInt const&>(other).
It is clearly impossible in python. So here is my solution. I added a non-virtual non-public function to do actual comparison to XInt and did not annotate the type of the parameter:
def _compare(self, other) -> int:
<do-actual-comparison>
def compare(self, other: X) -> int:
<handle cases where other is not XInt>
return self._compare_worker(other)
Did not test it yet but mypy does not complain and it seems that it will work due to duck typing in python. Maybe something similar will work for you.
You can convert a class of instance after it is initiated, see example below:
class A:
def __repr__(self):
return "class A"
def convert(self):
'convert A to B class'
self.__class__ = B
def hello(self):
print('hello from A')
class B(A):
""
def __repr__(self):
return "class B"
def hello(self):
print('hello from B')
a = A()
print(a)
a.hello()
a.convert()
print(a)
a.hello()
# output:
>>> "class A"
>>> "hello from A"
>>> "class B"
>>> "hello from B"
In your case, you can convert the class Game to whatever subclass you want after the instance is created.
Python cannot cast an object to another class (even subclass).
You must use concrete class when you create the game object. It can be done in a factory method (e.g. create_game), like this:
def create_game(online_game):
if online_game.type == 'baseball':
return BaseballGame()
else:
return Game()
def fetch_game_data:
games = []
games_found_online = code_that_fetches_online_games
for online_game in games_found_online:
new_game = create_game(online_game)
new_game.home_team = ...
new_game.away_team = ...
games.append(new_game)
return games

Categories