Почему это возможно?Python не придерживается парадигмы ограничительного программирования, а это означает, что если что-то может иметь смысл в каком-либо сценарии, интерпретатор не должен стоять на пути программиста, желающего это сделать.
При этом требуетсяболее высокий уровень дисциплины и ответственности на стороне программиста, но также обеспечивает большую степень гибкости в его возможностях метапрограммирования.
Итак, в конце концов, это выбор дизайна.Преимущество этого состоит в том, что вам не нужно явно использовать геттеры / сеттеры.
Для защищенных / закрытых членов / методов обычно добавляется _
или __
соответственно.Кроме того, можно было бы подделать защищенное от геттера / установщика поведение (которое также позволило бы выполнять дополнительный код) через декораторы методов @property
и @.setter
, например:
class MyClass():
_an_attribute = False
@property
def an_attribute(self):
return self._an_attribute
@an_attribute.setter
def an_attribute(self, value):
self._an_attribute = value
Это можно использовать следующим образом:
x = MyClass()
x.an_attribute
# False
x.an_attribute = 1
# sets the internal `_an_attribute` to 1.
x.an_attribute
# 1
и вы можете опустить часть @an_attribute.setter
, если вы хотите свойство только для чтения (своего рода),так что следующий код:
x = MyClass()
x.an_attribute
# False
, но попытка изменить его значение приведет к:
x.an_attribute = 1
AttributeError: невозможно установить атрибут
Конечно, вы все еще можете сделать:
x._an_attribute = 2
x.an_attribute
# 2
( РЕДАКТИРОВАТЬ: добавили еще немного кода, чтобы лучше показать использование )
РЕДАКТИРОВАТЬ: На патч обезьяны
Кроме того, в вашем коде вы также изменяете класс после его определения, и изменения имеют ретроспективный (своего рода) эффект.Это обычно называется monkey patching и может быть снова полезно в некоторых сценариях, когда вы хотите вызвать определенное поведение в некоторой части кода, сохраняя большую часть его логики, например:
class Number():
value = '0'
def numerify(self):
return float(self.value)
x = Number()
x.numerify()
# 0.0
Number.numerify = lambda self: int(self.value)
x.numerify()
# 0
Но это, конечно, не рекомендуемый стиль программирования, если доступны более чистые опции.