Язык программирования Python

Как подсчитать общее количество вызовов метода класса в Python?

Представьте, что в игре есть класс “Spaceship”, в котором у игроков есть возможность, среди прочего, изменить название корабля после его создания:

class Spaceship: def __init__(self, name, capitan): self.name = name self.capitan = capitan def print_data(self): data = { 'name': self.name, 'capitan': self.capitan } print data def rename(self, name): self.name = name ship = Spaceship('Звезда смерти', 'Цеситар') ship.rename('Тысячелетний сокол') ship.print_data() # Результат {'name': 'Звезда смерти', 'capitan': 'Цеситар'} {'name': 'Тысячелетний сокол', 'capitan': 'Цеситар'}

Если бы я хотел узнать, сколько раз менялось название корабля, я мог бы добавить счетчик:

class Spaceship: def __init__(self, name, capitan): self.name = name self.capitan = capitan self.total_renames = 0 def print_data(self): data = { 'name': self.name, 'capitan': self.capitan, 'total_renames': self.total_renames } print data def rename(self, name): self.name = name self.total_renames += 1 ship = Spaceship('Звезда смерти', 'Цеситар') ship.print_data() ship.rename('Тысячелетний сокол') ship.print_data() # Результат {'name': 'Звезда смерти', 'capitan': 'Цеситар', 'total_renames': 0} {'name': 'Тысячелетний сокол', 'capitan': 'Цеситар', 'total_renames': 1}

Но это поможет мне узнать, сколько раз каждый экземпляр класса, т.е. каждый корабль, был переименован:

ship = Spaceship('Звезда смерти', 'Цеситар') ship.print_data() ship.rename('Тысячелетний сокол') ship.print_data() ship = Spaceship('USS Enterprise', 'Фьерелла') ship.print_data() ship.rename('Центавра') ship.print_data() ship.rename('Челенджер') ship.print_data() # Результат {'name': 'Звезда смерти', 'capitan': 'Цеситар', 'total_renames': 0} {'name': 'Тысячелетний сокол', 'capitan': 'Цеситар', 'total_renames': 1} {'name': 'Энтерпрайз', 'capitan': 'Фьерелла', 'total_renames': 0} {'name': 'Центавра', 'capitan': 'Фьерелла', 'total_renames': 1} {'name': 'Челенджер', 'capitan': 'Фьерелла', 'total_renames': 2}
Code language: PHP (php)

Мне нужно подсчитать общее количество вызовов метода класса, а не общее количество вызовов для каждого экземпляра. Я знаю, что одним из способов может быть накопление всех кораблей и сложение атрибута total_renames каждого из них:

ships = [ship1, ship2, ship3] total = sum([ship.total_renames for ship in ships])

Но я хочу знать, можно ли сделать это на уровне класса, как некую постоянную переменную на время жизни игры. Есть ли способ сделать это?

Примечание: на данный момент я хочу сохранить простоту и не использовать базы данных.

Ответ.

Лучший способ реализовать это, на мой взгляд, это декоратор, который обрабатывает статическую переменную ( добавляю комментарии ко всем методам):

# -*- coding: utf-8 -*- class Spaceship: total_renames = 0 def __init__(self, name, capitan): self.name = name self.capitan = capitan def print_data(self): data = { 'name': self.name, 'capitan': self.capitan, 'total_renames': Spaceship.total_renames } print data def _dec_increases_renames(func): """ Это функция-декоратор, которая отвечает за вызов метода класса _increases_counter_renames. Инкремент не работает, если делать его внутри функции "internal". Последний должен вызывать метод класса. """ def internal(cls, *args, **kwargs): result = func(cls, *args, **kwargs) cls._increases_counter_renames() return result return internal @_dec_increases_renames def rename(self, name): """Метод декорирован с увеличением счетчика.""" self.name = name @classmethod def _increases_counter_renames(cls): """ Это метод класса, который только увеличивает статический счетчик. """ cls.total_renames += 1 ship = Spaceship('Звезда смерти', 'Цесистар') ship.print_data() ship.rename('Тысячелетний сокол') ship.print_data() ship = Spaceship('Энтерпрайз', 'Фьерелла') ship.print_data() ship.rename('Центавра') ship.print_data() ship.rename('Челенджер') ship.print_data()

Вывод этого кода соответствует требованиям:

{'name': 'Звезда смерти', 'capitan': 'Цесистар', 'total_renames': 0} {'name': 'Тысячелетний сокол', 'capitan': 'Цесистар', 'total_renames': 1} {'name': 'Энтерпрайз', 'capitan': 'Фьерелла', 'total_renames': 1} {'name': 'Центавра', 'capitan': 'Фьерелла', 'total_renames': 2} {'name': 'Челенджер', 'capitan': 'Фьерелла', 'total_renames': 3}
Code language: JavaScript (javascript)

Поэтому рекомендуются следующие шаги:

  1. Добавьте статическую переменную с начальным значением 0.
  2. Реализуйте метод класса, который при вызове только увеличивает статическую переменную с предыдущего значения.
  3. Реализуйте метод-декоратор, внутренняя функция которого просто вызывает метод класса из предыдущего пункта.
    • Увеличение счетчика в этой внутренней функции не работает.
  4. Используйте вышеупомянутый декоратор для декорирования функции, вызовы которой мы хотим подсчитать.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *