← Назад к вопросам
Чем класс-метод отличается от обычного метода?
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("Новый пост")) # Статический метод
Выводы
- Обычный метод (
self) — для работы с конкретным объектом - Метод класса (
cls) — для работы с классом и создания альтернативных конструкторов - Статический метод — для вспомогательных функций
- Выбор правильного типа делает код понятнее и правильнее