сделать запрет на создание атрибута класа вне конструктора класа

class clas():
    def __init__(self):
        a=1
        b=2
        c=3
claz=clas()
claz.d=500
print(claz.d)

как можно запретить создание атрибута извне ? чтобы нельзя было сделать атрибут d из данного примера


Ответы (5 шт):

Автор решения: Sergey Gornostaev

Определить слоты

class clas:
    __slots__ = ('a', 'b', 'c')

    def __init__(self):
        self.a=1
        self.b=2
        self.c=3
→ Ссылка
Автор решения: Spatz

Для полноты следует добавить, что помимо варианта со __slots__ в версии 3.7+ появилась возможность создавать Data-классы с атрибутом frozen:

from dataclasses import dataclass

@dataclass(frozen=True)
class Point:
    x: float
    y: float

a = Point(10.0, 20.0)
a.z = 30.0 # dataclasses.FrozenInstanceError: cannot assign to field 'z'
→ Ссылка
Автор решения: vadim vaduxa

Если требуется более сложная обработка запрета, например по условию - запретить присвоение только положительных чисел, то можно воспользоваться Getters and Setters

class A:
    def __init__(self):
        self.__x = 1

    @property
    def x(self):
        return self.__x

    @x.setter
    def x(self, x):
        if x:
            raise UserWarning('запрещено')
        else:
            self.__x = x

a = A()
print(a.x)  # 1
a.x = -2
print(a.x)  # -2
a.x = 2  # UserWarning: запрещено
→ Ссылка
Автор решения: Yahya

Через setattr

class clas:
    def __init__(self):
        self.a=1
        self.b=2
        self.c=3
    
    def __setattr__(self, key, value):
        if key == 'd':
            return None
        super().__setattr__(key, value)
→ Ссылка
Автор решения: Андрей Чередниченко

Все гораздо проще. Нужно сделать запрет на установку атрибутов на уровне класса, а при инициализации устанавливать атрибуты через главный объект:

class clas():
def __init__(self):
    object.__setattr__(self, 'a', 1)
    object.__setattr__(self, 'b', 2)
    object.__setattr__(self, 'c', 3)

def __setattr__(self, name, value):
    if hasattr(self, name):
        raise AttributeError('Изменение значения атрибута невозможно') 
    else:
        raise AttributeError('Установка нового атрибута невозможна') 

Теперь при инициализации класса атрибут будет задаваться на более верхнем уровне, минуя запрет классового сеттера, а при попытке задать новый атрибут извне, будет вызван классовый сеттер, который выдаст ошибку

→ Ссылка