Python, разрешающий доступ к неопределенной переменной класса/экземпляра
Я определил простой/пустой класс Python, как показано ниже. Теперь, если я устанавливаю значение для неопределенной переменной либо с помощью переменной экземпляра, либо с именем класса, Python свободно позволяет мне устанавливать значение для неопределенной переменной, а также позволяет мне получить к ней доступ как к переменной экземпляра или класса без каких-либо ошибок. Итак, в двух словах, я могу без проблем установить неопределенные переменные экземпляра и класса.
Как мы можем запретить пользователям устанавливать неопределенные переменные экземпляра и класса в Python.
Вот как Python обрабатывает эти неопределенные переменные (undefined_variable_1
и undefined_variable_2
)? Обрабатываются ли они как переменная экземпляра или переменная класса или что-то еще?
class Test:
pass
### #Now instantiate the class and try setting & it accessing undefined variables
t1 = Test()
t1.undefined_variable_1 = "Undefined class/instance variable being set through instance variable (t1)"
### #Access the undefined variable through instance variable
print(t1.undefined_variable_1)
Test.undefined_variable_2 = "Undefined class/instance variable being set through Class name (Test)"
### #Access the undefined variable through Class name
print(Test.undefined_variable_2)
Как мы можем ограничить пользователя от установки/доступа к неопределенной переменной экземпляра/экземпляра?
Вот как это всегда работает в Python. переменные, в данном случае атрибуты, не существуют пока вы не назначите им
@juanpa.arrivillaga Я подозреваю, что они действительно хотят, чтобы код вне класса не создавал новые атрибуты.
@juanpa.arrivillaga - поведение такое же, даже если я инициализирую другие атрибуты экземпляра с помощью метода __init__() и устанавливаю неопределенные переменные, как в моем примере. Если Python позволяет нам использовать неопределенные атрибуты w.r.t. пользовательский класс, то как он поддерживает инкапсуляцию? Пожалуйста, уточните.
@VivekN Python построен на философии, согласно которой мы все здесь взрослые люди по обоюдному согласию. Вы не мешаете людям делать потенциально страшные вещи; вы сообщаете им ситуации, с которыми должен справиться ваш класс, и если они захотят копаться в его внутренностях и, возможно, вызвать хаос, это их дело. Даже метод __slots__
, о котором я упоминал в своем ответе, имеет основную цель экономия памяти.
@VivekN __init__
не имеет особого статуса. Работает точно так же в __init__
. Если под «инкапсуляцией» вы подразумеваете модификаторы доступа, Python не поддерживает это. Конечно, он поддерживает инкапсуляцию в более широком смысле «объединения данных с операциями, которые работают с этими данными».
@Barmar Бармар, ну, вероятно, нет способа сделать то, что не перегружено и, вероятно, в любом случае будет легко ниспровергнуто.
@juanpa.arrivillaga А как насчет решения __slots__
в ответе? Кажется, это именно то, о чем просил ОП. Его можно было бы отменить, но он должен предотвращать непреднамеренное создание атрибута.
@Barmar, которого вы все еще можете назначать вне класса с помощью __slots__
. Я склонен использовать слоты для предотвращения ошибок случайный, например obj.mt_var = <something>
вместо obj.my_var = <something>
, хотя с тех пор, как я начал использовать mypy
, мне это не нужно. Как правило, я просто избегаю интерфейсов, которые требуют от вас этого в первую очередь. Так что my_obj.attribute = whatever
всегда выглядит неправильно :)
Значит ответ неверный? Обычно целью такого рода вещей является обнаружение опечаток, а не предотвращение преднамеренного кода.
@Barmar Бармар Я бы сказал, что вопрос плохо определен. Я вижу, как ваша интерпретация имеет смысл, но в ее нынешнем виде вопрос расплывчатый.
@ juanpa.arrivillaga - ответ от Бармара полезен. Между тем я не уверен, что неясно в вопросе, как показано ниже? Как мы можем запретить пользователям устанавливать неопределенные переменные экземпляра и класса в Python. Как Python обрабатывает эти неопределенные переменные (undefined_variable_1 и undefined_variable_2)? Обрабатываются ли они как переменная экземпляра или переменная класса или что-то еще?
@Vivek.N, потому что в Python вы всегда устанавливаете атрибут, который не определен. Вы должны иметь в виду что-то вроде «как предотвратить установку атрибута, который не определен в операторе определения класса» или «как предотвратить установку атрибута за пределами указанного диапазона имен». Потому что, опять же, переменные (атрибуты) делают не существует, пока они не назначены. В Python нет объявлений переменных.
Для этого вы можете установить __slots__
, который ограничивает атрибуты, которые может иметь экземпляр класса:
class Restricted:
__slots__ = ('a', 'b')
r = Restricted()
r.a = 1 # okay
r.b = 2 # okay
r.c = 3 # error
Если вы хотите иметь ту же функциональность для объект класса, вы можете создать собственный метакласс и переопределить __setattr__
:
class RestrictedMeta(type):
def __setattr__(self, attr, value):
if attr in ('a', 'b'):
super().__setattr__(attr, value)
else:
raise TypeError(f"Can't assign to attribute '{attr}' of class 'Restricted'")
class Restricted(metaclass=RestrictedMeta):
pass
Restricted.a = 1 # okay
Restricted.b = 2 # okay
Restricted.c = 3 # error
@VivekN Да, я отметил это в своем ответе. Для этого вам нужен собственный метакласс, пример которого я привел.
Можете ли вы сделать шаг назад и объяснить, почему вы хотите это сделать? В чем проблема?