Я пишу класс с пользовательскими методами __eq__ и __hash__, и __hash__ по сути возвращает один из атрибутов класса (который является целым числом). Поэтому мне нужно сделать этот атрибут максимально неизменяемым. Есть ли способ сделать атрибут неизменяемым в Python?
Могу, конечно, успеть __private, но это не совсем то. Кроме того, на данный момент я не уверен, следует ли мне сделать мой класс классом данных.
Дополнительный контекст, если это как-то актуально: класс Simplex представляет комбинаторный симплекс и хранит набор вершин (в форме двоичного числа) и целочисленный коэффициент. В классе есть метод boundary(), который должен возвращать объект типа Complex, представляющий собой коллекцию экземпляров Simplex. Метод __eq__ думает A == B, совпадают ли их множества вершин (коэффициенты не имеют значения). Метод __hash__ возвращает двоичные вершины хранения. Я хочу, чтобы __hash__ работал именно таким образом, потому что думаю, что это упростит сложение равных симплексов в Complex.






Попробуйте использовать собственный декоратор class_property.
Что-то вроде (копия из этого поста https://stackoverflow.com/a/5191224/24285005):
class ClassPropertyDescriptor(object):
def __init__(self, fget, fset=None):
self.fget = fget
self.fset = fset
def __get__(self, obj, klass=None):
if klass is None:
klass = type(obj)
return self.fget.__get__(obj, klass)()
def classproperty(func):
if not isinstance(func, (classmethod, staticmethod)):
func = classmethod(func)
return ClassPropertyDescriptor(func)
class Bar(object):
@classproperty
def bar(cls):
return 1
Фрэнк Йеллин совершенно прав, говоря, что в Python нет настоящих частных переменных.
Однако в Python есть возможность изменить способ доступа к атрибутам и их редактирования. Это можно использовать для изменения способа взаимодействия класса с окружающим кодом, например, добавление проверки — одна из основных причин, по которой вы можете захотеть, чтобы атрибут был закрытым.
Ниже приведен пример, как реализовать это с помощью геттера @property и сеттера @brand.setter декоратора.
class GermanCar:
def __init__(self, model, brand):
self.model = model
self.brand = brand
def __str__(self):
return f"The car brand is {self.brand} and the model is {self.model}"
@property
def brand(self):
return self._brand
@brand.setter
def brand(self, brand):
print(brand)
if brand not in {"BMW", "Mercedes", "Volkswagen"}:
raise ValueError(f"This class only allows German car brands, {brand} isn't.")
self._brand = brand
def build_car():
brand = input("Brand: ")
model = input("Model: ")
return GermanCar(model, brand)
car = build_car()
print(car)
Преимущество вышеизложенного заключается в том, что атрибут, с которым пользователи будут взаимодействовать car.brand, отделен от атрибута, который используется для хранения значения car._brand, тем самым снижая риски случайных изменений.
Если вы поиграетесь с этим кодом, вы заметите, что его нельзя изменить car.brand без использования функции установки, в которой вы можете добавить любую проверку (включая полный запрет редактирования).
Однако это не делает ее действительно неизменяемой переменной, а просто еще одним уровнем безопасности. Если кто-то действительно намеревается взломать ваш код и хочет обойти проверку, он может просто отредактировать car._brand напрямую, минуя проверку.
Вот почему существует соглашение об именах _private, даже если это всего лишь предупреждающий знак, который люди могут игнорировать. Однако вышеизложенное может предотвратить большинство непреднамеренных изменений.
Простой ответ: «нет». Рекомендуемый метод скрыть что-либо —
__private. Но в Python на самом деле нет такого понятия, как переменнаяprivate, поэтому человек, запускающий программу, всегда может копать где угодно.