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


Я пришел из мира 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?

11 424

11 ответов:

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

если вы хотите эмулировать частные переменные по какой-то причине, вы всегда можете использовать элемент __ префикс от PEP 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 и Питон, я никогда на самом деле используется private или protected.

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

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

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

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

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

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

право. Шизофренический социопат, который отказался читать блоки комментариев API.

существует вариация частных переменных в соглашении подчеркивания.

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 decorators, которые более тесно реализуют концепцию, но YMMV. Возможно, можно также написать определение класса, которое использует meta

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

посмотреть здесь подробнее об этом.

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

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

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

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

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

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

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

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

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

В 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" позже, не нарушая существующий код клиента.

в python один символ подчеркивания " _ " используется для указания, что метод или переменная не рассматривается как часть открытого 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 автоматически искажается для себя._A_ _ foobar в классе A. В классе B он искалечен для себя._Б__фрагментик. Таким образом, каждый подкласс может определить свою собственную переменную __foobar без переопределения родительских переменных. Но ничто не мешает вам получить доступ к переменным, начинающимся с двойных подчеркиваний. Однако искажение имен не позволяет вам случайно вызывать эти переменные /методы.

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