← Назад к вопросам

Чем класс-метод отличается от обычного метода?

2.0 Middle🔥 191 комментариев
#REST API и HTTP

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между методом класса и обычным методом

Это важное различие в Python, которое влияет на то, как метод получает доступ к данным. Разберу подробно.

Основные различия

Обычный метод (instance method):

  • Получает первый параметр self — экземпляр класса
  • Работает с данными конкретного объекта
  • Может читать и менять атрибуты объекта
  • Требует создания экземпляра класса для вызова

Метод класса (class method):

  • Получает первый параметр cls — сам класс
  • Работает с данными класса, а не объекта
  • Может читать и менять атрибуты класса
  • Можно вызвать без создания объекта
  • Помечается декоратором @classmethod

Практические примеры

class Counter:
    instances_created = 0  # Атрибут класса
    
    def __init__(self, name):
        self.name = name  # Атрибут объекта
        Counter.instances_created += 1
    
    # Обычный метод
    def get_name(self):
        return self.name
    
    # Метод класса
    @classmethod
    def get_total_instances(cls):
        return cls.instances_created
    
    # Другой метод класса
    @classmethod
    def from_string(cls, string):
        """Альтернативный конструктор"""
        name = string.split("-")[0]
        return cls(name)

# Использование обычного метода
counter1 = Counter("первый")
counter2 = Counter("второй")

print(counter1.get_name())  # "первый"
print(counter2.get_name())  # "второй"

# Использование метода класса
print(Counter.get_total_instances())  # 2 (вызов через класс)
print(counter1.get_total_instances())  # 2 (можно вызвать через объект)

# Использование альтернативного конструктора
counter3 = Counter.from_string("третий-код")
print(counter3.name)  # "третий"
print(Counter.get_total_instances())  # 3

Важные отличия в деталях

В обычном методе доступ к атрибутам:

class User:
    company = "TechCorp"  # Атрибут класса
    
    def __init__(self, name):
        self.name = name  # Атрибут объекта
        self.role = "Developer"  # Атрибут объекта
    
    def get_info(self):
        # self.name — берётся из объекта
        # self.company — берётся из класса (если нет в объекте)
        return f"{self.name} из {self.company}"
    
    def change_role(self, new_role):
        self.role = new_role  # Меняет только у этого объекта

user1 = User("Алиса")
user2 = User("Боб")

print(user1.get_info())  # "Алиса из TechCorp"
user1.change_role("Manager")
print(user1.role)  # "Manager"
print(user2.role)  # "Developer" (не изменилась)

В методе класса доступ только к атрибутам класса:

class Database:
    connection = None  # Атрибут класса
    config = {"host": "localhost"}  # Атрибут класса
    
    def __init__(self, db_name):
        self.db_name = db_name  # Атрибут объекта
    
    @classmethod
    def set_connection(cls, connection):
        # Работает с атрибутом класса
        cls.connection = connection
        print(f"Соединение установлено: {cls.connection}")
    
    @classmethod
    def get_config(cls):
        # Возвращает конфиг класса
        return cls.config
    
    @classmethod
    def from_file(cls, filename):
        """Создаёт экземпляр, читая файл"""
        # Может создать объект
        db_name = f"db_{filename}"
        return cls(db_name)
    
    def get_my_name(self):
        # Это обычный метод — доступ к self
        return self.db_name

db1 = Database("users_db")
db2 = Database("posts_db")

# Вызов метода класса
Database.set_connection("postgresql://localhost")
print(Database.get_config())  # {"host": "localhost"}

# Вызов обычного метода
print(db1.get_my_name())  # "users_db"
print(db2.get_my_name())  # "posts_db"

# Создание через альтернативный конструктор
db3 = Database.from_file("backup.sql")
print(db3.get_my_name())  # "db_backup.sql"

Ещё есть staticmethod

Есть третий вид — статический метод, который вообще не получает ни self ни cls:

class Utils:
    @staticmethod
    def format_price(price):
        """Чистая функция, не зависит от класса"""
        return f"${price:.2f}"
    
    @classmethod
    def get_currency(cls):
        """Работает с классом"""
        return "USD"
    
    def instance_method(self):
        """Работает с объектом"""
        pass

# Все эти вызовы работают
print(Utils.format_price(99.5))  # "$99.50" (статический)
print(Utils.get_currency())  # "USD" (метод класса)

utils = Utils()
print(utils.format_price(99.5))  # "$99.50" (можно через объект)
print(utils.get_currency())  # "USD" (можно через объект)

Когда использовать каждый тип

Обычный метод (self):

  • Работаете с данными конкретного объекта
  • Нужна история/состояние объекта
  • Пример: user.get_name(), order.calculate_total()

Метод класса (cls):

  • Альтернативные конструкторы
  • Работа с данными, общими для всех объектов
  • Фабричные методы
  • Примеры: User.from_email(), logger.set_level(), Database.from_config()

Статический метод:

  • Вспомогательные функции, не зависящие от класса
  • Утилиты
  • Пример: Utils.format_date(), Math.sqrt()

Реальный пример из практики

from datetime import datetime

class BlogPost:
    total_posts = 0  # Счётчик всех постов
    
    def __init__(self, title, content):
        self.title = title
        self.content = content
        self.created_at = datetime.now()
        BlogPost.total_posts += 1
    
    # Обычный метод — работает с постом
    def get_snippet(self, length=100):
        return self.content[:length] + "..."
    
    # Метод класса — альтернативный конструктор
    @classmethod
    def from_markdown(cls, title, markdown_file):
        with open(markdown_file) as f:
            content = f.read()
        return cls(title, content)
    
    # Метод класса — статистика
    @classmethod
    def get_stats(cls):
        return {"total": cls.total_posts, "timestamp": datetime.now()}
    
    # Статический метод — утилита
    @staticmethod
    def validate_title(title):
        return len(title) > 3 and len(title) < 200

# Использование
post1 = BlogPost("Метаморфоз", "Однажды Грегор проснулся...")
post2 = BlogPost.from_markdown("README", "./readme.md")

print(post1.get_snippet())  # Обычный метод
print(BlogPost.get_stats())  # Метод класса
print(BlogPost.validate_title("Новый пост"))  # Статический метод

Выводы

  1. Обычный метод (self) — для работы с конкретным объектом
  2. Метод класса (cls) — для работы с классом и создания альтернативных конструкторов
  3. Статический метод — для вспомогательных функций
  4. Выбор правильного типа делает код понятнее и правильнее
Чем класс-метод отличается от обычного метода? | PrepBro