Найдётся несколько простых способов — самый прямой и универсальный — переопределить метод __delattr__ в вашем классе. Когда кто‑то выполняет del obj.attr (или del Class.attr для атрибутов класса), Python вызывает obj.__delattr__('attr') (или метакласс.__delattr__ для удаления атрибута класса). Поэтому можно просто бросать исключение.
Примеры.
1) Запретить удаление любых атрибутов экземпляра:
```python
class Foo(BaseModel):
def __delattr__(self, name):
raise AttributeError("Удаление атрибутов запрещено")
```
2) Разрешить удалять только «внутренние» атрибуты (начинающиеся с "_"):
```python
class Foo(BaseModel):
def __delattr__(self, name):
if name.startswith("_"):
super().__delattr__(name) # или object.__delattr__(self, name)
else:
raise AttributeError("Удаление публичных атрибутов запрещено")
```
3) Разрешить удалять только некоторые поля:
```python
class Foo(BaseModel):
_allowed_to_delete = {"temp", "cache"}
def __delattr__(self, name):
if name in self._allowed_to_delete:
super().__delattr__(name)
else:
raise AttributeError(f"Удаление поля {name!r} запрещено")
```
4) Запретить удаление атрибутов класса (del Foo.attr) — через метакласс:
```python
class NoDelMeta(type):
def __delattr__(cls, name):
raise AttributeError("Удаление атрибутов класса запрещено")
class Foo(BaseModel, metaclass=NoDelMeta):
x = 1
```
Альтернативы и замечания:
- Если хотите только запретить del для отдельных свойств, можно использовать @property без deleter: del obj.prop вызовет AttributeError.
- Для Pydantic BaseModel обычно можно безопасно переопределять __delattr__, но если вам нужно сохранить специфичную логику BaseModel — вызывайте super().__delattr__(name) там, где хотите действительно удалить.
- Помните, что прямой вызов object.__delattr__(obj, name) (если кто‑то захочет обходить защиту) может обойти ваш код, но это экзотический вариант; обычный del будет вызывать ваш __delattr__.
Если покажете конкретный код (какие поля, требуется ли разрешать удаление некоторых из них, используете ли Pydantic и т.д.), подскажу точнее.