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

Как создать переменную класса?

1.3 Junior🔥 181 комментариев
#Python Core

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

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

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

Как создать переменную класса в Python

Переменные класса — это атрибуты, которые существуют на уровне класса и общие для всех экземпляров. Вот полное руководство.

Основное определение

# Переменная класса определяется прямо в теле класса
class Car:
    # Переменная класса (общая для всех экземпляров)
    wheels = 4
    manufacturer = "Unknown"
    
    def __init__(self, color):
        # Переменная экземпляра (своя для каждого экземпляра)
        self.color = color

# Доступ к переменной класса
print(Car.wheels)  # 4 (через класс)

car1 = Car("red")
print(car1.wheels)  # 4 (через экземпляр)

car2 = Car("blue")
print(car2.wheels)  # 4 (у обоих одинаково)
print(car2.color)   # "blue" (разные экземпляры)

Разница между переменными класса и экземпляра

class Student:
    # Переменная класса
    school_name = "Public School"
    total_students = 0  # Считаем количество студентов
    
    def __init__(self, name):
        # Переменная экземпляра
        self.name = name
        Student.total_students += 1  # Инкрементируем счётчик класса

# Создаём студентов
student1 = Student("Alice")
student2 = Student("Bob")
student3 = Student("Charlie")

print(Student.total_students)  # 3
print(Student.school_name)     # "Public School"

print(student1.name)           # "Alice" — переменная экземпляра
print(student1.school_name)    # "Public School" — переменная класса

Важное правило: изменение переменной класса

class Config:
    debug = False  # Переменная класса

print(Config.debug)  # False

# ⚠️ ОСТОРОЖНО: различие между чтением и записью

# 1. ЧТЕНИЕ переменной класса через экземпляр (OK)
config = Config()
print(config.debug)  # False (берёт из класса)

# 2. ЗАПИСЬ через экземпляр создаёт переменную ЭКЗЕМПЛЯРА!
config.debug = True  # Это НЕ меняет класс
print(config.debug)  # True (у экземпляра)
print(Config.debug)  # False (в классе осталось прежнее)
print(config.__dict__)  # {'debug': True} — собственная переменная

# 3. ЗАПИСЬ через класс меняет для всех
Config.debug = True
print(Config.debug)  # True
config2 = Config()
print(config2.debug)  # True (новые экземпляры получат новое значение)

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

Пример 1: Счётчик экземпляров

class Book:
    total_books = 0  # Переменная класса
    
    def __init__(self, title, author):
        self.title = title
        self.author = author
        Book.total_books += 1  # Увеличить счётчик
    
    @classmethod
    def get_total_books(cls):
        return cls.total_books

book1 = Book("1984", "Orwell")
book2 = Book("Brave New World", "Huxley")
book3 = Book("Fahrenheit 451", "Bradbury")

print(Book.get_total_books())  # 3
print(Book.total_books)        # 3

Пример 2: Конфигурация приложения

class Database:
    # Переменные класса — конфигурация
    host = "localhost"
    port = 5432
    database_name = "mydb"
    connections = []  # Список всех подключений
    
    def __init__(self, user, password):
        self.user = user  # Переменная экземпляра
        self.password = password
        self.connection_id = len(Database.connections) + 1
        Database.connections.append(self.connection_id)
    
    def get_connection_string(self):
        return f"postgresql://{self.user}@{Database.host}:{Database.port}/{Database.database_name}"

db1 = Database("admin", "secret1")
db2 = Database("user", "secret2")

print(Database.connections)  # [1, 2]
print(db1.get_connection_string())
# postgresql://admin@localhost:5432/mydb

Пример 3: Версионирование класса

class APIClient:
    version = "1.0.0"
    api_key = None
    
    def __init__(self, endpoint):
        self.endpoint = endpoint  # Переменная экземпляра
    
    @classmethod
    def set_api_key(cls, key):
        """Установить API ключ для всех экземпляров"""
        cls.api_key = key
    
    @classmethod
    def get_version(cls):
        return cls.version

# Установить глобальный API ключ
APIClient.set_api_key("sk-1234567890")

# Все экземпляры используют один API ключ
client1 = APIClient("https://api.example.com")
client2 = APIClient("https://api2.example.com")

print(client1.api_key)  # "sk-1234567890"
print(client2.api_key)  # "sk-1234567890" (общий)
print(APIClient.version)  # "1.0.0"

Методы класса (classmethod) vs переменные класса

class User:
    # Переменная класса
    user_count = 0
    
    def __init__(self, name):
        self.name = name
        User.user_count += 1
    
    # Метод класса — может работать с переменными класса
    @classmethod
    def get_user_count(cls):
        """Получить количество созданных пользователей"""
        return cls.user_count
    
    @classmethod
    def create_from_dict(cls, data):
        """Альтернативный конструктор"""
        return cls(data['name'])

user1 = User("Alice")
user2 = User("Bob")

print(User.get_user_count())  # 2 — метод класса읽ает переменную класса
print(User.user_count)  # 2 — прямой доступ

Мутируемые переменные класса (опасно!)

# ❌ ОПАСНО: изменяемые объекты как переменные класса
class BadDesign:
    items = []  # Изменяемый объект!
    
    def __init__(self, name):
        self.name = name
        BadDesign.items.append(name)  # Изменяем список класса

obj1 = BadDesign("item1")
obj2 = BadDesign("item2")

print(BadDesign.items)  # ["item1", "item2"] — список КЛАССА
print(obj1.items is BadDesign.items)  # True — они один и тот же!

# Это может привести к неожиданным ошибкам

# ✅ ПРАВИЛЬНО: переменные экземпляра для изменяемых объектов
class GoodDesign:
    def __init__(self, name):
        self.name = name
        self.items = []  # Переменная экземпляра — своя для каждого

obj1 = GoodDesign("item1")
obj2 = GoodDesign("item2")

obj1.items.append("a")
obj2.items.append("b")

print(obj1.items)  # ["a"] — своя
print(obj2.items)  # ["b"] — своя
print(obj1.items is obj2.items)  # False — разные

Статические методы vs переменные класса

class Math:
    # Переменная класса
    PI = 3.14159
    
    @staticmethod
    def circle_area(radius):
        """Статический метод — не использует состояние класса"""
        return Math.PI * radius ** 2
    
    @classmethod
    def get_constant(cls):
        """Метод класса — может использовать переменные класса"""
        return cls.PI

print(Math.circle_area(5))  # 78.53975
print(Math.get_constant())  # 3.14159

Доступ через dict

class Example:
    class_var = "class"
    
    def __init__(self):
        self.instance_var = "instance"

obj = Example()

# Переменные класса находятся в __dict__ класса
print(Example.__dict__.keys())
# dict_keys(['__module__', '__doc__', 'class_var', '__init__', '__dict__', '__weakref__'])

# Переменные экземпляра находятся в __dict__ экземпляра
print(obj.__dict__)
# {'instance_var': 'instance'}

# Но Python сначала ищет в экземпляре, потом в классе
print(obj.class_var)  # "class" (найдётся в классе)
print(obj.instance_var)  # "instance" (найдётся в экземпляре)

Type hints для переменных класса

from typing import ClassVar, List

class TypedExample:
    # Обозначение переменной класса с типом
    version: ClassVar[str] = "1.0.0"
    registry: ClassVar[List[str]] = []
    
    def __init__(self, name: str):
        self.name: str = name  # Переменная экземпляра

# IDE и type checker понимают, что это переменная класса
print(TypedExample.version)
print(TypedExample.registry)

Итоговые рекомендации

Используй переменные класса для:

  • Констант (версия, константы, конфигурация)
  • Счётчиков (количество экземпляров)
  • Регистров (список всех объектов)
  • Конфигурации приложения

Не используй переменные класса для:

  • Изменяемых объектов (списков, словарей)
  • Данных, уникальных для экземпляра
  • Состояния экземпляра

Правила:

  1. Определи переменную класса прямо в теле класса
  2. Обращайся через класс: ClassName.variable
  3. Для изменяемых данных используй переменные экземпляра
  4. Используй @classmethod для методов, работающих с переменными класса
  5. Используй ClassVar в type hints для явности