Почему переменная класса доступна снаружи - PullRequest
0 голосов
/ 06 февраля 2019

Изучение Python Я только что столкнулся с чем-то, чего я не очень понимаю.Давайте возьмем этот пример:

class CV_Test:
    classVar = 'First'

cv = CV_Test()
print(cv.classVar)
CV_Test.classVar = 'Second'
cv2 = CV_Test()
print(cv2.classVar)
print(CV_Test.classVar)

Вывод:

First
Second
Second

Может кто-нибудь сказать мне, почему это возможно и для чего это хорошо?Разве это не противоречит определению класса как плана, если я могу изменить, может быть, важные значения внутри класса извне, и не является ли это конфликтом парадигмы OOP из encapsulation.Исходя из .NET Я на самом деле просто знаю доступ к переменным через геттер и сеттер, но не просто так.Поэтому мне любопытно, какая важная цель может быть в том, чтобы это было разрешено.

1 Ответ

0 голосов
/ 06 февраля 2019

Почему это возможно?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

Но это, конечно, не рекомендуемый стиль программирования, если доступны более чистые опции.

...