Что делает моя программа
Моя программа симулирует фэнтези-футбол. Его входными данными являются команды и результаты команд в конкретном матче, а выходными данными — количество очков, заработанных каждой командой в каждом матче в соответствии с заданными правилами подсчета очков.
Вот пример команды:
team1 = [
calculate_points.Player(p_id=204597, full_name="Jordan Pickford", club='ENG',
position='goalkeeper', is_captain=True,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=213442, full_name="Luke Shaw", club='ENG',
position='defender', is_captain=False,
is_vice_captain=True, points=0.0),
calculate_points.Player(p_id=204614, full_name="Harry Maguire", club='ENG',
position='defender', is_captain=False,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=204615, full_name="Mason Mount", club='ENG',
position='midfielder', is_captain=False,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=204617, full_name="Harry Kane", club='ENG',
position='forward', is_captain=False,
is_vice_captain=False, points=0.0),
]
И пример командного результата:
team_result1 = calculate_points.TeamResult(
team='ENG',
goals_for=1,
goals_against=0,
scored_goals=['Harry Kane'],
made_assist=['Kalvin Phillips'],
played60=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Raheem Sterling', 'Declan Rice', 'Harry Kane'],
finished_game=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Mason Mount', 'Harry Kane'],
got_booked=['Kyle Walker'],
made_shots_on_tg=['Harry Kane', 'Harry Kane', 'Raheem Sterling',
'Mason Mount', 'Harry Kane'],
saves=3)
Какую обратную связь я хотел бы получить
Суть программы — get_team_points() функция, которая вычисляет, сколько очков команда заработала в данном матче, добавив очки, заработанные каждым игроком в команде.
Чтобы иметь возможность выполнять высокопроизводительное моделирование, он должен работать как можно быстрее. Имея это в виду, я ищу способ добиться этого.
Поскольку у меня нет никаких ограничений на то, что можно использовать для этого, я открыт для любых предложений, включая рефакторинг существующего кода, использование сторонних библиотек, написание расширений C / C ++ или даже переписывание программы на другом языке.
Также приветствуются любые другие отзывы, выходящие за рамки производительности.
Что я уже пробовал
- уменьшение размера
TeamResultобъект, я попытался использовать список идентификаторов игроков вместо их полных имен. - устранив некоторые вызовы функций, я попытался удалить функции для расчета очков игрока на позицию, такие как
calculate_goalkeeper_points(),calculate_defender_points(),calculate_midfielder_points()иcalculate_forward_points()чтобы сделать это в одной функции для всех игроков. - с использованием
Cythonдля изготовленияcalculate_team_points()функция предварительно скомпилирована и импортирована как расширение C.
Хотя существенного ускорения эти шаги не получили.
Мой код, включая несколько модульных тестов
Calcul_points.py
from dataclasses import dataclass
from typing import List
CAPTAIN_BONUS = 2.0
VICE_CAPTAIN_BONUS = 1.5
@dataclass
class Scoring:
"""
Represents football scoring.
"""
defender_goal: int=6
midfielder_goal: int=5
forward_goal: int=4
assist: int=3
defender_shot_on_tg: float=0.6
midfielder_or_forward_shot_on_tg: float=0.4
goalkeeper_save: float=0.5
pos_impact: float=0.3
neg_impact: float=-pos_impact
yellow_card: int=-1
defender_or_goalkeeper_clean_sheet: int=4
midfielder_clean_sheet: int=1
played60: int=2
midfielder_or_forward_finished_game: int=1
scoring = Scoring()
PlayerId = int
PlayerName = str
PlayerClub = str
PlayerPosition = str
Points = float
@dataclass
class Player:
"""
Represents a player in Fantasy Football.
"""
p_id: PlayerId
full_name: PlayerName
club: PlayerClub
position: PlayerPosition
is_captain: bool=False
is_vice_captain: bool=False
points: Points=0.0
Team = List[Player]
Teams = List[Team]
@dataclass
class TeamResult:
"""
Represents the result of a particular team with its name, goals scored,
goals conceded, players who scored goals and made assists and the number of
saves made by the goalkeeper.
"""
team: PlayerClub
goals_for: int
goals_against: int
scored_goals: List[PlayerName]
made_assist: List[PlayerName]
played60: List[PlayerName]
finished_game: List[PlayerName]
got_booked: List[PlayerName]
made_shots_on_tg: List[PlayerName]
saves: int
TeamResults = List[TeamResult]
def get_team_points(team: Team, team_result: TeamResult) -> Points:
"""
Returns how many points the given team earned with the given team result.
"""
team = calculate_team_points(team, team_result)
team = apply_captaincy(team)
return sum(p.points for p in team)
def calculate_team_points(team: Team, team_result: TeamResult) -> Team:
"""
Assigns earned points for each player in the team.
"""
points_factory = {
'goalkeeper': calculate_goalkeeper_points,
'defender': calculate_defender_points,
'midfielder': calculate_midfielder_points,
'forward': calculate_forward_points,
}
for player in team:
player.points = points_factory[player.position](player, team_result)
return team
def calculate_goalkeeper_points(goalkeeper: Player, team_result: TeamResult) -> Points:
"""
Returns points earned by a goalkeeper.
"""
got_booked = scoring.yellow_card if goalkeeper.full_name in team_result.got_booked else 0
goals_conceded = scoring.defender_or_goalkeeper_clean_sheet if team_result.goals_against == 0 else team_result.goals_against // 2 * -1
impact = calculate_impact(team_result)
saves = team_result.saves * scoring.goalkeeper_save
playing_time = scoring.played60
return sum((goals_conceded, impact, saves, playing_time, got_booked))
def calculate_defender_points(defender: Player, team_result: TeamResult) -> Points:
"""
Returns points earned by a defender.
"""
got_booked = scoring.yellow_card if defender.full_name in team_result.got_booked else 0
goals_conceded = scoring.defender_or_goalkeeper_clean_sheet if team_result.goals_against == 0 else team_result.goals_against // 2 * -1
impact = calculate_impact(team_result)
playing_time = scoring.played60
goals = team_result.scored_goals.count(defender.full_name) * scoring.defender_goal
assists = team_result.made_assist.count(defender.full_name) * scoring.assist
shots_on_tg = ((team_result.made_shots_on_tg.count(defender.full_name) -
team_result.scored_goals.count(defender.full_name)) * scoring.defender_shot_on_tg)
return sum((goals_conceded, impact, playing_time, goals, assists,
got_booked, shots_on_tg))
def calculate_midfielder_points(midfielder: Player, team_result: TeamResult) -> Points:
"""
Returns points earned by a midfielder.
"""
got_booked = scoring.yellow_card if midfielder.full_name in team_result.got_booked else 0
clean_sheet = scoring.midfielder_clean_sheet if team_result.goals_against == 0 else 0
impact = calculate_impact(team_result)
playing_time = scoring.midfielder_or_forward_finished_game + scoring.played60 if midfielder.full_name in team_result.finished_game else scoring.played60
goals = team_result.scored_goals.count(midfielder.full_name) * scoring.midfielder_goal
assists = team_result.made_assist.count(midfielder.full_name) * scoring.assist
shots_on_tg = ((team_result.made_shots_on_tg.count(midfielder.full_name) -
team_result.scored_goals.count(midfielder.full_name)) * scoring.midfielder_or_forward_shot_on_tg)
return sum((clean_sheet, impact, playing_time, goals, assists, got_booked,
shots_on_tg))
def calculate_forward_points(forward: Player, team_result: TeamResult) -> Points:
"""
Returns points earned by a forward.
"""
got_booked = scoring.yellow_card if forward.full_name in team_result.got_booked else 0
impact = calculate_impact(team_result)
playing_time = scoring.midfielder_or_forward_finished_game + scoring.played60 if forward.full_name in team_result.finished_game else scoring.played60
goals = team_result.scored_goals.count(forward.full_name) * scoring.forward_goal
assists = team_result.made_assist.count(forward.full_name) * scoring.assist
shots_on_tg = ((team_result.made_shots_on_tg.count(forward.full_name) -
team_result.scored_goals.count(forward.full_name)) * scoring.midfielder_or_forward_shot_on_tg)
return sum((impact, playing_time, goals, assists, got_booked, shots_on_tg))
def calculate_impact(team_result: TeamResult) -> Points:
"""
Calculates impact for a team based on whether it won, lost or drew.
"""
if team_result.goals_for > team_result.goals_against:
return scoring.pos_impact
elif team_result.goals_for < team_result.goals_against:
return scoring.neg_impact
return 0
def apply_captaincy(team: Team) -> Team:
"""
Multiplies points of captain and vice_captain.
"""
for player in team:
if player.is_captain:
player.points *= CAPTAIN_BONUS
elif player.is_vice_captain:
player.points *= VICE_CAPTAIN_BONUS
return team
test_points.py
import unittest
import calculate_points
team1 = [
calculate_points.Player(p_id=204597, full_name="Jordan Pickford", club='ENG',
position='goalkeeper', is_captain=True,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=213442, full_name="Luke Shaw", club='ENG',
position='defender', is_captain=False,
is_vice_captain=True, points=0.0),
calculate_points.Player(p_id=204614, full_name="Harry Maguire", club='ENG',
position='defender', is_captain=False,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=204615, full_name="Mason Mount", club='ENG',
position='midfielder', is_captain=False,
is_vice_captain=False, points=0.0),
calculate_points.Player(p_id=204617, full_name="Harry Kane", club='ENG',
position='forward', is_captain=False,
is_vice_captain=False, points=0.0),
]
team_result1 = calculate_points.TeamResult(
team='ENG',
goals_for=1,
goals_against=0,
scored_goals=['Harry Kane'],
made_assist=['Kalvin Phillips'],
played60=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Raheem Sterling', 'Declan Rice', 'Harry Kane'],
finished_game=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Mason Mount', 'Harry Kane'],
got_booked=['Kyle Walker'],
made_shots_on_tg=['Harry Kane', 'Harry Kane', 'Raheem Sterling',
'Mason Mount', 'Harry Kane'],
saves=3)
team_result2 = calculate_points.TeamResult(
team='ENG',
goals_for=2,
goals_against=1,
scored_goals=['Raheem Sterling', 'Mason Mount'],
made_assist=['Substitutes', 'Luke Shaw'],
played60=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Raheem Sterling', 'Mason Mount', 'Harry Kane'],
finished_game=['Jordan Pickford', 'Luke Shaw', 'John Stones',
'Harry Maguire', 'Kieran Trippier', 'Kyle Walker',
'Raheem Sterling'],
got_booked=['Jordan Pickford'],
made_shots_on_tg=['Harry Kane', 'Mason Mount', 'Mason Mount',
'Substitutes', 'Harry Kane'], saves=2)
team_result3 = calculate_points.TeamResult(
team='ENG',
goals_for=0,
goals_against=2,
scored_goals=[],
made_assist=[],
played60=['Jordan Pickford', 'Luke Shaw', 'John Stones', 'Harry Maguire',
'Kieran Trippier', 'Kyle Walker', 'Kalvin Phillips',
'Declan Rice', 'Harry Kane'],
finished_game=['Jordan Pickford', 'Luke Shaw', 'John Stones',
'Harry Maguire', 'Kieran Trippier', 'Kyle Walker',
'Kalvin Phillips', 'Declan Rice', 'Harry Kane'],
got_booked=['Luke Shaw', 'John Stones', 'Raheem Sterling', 'Mason Mount'],
made_shots_on_tg=['Harry Kane'], saves=2)
class TestGetTeamPoints(unittest.TestCase):
def test_won_game_with_cleansheet(self):
self.assertAlmostEqual(calculate_points.get_team_points(team1, team_result1), 44.15)
def test_won_game_with_conceded_goal(self):
self.assertAlmostEqual(calculate_points.get_team_points(team1, team_result2), 25.65)
def test_lost_game_with_no_goals_scored(self):
self.assertAlmostEqual(calculate_points.get_team_points(team1, team_result3), 7.45)
if __name__ == '__main__':
unittest.main()
1 ответ
Я не думаю, что твой Scoring class — отличное место для хранения констант. (Даже если бы это было так, обычный класс со статикой подошел бы лучше, чем одноэлементный класс данных.) Если вы хотите сделать что-то подобное, создайте модуль вместо класса, чтобы получить дешевое пространство имен. Учитывая, как используются эти цифры, я предлагаю просто переместить их в строку.
Приятно видеть, что вы применяете псевдонимы для PlayerId и т. д. Если вы хотите сделать еще один шаг в безопасности типов, вместо простого псевдонима вы можете использовать NewType.
Я не понимаю почему С club является собственностью плеера. Разве это не собственность команды?club Предполагается, что это свойство игрока, почему оно также связано с объектом результата?
Имея is_captain и is_vice_captain as booleans для игрока проблематично, потому что вы можете сделать несколько капитанов команд, что, вероятно, невозможно. Более надежный вариант — просто включить в командный объект капитана и заместителей.
Я считаю, что «TeamResult» более понятно как «TeamGame», поскольку он относится к объекту команды, а не сохраняет строку клуба. Кроме того, некоторые из этих списков должны быть наборами с учетом того, как они используются.
То, как вы выполняете мутацию на месте для apply_captaincy вводит проблемы — более сложный для отладки код и объекты, достоверность которых труднее гарантировать. Вместо этого возвращайте номера точек из методов и не сохраняйте их ни в одном из объектов класса.
Ваш points_factory это несколько неудобный удар по полиморфизму, где более традиционная модель наследования полиморфных классов упростит задачу, а также сократит много повторяющегося кода в calculate_* методы. Даже если бы вы сохранили этот шаблон, передача позиций в виде строк не является хорошей идеей, и вместо этого они должны быть перечислениями.
team1 и т. д. в вашем тестовом модуле могут быть исключены из глобального пространства имен и перемещены, например, в статику вашего тестового класса. Переменные результата следует переместить в отдельные методы тестирования, поскольку они используются только один раз.
Ссылки на ваши плееры, а не строки с полными именами, лучше представить в виде идентификаторов — для этого и нужны идентификаторы.
В вашей логике есть элемент, которого я не понимаю: вы всегда добавлять scoring.played60 независимо от того, действительно ли данный игрок появлялся в вашем played60 коллекция. Я показал (закомментированную) реализацию, которая не добавляет этот элемент оценки, если игрок не появился в этой коллекции. Хотя это закомментировано, результаты, которые я показал, идентичны вашим.
Ваши тестовые данные немного странные — у вас большие пробелы в определении вашей команды и не хватает многих игроков, упомянутых в ваших результатах. Может быть, это нормально; пока вы не подтвердите, что ссылки в ваших объектах результатов появляются в экземпляре группы, и тогда это не нормально.
Предложенный
from dataclasses import dataclass
from numbers import Real
from typing import NewType, Iterable, Tuple, ClassVar, Set, Sequence
import unittest
from unittest import TestCase
PlayerId = NewType('PlayerId', int)
PlayerName = NewType('PlayerName', str)
Club = NewType('Club', str)
Points = NewType('Points', Real)
@dataclass
class Player:
"""
Represents a player in Fantasy Football.
"""
p_id: PlayerId
full_name: PlayerName
shot_bonus: ClassVar[Points] = 0.4
clean_sheet_bonus: ClassVar[Points] = 4
assist_bonus: ClassVar[Points] = 3
goal_bonus: ClassVar[Points]
@staticmethod
def booked_points(was_booked: bool) -> Points:
if was_booked:
return -1 # yellow_card
return 0
@classmethod
def clean_sheet_points(cls, goals_against: int) -> Points:
if goals_against == 0:
return cls.clean_sheet_bonus
return -(goals_against//2)
@staticmethod
def playtime_points(played_60: bool, finished_game: bool) -> Points:
# if played_60:
return 2
# return 0
@classmethod
def goal_points(cls, goals: int) -> Points:
return cls.goal_bonus * goals
@classmethod
def assist_points(cls, assists: int) -> Points:
return assists * cls.assist_bonus
@classmethod
def shot_points(cls, shots_on: int, scored_goals: int) -> Points:
return cls.shot_bonus*(shots_on - scored_goals)
def captaincy_bonus(self, team: 'Team') -> Points:
if team.captain is self:
return 2
if team.vice_captain is self:
return 1.5
return 1
def get_points_before_captaincy(self, game: 'TeamGame') -> Points:
return (
self.booked_points(self.p_id in game.got_booked)
+ self.clean_sheet_points(game.goals_against)
+ game.impact
+ self.playtime_points(
self.p_id in game.played60,
self.p_id in game.finished_game,
)
+ self.goal_points(
game.scored_goals.count(self.p_id)
)
+ self.assist_points(
game.made_assist.count(self.p_id)
)
+ self.shot_points(
game.made_shots_on_tg.count(self.p_id),
game.scored_goals.count(self.p_id),
)
)
def get_points(self, game: 'TeamGame') -> Points:
return self.get_points_before_captaincy(game) * self.captaincy_bonus(game.team)
class GoalKeeper(Player):
shot_bonus = 0
goal_bonus = 0
assist_bonus = 0
def get_points_before_captaincy(self, game: 'TeamGame') -> Points:
return (
super().get_points_before_captaincy(game)
+ game.saves * 0.5
)
class Defender(Player):
shot_bonus = 0.6
goal_bonus = 6
class FrontLine(Player):
@staticmethod
def playtime_points(played_60: bool, finished_game: bool) -> Points:
p = Player.playtime_points(played_60, finished_game)
if finished_game:
p += 1
return p
class Midfielder(FrontLine):
clean_sheet_bonus = 1
goal_bonus = 5
@classmethod
def clean_sheet_points(cls, goals_against: int) -> Points:
if goals_against == 0:
return cls.clean_sheet_bonus
return 0
class Forward(FrontLine):
goal_bonus = 4
@classmethod
def clean_sheet_points(cls, goals_against: int) -> Points:
return 0
class Team:
def __init__(
self,
club: Club,
players: Iterable[Player],
vice_captain: Player,
captain: Player,
) -> None:
self.club, self.vice_captain, self.captain = club, vice_captain, captain
self.players = {p.p_id: p for p in players}
@dataclass
class TeamGame:
"""
Represents the result of a particular team with its name, goals scored,
goals conceded, players who scored goals and made assists and the number of
saves made by the goalkeeper.
"""
team: Team
goals_for: int
goals_against: int
saves: int
scored_goals: Sequence[PlayerId]
made_assist: Sequence[PlayerId]
made_shots_on_tg: Sequence[PlayerId]
played60: Set[PlayerId]
finished_game: Set[PlayerId]
got_booked: Set[PlayerId]
@property
def points_by_player(self) -> Iterable[Tuple[Player, Points]]:
for player in self.team.players.values():
yield player, player.get_points(self)
@property
def won(self) -> bool: return self.goals_for > self.goals_against
@property
def lost(self) -> bool: return self.goals_for < self.goals_against
@property
def draw(self) -> bool: return self.goals_for == self.goals_against
@property
def impact(self) -> Points:
"""
Calculates impact for a team based on whether it won, lost or drew.
"""
if self.won: return 0.3
if self.lost: return -0.3
return 0
@property
def points(self) -> Points:
"""
Returns how many points the given team earned with the given team result.
"""
return sum(points for player, points in self.points_by_player)
class TestGetTeamPoints(TestCase):
pickford_id, shaw_id, maguire_id, mount_id, kane_id = (
PlayerId(i) for i in (
204597, 213442, 204614, 204615, 204617,
)
)
phillips_id = PlayerId(99999) # ???
pickford = GoalKeeper(
p_id=pickford_id, full_name=PlayerName('Jordan Pickford'),
)
shaw = Defender(
p_id=shaw_id, full_name=PlayerName('Luke Shaw'),
)
team1 = Team(
club=Club('ENG'),
captain=pickford,
vice_captain=shaw,
players=(
pickford, shaw,
Defender(p_id=maguire_id, full_name=PlayerName('Harry Maguire')),
Midfielder(p_id=mount_id, full_name=PlayerName('Mason Mount')),
Forward(p_id=kane_id, full_name=PlayerName('Harry Kane')),
),
)
def test_won_game_with_cleansheet(self) -> None:
team_result1 = TeamGame(
team=self.team1,
goals_for=1,
goals_against=0,
saves=3,
scored_goals=[self.kane_id],
made_assist=[self.phillips_id],
played60={
self.pickford_id, self.shaw_id, self.maguire_id, self.kane_id, self.phillips_id,
},
finished_game={
self.pickford_id, self.shaw_id, self.maguire_id, self.kane_id, self.phillips_id, self.mount_id,
},
got_booked=set(),
made_shots_on_tg=[
self.kane_id, self.kane_id, self.mount_id, self.kane_id,
],
)
# self.assertAlmostEqual(team_result1.points, Points(44.15))
team_result1.points
def test_won_game_with_conceded_goal(self) -> None:
team_result2 = TeamGame(
team=self.team1,
goals_for=2,
goals_against=1,
scored_goals=[self.mount_id],
made_assist=[self.shaw_id],
played60={self.pickford_id, self.shaw_id, self.maguire_id, self.phillips_id, self.mount_id, self.kane_id},
finished_game={self.pickford_id, self.shaw_id, self.maguire_id},
got_booked={self.pickford_id},
made_shots_on_tg=[self.kane_id, self.mount_id, self.mount_id, self.kane_id],
saves=2,
)
# self.assertAlmostEqual(team_result2.points, Points(25.65))
team_result2.points
def test_lost_game_with_no_goals_scored(self) -> None:
team_result3 = TeamGame(
team=self.team1,
goals_for=0,
goals_against=2,
scored_goals=[],
made_assist=[],
played60={self.pickford_id, self.shaw_id, self.maguire_id, self.phillips_id, self.kane_id},
finished_game={self.pickford_id, self.shaw_id, self.maguire_id, self.phillips_id, self.kane_id},
got_booked={self.shaw_id, self.mount_id},
made_shots_on_tg=[self.kane_id],
saves=2,
)
# self.assertAlmostEqual(team_result3.points, Points(7.45))
team_result3.points
if __name__ == '__main__':
unittest.main()
Хотя это действительно выходит за рамки вашего вопроса, учитывая ваши приоритеты, вам вообще не следует использовать генераторы или классы. Это пример, который должен помочь вам начать путь к векторизации; это не совсем то же самое, что и вы, потому что в некоторых местах у вас есть кусочные операции и разделение полов. Чем меньше вы этого сделаете, тем лучше.
positions = np.array(
(
# Goalkeep defender midfield forward
(-1.0, -1.0, -1.0, -1.0), # yellow-card booked
(-0.5, -0.5, 0.0, 0.0), # goals-against
( 0.0, 0.0, 1.0, 1.0), # finished game
( 0.0, 6-0.6, 5-0.4, 4-0.4), # goals, subtracting shot coefficient
( 0.5, 0.0, 0.0, 0.0), # saves
( 0.0, 3.0, 3.0, 3.0), # assists
( 0.0, 0.6, 0.4, 0.4), # shots
)
)
players = np.array(
(
# pickford shaw maguire mount kane
(1.0, 0.0, 0.0, 0.0, 0.0), # goalkeep
(0.0, 1.0, 1.0, 0.0, 0.0), # defender
(0.0, 0.0, 0.0, 1.0, 0.0), # midfield
(0.0, 0.0, 0.0, 0.0, 1.0), # forward
)
)
result2 = np.array(
(
# pickford shaw maguire mount kane
(1, 0, 0, 0, 0), # yellow-card booked
(1, 1, 1, 1, 1), # goals against (whole team, broadcast)
(1, 1, 1, 0, 0), # finished game
(0, 0, 0, 1, 0), # goals
(2, 2, 2, 2, 2), # saves (whole team, broadcast)
(0, 1, 0, 0, 0), # assists
(0, 0, 0, 2, 2), # shots
)
)
impact = 0.3
played60 = 2
captain = np.array((2, 1.5, 1, 1, 1))
points = (positions @ players) * result2
player_points = captain*(np.sum(points, axis=0) + impact + played60)
game_points = np.sum(player_points)

Спасибо за обзор! 1.
clubявляется собственностью игрока, потому что фэнтезийная команда может состоять из игроков из разных клубов; 2. У меня было капитанское званиеEnumв другой версии этой программы, хотя это не является серьезной проблемой; 3. Я использовал мутацию на месте вapply_captaincyчтобы сохранить некоторые вызовы функций и использовать его как метод класса в другой версии; 4. То же самое и с «points_factory», просто попытался сэкономить некоторые накладные расходы на вызов функции; 5.test_points.pyтолько для демонстрационных целей;– Konstantin Kostanzhoglo
6.
scoring.played60на будущее, пока можно оставить; 7. Многие игроки отсутствуют, потому что я создал только одну команду для демонстрационных целей.– Konstantin Kostanzhoglo
Если вы настолько заботитесь о микрооптимизации, что накладные расходы на вызов функций являются проблемой, вы используете совершенно неправильный стек и хотели бы перейти к numpy.
— Райндериен
Я собираюсь предположить, что это преждевременная оптимизация.
— Райндериен
На самом деле это не так, я успешно использую это в течение нескольких месяцев, тем не менее, я хотел бы сделать это быстрее, чтобы запускать более крупные симуляции в течение нескольких минут, а не в течение часа или двух.
– Konstantin Kostanzhoglo
Показать 2 больше комментариев