Есть ли у Python “приватные” переменные в классах?

StackOverflow https://stackoverflow.com/questions/1641219

  •  08-07-2019
  •  | 
  •  

Вопрос

Я пришел из мира Java и читаю книгу Брюса Экельса " Шаблоны, рецепты и идиомы Python 3.

Читая о классах, далее говорится, что в Python нет необходимости объявлять переменные экземпляра.Вы просто используете их в конструкторе, и бум, они там.

Так, например:

class Simple:
    def __init__(self, s):
        print("inside the simple constructor")
        self.s = s

    def show(self):
        print(self.s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Если это правда, то любой объект класса Simple можно просто изменить значение переменной s вне класса.

Например:

if __name__ == "__main__":
    x = Simple("constructor argument")
    x.s = "test15" # this changes the value
    x.show()
    x.showMsg("A message")

В Java нас учили о публичных / частных / защищенных переменных.Эти ключевые слова имеют смысл, потому что иногда вам нужны переменные в классе, к которым никто за пределами класса не имеет доступа.

Почему это не требуется в Python?

Это было полезно?

Решение

Это культурно. В Python вы не пишете в экземпляр класса или переменные класса. В Java ничто не мешает вам делать то же самое, если вы действительно хотите - в конце концов, вы всегда можете отредактировать исходный код самого класса для достижения того же эффекта. Python отказывается от претензий на безопасность и поощряет программистов к ответственности. На практике это работает очень хорошо.

Если по какой-то причине вы хотите эмулировать закрытые переменные, вы всегда можете использовать префикс __ из ПКП 8 . Python изменяет имена переменных, таких как __foo , так что их не легко увидеть в коде вне класса, который их содержит (хотя вы можете обойти его, если вы уверены, достаточно, точно так же, как вы можете обойти защиту Java, если работаете над этим).

В соответствии с тем же соглашением префикс _ означает, что держится подальше, даже если технически вам это не запрещено . Вы не играете с переменными другого класса, которые выглядят как __foo или _bar .

Другие советы

Закрытые переменные в python - более или менее хак: интерпретатор намеренно переименовывает переменную.

class A:
    def __init__(self):
        self.__var = 123
    def printVar(self):
        print self.__var

Теперь, если вы попытаетесь получить доступ к __ var вне определения класса, произойдет сбой:

 >>>x = A()
 >>>x.__var # this will return error: "A has no attribute __var"

 >>>x.printVar() # this gives back 123

Но вы можете легко сойти с рук:

 >>>x.__dict__ # this will show everything that is contained in object x
               # which in this case is something like {'_A__var' : 123}

 >>>x._A__var = 456 # you now know the masked name of private variables
 >>>x.printVar() # this gives back 456

Вы, вероятно, знаете, что методы в ООП вызываются так: x.printVar () = > A.printVar (x) , если A.printVar () может получить доступ к некоторому полю в x , к этому полю также можно получить доступ снаружи A.printVar () ... в конце концов, функции создаются для возможности повторного использования, и внутри операторов нет особой власти.

Игра отличается, когда задействован компилятор ( конфиденциальность - это концепция уровня компилятора ). Он знает об определении класса с помощью модификаторов контроля доступа, поэтому может выдавать ошибку, если правила не соблюдаются во время компиляции

Как правильно сказано во многих комментариях выше, давайте не будем забывать о главной цели модификаторов доступа: помочь пользователям кода понять, что должно измениться, а что нет. Когда вы видите приватное поле, вы не возитесь с ним. Так что это в основном синтаксический сахар, который легко достигается в Python с помощью _ и __.

"В java нас учили о публичных / частных / защищенных переменных"

"Почему это не требуется в python?"

По той же причине это не так требуемый на языке Java.

Вы вольны использовать - или не использовать private и protected.

Как программист на Python и Java, я обнаружил, что private и protected это очень, очень важные концепции дизайна.Но с практической точки зрения, в десятках тысяч строк Java и Python я никогда на самом деле использованный private или protected.

Почему бы и нет?

Вот мой вопрос: "защищен от кого?"

Другие программисты в моей команде?У них есть источник.Что значит защищенный, когда они могут его изменить?

Другие программисты в других командах?Они работают в одной компании.Они могут - с помощью телефонного звонка - установить источник.

Клиенты?Это программирование по найму (как правило).Клиенты (как правило) владеют кодом.

Итак, от кого именно я это защищаю?

В соглашении о подчеркивании есть несколько закрытых переменных.

In [5]: class Test(object):
   ...:     def __private_method(self):
   ...:         return "Boo"
   ...:     def public_method(self):
   ...:         return self.__private_method()
   ...:     

In [6]: x = Test()

In [7]: x.public_method()
Out[7]: 'Boo'

In [8]: x.__private_method()
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-8-fa17ce05d8bc> in <module>()
----> 1 x.__private_method()

AttributeError: 'Test' object has no attribute '__private_method'

Есть некоторые тонкие различия, но для идеологической чистоты шаблона программирования достаточно, что это хорошо.

Существуют примеры декораторов @private, которые более близко реализуют эту концепцию, но YMMV. Можно также написать определение класса, которое использует мета

Python имеет ограниченную поддержку частных идентификаторов, благодаря функции, которая автоматически добавляет имя класса к любым идентификаторам, начинающимся с двух подчеркиваний. По большей части это прозрачно для программиста, но общий эффект заключается в том, что любые переменные, названные таким образом, могут использоваться как частные переменные.

Подробнее об этом см. .

В общем, реализация объектной ориентации в Python немного примитивна по сравнению с другими языками. Но на самом деле мне это нравится. Это очень концептуально простая реализация, которая хорошо вписывается в динамический стиль языка.

Как уже упоминалось ранее, вы можете указать, что переменная или метод являются закрытыми, добавив перед ними знак подчеркивания. Если вам кажется, что этого недостаточно, вы всегда можете использовать декоратор property . Вот пример:

class Foo:

    def __init__(self, bar):
        self._bar = bar

    @property
    def bar(self):
        """Getter for '_bar'."""
        return self._bar

Таким образом, кто-то или что-то, ссылающееся на bar , фактически ссылается на возвращаемое значение функции bar , а не на саму переменную, и поэтому к нему можно получить доступ, но не изменилось. Однако, если кто-то действительно хочет, он может просто использовать _bar и присвоить ему новое значение. Не существует надежного способа запретить кому-либо доступ к переменным и методам, которые вы хотите скрыть, как уже неоднократно говорилось. Однако использование property - самое ясное сообщение о том, что переменная не подлежит редактированию. property также может использоваться для более сложных путей доступа getter / setter / deleter, как описано здесь: https://docs.python.org/3/library/functions.html#property

Единственный раз, когда я использую закрытые переменные, это когда мне нужно делать что-то другое при записи или чтении из переменной, и поэтому мне нужно принудительно использовать установщик и / или получатель.

Опять же, это идет в культуру, как уже говорилось. Я работал над проектами, где чтение и запись переменных других классов были бесплатными для всех. Когда одна реализация устарела, потребовалось намного больше времени, чтобы идентифицировать все пути кода, которые использовали эту функцию. Когда использование сеттеров и геттеров было принудительным, можно было легко написать оператор отладки, чтобы определить, что был объявлен устаревший метод, и путь к коду, который его вызывает.

Когда вы работаете над проектом, в котором каждый может написать расширение, уведомление пользователей о устаревших методах, которые должны исчезнуть в нескольких выпусках, следовательно, жизненно важно, чтобы поломка модуля была минимальной при обновлении.

Итак, мой ответ: если вы и ваши коллеги поддерживаете простой кодовый набор, тогда защита переменных класса не всегда необходима. Если вы пишете расширяемую систему, тогда становится необходимым, когда вносятся изменения в ядро, которые должны быть отслежены всеми расширениями, использующими код.

частные и защищенные концепции очень важны. Но python - всего лишь инструмент для создания прототипов и быстрой разработки с ограниченными ресурсами, доступными для разработки, поэтому некоторые уровни защиты не так строги в Python. Вы можете использовать " __ " в классе он работает правильно, но выглядит недостаточно хорошо - каждый доступ к такому полю содержит эти символы.

Кроме того, вы можете заметить, что концепция ООП Python не идеальна, смолтальк или рубин намного ближе к концепции чистого ООП. Даже C # или Java ближе.

Python - очень хороший инструмент. Но это упрощенный язык ООП. Синтаксически и концептуально упрощено. Основная цель существования Python - предоставить разработчикам возможность быстро и легко писать легко читаемый код с высоким уровнем абстракции.

Извините, ребята, за "воскрешение" нить, но, надеюсь, это кому-нибудь поможет:

В Python3, если вы просто хотите "инкапсулировать" атрибуты класса, как в Java, вы можете сделать то же самое, как это:

class Simple:
    def __init__(self, str):
        print("inside the simple constructor")
        self.__s = str

    def show(self):
        print(self.__s)

    def showMsg(self, msg):
        print(msg + ':', self.show())

Для создания экземпляра этого выполните:

ss = Simple("lol")
ss.show()

Обратите внимание: print (ss .__ s) выдаст ошибку.

На практике Python3 запутывает глобальное имя атрибута. Превращая это как "частный" атрибут, как в Java. Имя атрибута по-прежнему глобально, но недоступно, как частный атрибут в других языках.

Но не бойся этого. Это не важно Это тоже делает работу. ;)

В Python нет закрытых переменных, как в C ++ или Java. Вы можете получить доступ к любой переменной-члену в любое время, если хотите. Тем не менее, вам не нужны закрытые переменные в Python, потому что в Python неплохо представить переменные-члены ваших классов. Если вам нужно инкапсулировать переменную-член, вы можете сделать это, используя " @ property " позже, не нарушая существующий клиентский код.

В питоне подчеркивание "_" используется для обозначения того, что метод или переменная не рассматривается как часть общедоступного API класса и что эта часть API может изменяться между различными версиями. Вы можете использовать эти методы / переменные, но ваш код может сломаться, если вы используете более новую версию этого класса.

Двойное подчеркивание " __ " не означает «частная переменная». Вы используете его для определения переменных, которые являются «локальными классами» и которые не могут быть легко переопределены подклассами. Он искажает имя переменной.

Например:

class A(object):
    def __init__(self):
        self.__foobar = None # will be automatically mangled to self._A__foobar

class B(A):
    def __init__(self):
        self.__foobar = 1 # will be automatically mangled to self._B__foobar

self .__ Имя foobar автоматически передается self._A__foobar в классе A. В классе B оно передается self._B__foobar. Таким образом, каждый подкласс может определять свою собственную переменную __foobar без переопределения своих родительских переменных. Но ничто не мешает вам получить доступ к переменным, начинающимся с двойного подчеркивания. Однако искажение имен не позволяет вам вызывать эти переменные / методы случайно.

Я настоятельно рекомендую посмотреть, как Рэймонд Хеттингерс расскажет о "наборе инструментов для разработки классов Pythons". из Pycon 2013 (должен быть доступен на Youtube), который дает хороший пример, почему и как вы должны использовать переменные @property и " __ " -instance.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top