My program represents a basic model of a player in Fantasy Football with players playing in different positions and having different scoring systems for the actions on the pitch.
A particular usage is a table with players and their values per price which provides some suggestions about who to pick into the team.
I would like to get feedback about my design choice to represent a player as a class and the way I used Python class model for doing that, particularly usage of inheritance.
I'm also wondering whether representing the scoring system as class level attributes for every position is the common way of doing things.
The code:
"""Basic modelling of a player in Fantasy Football via classes with inheritance."""
class Player():
"""Base class representing a player in Fantasy Football."""
assist = 3
pos_impact = 1
neg_impact = -1
yellow_card = -1
made_start = 1
played_60minutes = 1
def __init__(self, name='', price=-1, club=''):
"""Initialises a player with some shared properties."""
self.name = name
self.price = price
self.club = club
self.assist = 0
self.pos_impact = 0
self.neg_impact = 0
self.yellow_card = 0
self.made_start = 1
self.played_60minutes = 0.95
def calculate_points(self):
"""Calculates points for properties shared by all the players."""
total_points = 0
total_points += self.assist * Player.assist
total_points += self.pos_impact * Player.pos_impact + self.neg_impact * Player.neg_impact
total_points += self.yellow_card * Player.yellow_card
total_points += self.made_start * Player.made_start
return total_points
def calculate_value_per_price(self):
"""Calculates how many points a player earns per price."""
total_points = self.calculate_points()
return total_points / self.price
class Goalkeeper(Player):
"""Class representing a goalkeeper in fantasy football."""
goal = 8
clean_sheet = 4
save = 0.5
two_or_more_conceded = -1
def __init__(self, name='', price=-1, club=''):
"""Initialises a goalkeeper."""
super().__init__(name, price, club)
self.goal = 0
self.clean_sheet = 0
self.save = 0
self.two_or_more_conceded = 0
def calculate_points(self):
"""Calculates points for a goalkeeper."""
total_points = super().calculate_points()
total_points += self.goal * Goalkeeper.goal
total_points += self.clean_sheet * Goalkeeper.clean_sheet
total_points += self.save * Goalkeeper.save
total_points += self.two_or_more_conceded * Goalkeeper.two_or_more_conceded
return total_points
class Defender(Player):
"""Class representing a defender in fantasy football."""
goal = 6
clean_sheet = 4
two_or_more_conceded = -1
def __init__(self, name='', price=-1, club=''):
"""Initialises a defender."""
super().__init__(name, price, club)
self.goal = 0
self.clean_sheet = 0
self.two_or_more_conceded = 0
def calculate_points(self):
"""Calculates points for a defender."""
total_points = super().calculate_points()
total_points += self.goal * Defender.goal
total_points += self.clean_sheet * Defender.clean_sheet
total_points += self.two_or_more_conceded * Defender.two_or_more_conceded
return total_points
class Midfielder(Player):
"""Class representing a midfielder in fantasy football."""
goal = 5
clean_sheet = 1
played_90minutes = 1
def __init__(self, name='', price=-1, club=''):
"""Initialises a midfielder."""
super().__init__(name, price, club)
self.goal = 0
self.clean_sheet = 0
self.played_90minutes = 0
def calculate_points(self):
"""Calculates points for a midfielder."""
total_points = super().calculate_points()
total_points += self.goal * Midfielder.goal
total_points += self.clean_sheet * Midfielder.clean_sheet
total_points += self.played_90minutes * Midfielder.played_90minutes
return total_points
class Forward(Player):
"""Class representing a forward in fantasy football."""
goal = 4
played_90minutes = 1
def __init__(self, name='', price=-1, club=''):
"""Initialises a forward."""
super().__init__(name, price, club)
self.goal = 0
self.played_90minutes = 0
def calculate_points(self):
"""Calculates points for a forward."""
total_points = super().calculate_points()
total_points += self.goal * Forward.goal
total_points += self.played_90minutes * Forward.played_90minutes
return total_points
def compare_players(players):
"""Compares players by value per price."""
print_players_comparison(calculate_players_comparison(players))
def calculate_players_comparison(players):
"""
Creates a table with players properties;
Sorted by value per price in descending order.
"""
players_stats = []
for player in players:
player_stats = {}
player_stats['name'] = player.name
player_stats['club'] = player.club
player_stats['points'] = player.calculate_points()
player_stats['price'] = player.price
player_stats['value_per_price'] = player.calculate_value_per_price()
players_stats.append(player_stats)
return sorted(players_stats, key=lambda x: x['value_per_price'], reverse=True)
def print_players_comparison(players_stats):
"""Prints players comparison."""
print(f'{"Name":<16} {"Club":<16} {"Points":<10} {"Price":<10} {"Value per price":<10}')
print('='*72)
for player in players_stats:
print(f'{player["name"]:<16} {player["club"]:<16} {player["points"]:<10.2f} {player["price"]:<10.2f} {player["value_per_price"]:<10.2f}')
if __name__ == '__main__':
ederson = Goalkeeper(name='Ederson', price=11.5, club='Man City')
reguilon = Defender(name='Sergio Reguilon', price=8.8, club='Tottenham')
grealish = Midfielder(name='Jack Grealish', price=9.2, club='Aston Villa')
maupay = Forward(name='Neal Maupay', price=7.6, club='Brighton')
ederson.pos_impact = 0.65
ederson.neg_impact = 0.20
ederson.yellow_card = 0.05
ederson.clean_sheet = 0.40
ederson.save = 3
ederson.two_or_more_conceded = 0.29
reguilon.pos_impact = 0.52
reguilon.neg_impact = 0.26
reguilon.yellow_card = 0.10
reguilon.assist = 0.08
reguilon.goal = 0.03
reguilon.clean_sheet = 0.36
reguilon.two_or_more_conceded = 0.32
grealish.pos_impact = 0.42
grealish.neg_impact = 0.33
grealish.yellow_card = 0.07
grealish.played_90minutes = 0.80
grealish.assist = 0.30
grealish.goal = 0.35
grealish.clean_sheet = 0.25
maupay.pos_impact = 0.18
maupay.neg_impact = 0.49
maupay.yellow_card = 0.05
maupay.played_90minutes = 0.65
maupay.assist = 0.12
maupay.goal = 0.26
players = [ederson, reguilon, grealish, maupay]
compare_players(players)