Частные сценарии python

Понимание объектно-ориентированного программирования (ООП) имеет решающее значение, если вы хотите изучать Python. Одним из аспектов ООП является изучение

Понимание объектно-ориентированного программирования (ООП) имеет решающее значение, если вы хотите изучать Python.

Одним из аспектов ООП является изучение того, как определять и использовать частные методы.

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

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

tl;dr – Префикс имени вашего атрибута или метода с одним подчеркиванием. Однако следует помнить, что Python не поддерживает инкапсуляцию, поэтому на самом деле ничего не является приватным.

Что такое частные методы?

Закрытый метод – это метод класса, который можно вызывать только изнутри класса, в котором он определен.

Это означает, что вы не можете (и не должны) получать доступ или вызывать эти методы извне класса.

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

Давайте рассмотрим простой пример частного метода на языке программирования, отличном от Python, скажем, Java. (Вы поймете, почему, позже)

class Hello {
  private void printHello() {
    System.out.println("Привет мир");
  }
}

В Java ключевое слово private используется для объявления частного метода. Итак, в этом примере мы определяем закрытый метод с именем printHello () в классе Hello.

Если вы попытаетесь вызвать этот метод извне класса, он просто не будет работать.

class Hello { 
  private void printHello() { 
    System.out.println("Привет мир");
  } 
}

public class HelloWorld{
  public static void main(String []args){
    Hello h = new Hello();
    h.printHello();
  }
}

Если вы выполните приведенный выше код, вы получите самоочевидное сообщение об ошибке компиляции.

$javac HelloWorld.java
error: printHello() has private access in Hello
  h.printHello();
   ^
1 error

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

class Hello {
  public void print() {
    printHello();
  }
  private void printHello() { 
    System.out.println("Привет мир");
  } 
}

public class HelloWorld{
  public static void main(String []args){
    Hello h = new Hello();
    h.print();
  }
}

Теперь, если вы запустите вышеупомянутую программу, вы не получите никаких ошибок, и вы получите строку «Привет мир», напечатанную на экране.

Обратите внимание, что частный метод printHello() лишь вызывается из внутрикласса и основной программы только называется публичным методом print().

Ну, это круто и все. Вы, наверное, уже знали это. Главный вопрос: зачем нам частные методы? и когда мы должны их использовать?

Когда вы должны использовать частные методы?

Прежде всего, помните, что инкапсуляция является одним из принципов объектно-ориентированного программирования (ООП).

Но что такое инкапсуляция на самом деле?

В объектно-ориентированном программировании инкапсуляция означает скрытие внутренней реализации объекта от внешнего мира.

Это означает, что единственный способ взаимодействия с объектом – через четко определенный интерфейс объекта.

Другими словами, воспринимайте объект как черный ящик, с которым вы можете взаимодействовать через четко определенный интерфейс, не беспокоясь о том, как на самом деле реализован черный ящик.

Например, представьте объект, представляющий автомобиль, простой автомобиль, который позволяет вам только управлять им drive(), нажимая на педаль газа, или останавливать stop(), нажимая на тормоза.

В этом случае мы говорим, что drive() и stop() – это интерфейсы между вами (пользователем автомобиля) и экземпляром автомобиля.

Вам не нужно беспокоиться о том, как машина на самом деле движется или останавливается. Это не ваша проблема. Это то, что заботит конструктора автомобиля. Для вас все, что вы хотите сделать, это либо водить, либо останавливать машину.

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

Давайте ответим на эти два вопроса.

Первое: мы упомянули, что инкапсуляция скрывает реализацию объекта от внешнего мира. Что такое внешний мир?

Внешний мир – это в основном другие разработчики, которые будут использовать проектируемый вами класс (это может быть вы).

Это НЕ конечный пользователь, который будет использовать ваш двоичный файл (у них будет либо пользовательский интерфейс, либо интерфейс командной строки), но инкапсуляция (по крайней мере, в мире ООП) касается потребителей разработчиков.

Второе: почему инкапсуляция полезна? Почему это имеет значение?

Отличный вопрос давайте вернемся к примеру с автомобилем, который мы объяснили ранее.

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

Нужно ли вам (пользователю автомобиля) узнавать что-то новое, чтобы иметь возможность управлять автомобилем после замены двигателя?

Точно нет. Тем не менее, все, что вам нужно сделать, это нажать на педаль газа, и машина будет двигаться.

Эта абстракция очень важна для написания поддерживаемого кода.

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

Это потому, что, пока интерфейс не меняется, все хорошо. Ничего не ломается.

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

В объектно-ориентированном программировании вы определяете этот интерфейс, объявляя открытые атрибуты и методы (public).

И вы достигнете инкапсуляции, объявив закрытые атрибуты и методы (private).

С этим введением, теперь мы можем начать статью.

Прежде чем перейти к закрытым методам и атрибутам, давайте начнем с простого примера.

Давайте построим базовый класс.

class MyClass:
  def __init__(self):
    self.var = 1

  def get_var(self):
    return self.var

В этом примере мы определили класс с именем MyClass.

Внутри этого класса в методе __init__ мы определили один атрибут var, который инициализируется значением 1, и метод get_var, который возвращает значение var.

Теперь давайте прочитаем, а затем изменим значение var.

>> my_object = MyClass() # Создайте экземпляр MyClass
>> my_object.var   # Вызвать атрибут “var”
1                  # Результат - “1”, как и ожидалось
>> my_object.get_var()
1
>> my_object.var = 2
>> my_object.var
2
>> my_object.get_var()
2

Как видите, мы легко изменили значение var с 1 на 2.

Мы смогли это сделать, потому что у нас есть ДОСТУП к атрибуту var  извне.

Но что, если мы хотим скрыть этот атрибут от внешних пользователей?

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

Определение личных атрибутов и методов (private) в Python

Чтобы определить частные атрибуты или методы в Python, вот что вам нужно сделать.

Просто добавьте к имени префикс с единственным подчеркиванием.

Это так просто.

Теперь давайте перепишем приведенный выше пример, чтобы сделать var и get_var приватными.

class MyClass:
  def __init__(self):
    self._var = 1
  def _get_var(self):
    return self._var

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

>> my_object = MyClass()  # Создание экземпляра MyClass
>> my_object._var  # Чтение _var
1
>> my_object._get_var()
1

Хм, подожди! Как?

Мы думали, что мы не можем получить доступ к приватным атрибутам или приватным методам! Как это возможно?

В Python закрытый доступ к закрытым атрибутам (и методам) не применяется.

Поэтому, когда мы говорим, что атрибуты, начинающиеся с одного подчеркивания, являются «частными», это просто соглашение. Но это не соблюдается.

Python не поддерживает инкапсуляцию. Мы любим инкапсуляцию, но разработчики языка решили не поддерживать ее. Ну что ж.

Утверждение о том, что инкапсуляция не является обязательной, не означает, что вам следует обращаться к атрибутам и методам с префиксом подчеркивания.

Не делайте этого, потому что это не обязательно.

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

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

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

Что делают эти двойные ведущие подчеркивания?

Префикс с двойным подчеркиванием (искажение имени)

Давайте вернемся к нашему классу и определим наши var и get_var (), но на этот раз используя двойные подчеркивания вместо одного.

class MyClass:
  def __init__(self):
    self.__var = 1

  def __get_var(self):
    return self.__var

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

>> my_object = MyClass()
>> my_object.__var

AttributeError: 'MyClass' object has no attribute '__var'

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

Точно так же, если вы попытаетесь получить доступ к __get_var (), вы получите ту же ошибку.

>> my_object.__get_var()

AttributeError: 'MyClass' object has no attribute '__get_var'

В чем дело?

Одна вещь, которую мы могли бы сделать, чтобы исследовать происходящее, это напечатать содержимое dir (my_object)

dir() перечисляет все атрибуты (и методы), которые имеет объект

>> dir(my_object)
['_MyClass__get_var', '_MyClass__var',...]

Интересно! Похоже, что Python переименовал переменные __var и __get_var в _MyClass__var и _MyClass__get_var соответственно.

Такое поведение при изменении имен атрибутов или методов называется искажением имен.

Манглинг имен затрудняет доступ к переменным извне класса, но он все еще доступен через _MyClass__var.

>> my_object._MyClass__var = 3
>> my_object._MyClass__var
3

Точно так же вы можете получить доступ к __get_var с его искаженным именем _MyClass__get_var.

Другими словами, вне класса вам нужно будет использовать искаженное имя атрибута, но внутри класса вы все равно можете получить доступ к атрибуту обычным способом. (посмотрите, как мы получили доступ к __var изнутри __get_var () )

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

Это не правильно, поскольку это не то, для чего используется искажение имени.

Имя искажения в основном используется, когда вы унаследовали классы, но это уже другая история.

Что вы должны сделать, это то, что вы должны следовать соглашению и использовать единственное подчеркивание, чтобы обозначить что-то как личное.

Вывод

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

Если вы нашли ошибку, пожалуйста, выделите фрагмент текста и нажмите Ctrl+Enter.

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

Модификаторы доступа

Модификаторы доступы ограничивают доступ объектам — к методам их класса, или дочерним классам — к методам их класса-родителя. Использование модификаторов доступа помогает сокрыть данные в классе таким образом, чтобы никто снаружи не смог помешать работе этого класса.

private (приватные) методы доступны только внутри класса, protected (защищенные) — внутри класса и в дочерних классах.

Как реализованы приватные и защищенные методы в Python

Спойлер — на уровне соглашения, что взрослые люди просто не будут их вызывать вне класса. Перед приватными методами нужно писать двойное нижнее подчеркивание, перед защищенными одно. И вы по-прежнему можете обратиться к методам, несмотря на их «ограниченный» доступ.

class Car:

    def _start_engine(self):
        return "Engine's sound."

    def run(self):
        return self._start_engine()


if __name__ == '__main__':
    car = Car()

    assert "Engine's sound." == car.run()
    assert "Engine's sound." == car._start_engine()

Можно определить следующие минусы:

  • Если бы метод _start_engine обновлял какие-то переменные класса или сохранял состояние, а не просто возвращал «тупой расчет», вы могли что-то поломать для будущей работы с классом. Вы не позволяете себе что-то чинить в моторе вашей машины, потому что тогда никуда не поедете, верно?
  • Вытекающий пункт из предыдущего — чтобы убедиться, что можно «безопасно» (вызов метода не навредит самому классу) использовать защищенный метод — нужно заглянуть в его код и потратить время.
  • Авторы библиотек рассчитывают, что никто не пользуется защищенными и приватными методами классов, которые вы используете в своих проектах. Поэтому могут в любой релиз изменить его реализацию (которая на публичные методы не повлияет из-за обратной совместимости, но вы — пострадаете).
  • Автор класса, ваш коллега, рассчитывает, что вы не увеличите технический долг проекта, использовав защищенный или приватный метод вне созданного им класса. Ведь тому, кто будет его (приватный метод класса) рефакторить или изменять, придется убедиться (например, через тесты), что его изменения не поломают ваш код. А если поломают — ему нужно будет тратить время на то, чтобы решить эту проблему (костылем, потому что надо на вчера).
  • Возможно, вы следите за тем, чтобы другие программисты не использовали защищенные или приватные методам на code review и «бьете за это по рукам», значит — тратите время.

Как реализовать защищенные методы с помощью библиотеки

from accessify import protected


class Car:

    @protected
    def start_engine(self):
        return "Engine's sound."

    def run(self):
        return self.start_engine()


if __name__ == '__main__':
    car = Car()

    assert "Engine's sound." == car.run()

    car.start_engine()

Попытавшись вызвать метод start_engine за пределами класса, вы получите следующую ошибку (метод недоступен согласно политике доступа):

Traceback (most recent call last):
  File "examples/access/private.py", line 24, in <module>
    car.start_engine()
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/main.py", line 92, in private_wrapper
    class_name=instance_class.__name__, method_name=method.__name__,
accessify.errors.InaccessibleDueToItsProtectionLevelException: Car.start_engine() is inaccessible due to its protection level

Используя библиотеку:

  • Вам не надо использовать некрасивое (субъективно) нижнее или двойное нижнее подчеркивание.
  • Получаете красивый (субъективно) метод внедрения модификаторов доступа в код — декораторы private и protected.
  • Перекладываете ответственность с человека на интерпретатор.

Как это работает:

  1. Декоратор private или protected — самый «высоко» расположенный декоратор, срабатывает до метода класса, которому объявили приватный или защищенный модификатор доступа.

  2. В декораторе с помощью встроенной библиотеки inspect достается текущий объект из стека вызовов — inspect.currentframe(). У этого объекта есть следующие полезные нам атрибуты: пространство имен (locals) и ссылка на предыдущий объект из стека вызова (объект, который вызывает метод с модификатором доступа).

    (Очень упрощенная иллюстрация)

  3. inspect.currentframe().f_back — используем этот атрибут, чтобы проверить, находится ли предыдущий объект из стека вызова в теле класса или нет. Для этого смотрим на пространство имен — f_locals. Если атрибут self в пространстве имен есть — метод вызывается внутри класса, если нет — вне класса. Если вызывать метод с приватным или защищенным модификатором доступа вне класса — будет ошибка политики доступа.

Интерфейсы

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

Пример

Имеем класс User, который использует объект storage, чтобы создать нового пользователя.

class User:

    def __init__(self, storage):
        self.storage = storage

    def create(self, name):
        return storage.create_with_name(name=name)

Сохранять пользователя можно в базу данных, используя DatabaseStorage.create_with_name.

class DatabaseStorage:

    def create_with_name(self, name):
        ...

Сохранять пользователя можно в файлы, используя FileStorage.create_with_name.

class FileStorage:

    def create_with_name(self, name):
        ...

За счет того, что сигнатуры методов create_with_name (название, аргументы) у классов одинаковые — классу User не стоит волноваться какой объект ему подставили, если у обоих одинаковые методы. Это может быть достигнуто если классы FileStorage и DatabaseStorage реализуют одинаковый интерфейс (то есть связаны контрактом определить какой-то метод с логикой внутри).

if __name__ == '__main__':

    if settings.config.storage = FileStorage:
        storage = FileStorage()

    if settings.config.storage = DatabaseStorage:
        storage = DatabaseStorage()

    user = User(storage=storage)
    user.create_with_name(name=...)

Как работать с интерфейсами с помощью библиотеки

Если класс имплементирует интерфейс, класс должен содержать все методы интерфейса. В примере ниже интерфейс «HumanInterface» содержит метод «eat», а класс «Human» его имплементирует, но не реализовывает метод «eat».

from accessify import implements


class HumanInterface:

    @staticmethod
    def eat(food, *args, allergy=None, **kwargs):
        pass


if __name__ == '__main__':

    @implements(HumanInterface)
    class Human:

        pass

Скрипт завершит работу со следующей ошибкой:

Traceback (most recent call last):
  File "examples/interfaces/single.py", line 18, in <module>
    @implements(HumanInterface)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator
    interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanInterface.eat(food, args, allergy, kwargs)

Если класс имплементирует интерфейс, класс должен содержать все методы интерфейса, включая все входящие аргументы. В примере ниже интерфейс «HumanInterface» содержит метод «eat», который на вход принимает 4 аргумента, а класс «Human» его имплементирует, но реализовывает метод «eat» только с 1 аргументом.

from accessify import implements


class HumanInterface:

    @staticmethod
    def eat(food, *args, allergy=None, **kwargs):
        pass


if __name__ == '__main__':

    @implements(HumanInterface)
    class Human:

        @staticmethod
        def eat(food):
            pass

Скрипт завершит работу со следующей ошибкой:

Traceback (most recent call last):
  File "examples/interfaces/single_arguments.py", line 16, in <module>
    @implements(HumanInterface)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 87, in decorator
    interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedWithMismatchedArgumentsException: class Human implements interface member HumanInterface.eat(food, args, allergy, kwargs) with mismatched arguments

Если класс имплементирует интерфейс, класс должен содержать все методы интерфейса, включая входящие аргументы и модификаторы доступа. В примере ниже интерфейс «HumanInterface» содержит приватный метод «eat», а класс «Human» его имплементирует, но не реализовывает приватный модификатор доступа к методу «eat».

from accessify import implements, private


class HumanInterface:

    @private
    @staticmethod
    def eat(food, *args, allergy=None, **kwargs):
        pass


if __name__ == '__main__':

    @implements(HumanInterface)
    class Human:

        @staticmethod
        def eat(food, *args, allergy=None, **kwargs):
            pass

Скрипт завершит работу со следующей ошибкой:

Traceback (most recent call last):
  File "examples/interfaces/single_access.py", line 18, in <module>
    @implements(HumanInterface)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 77, in decorator
    interface_method_name=interface_method.name,
accessify.errors.ImplementedInterfaceMemberHasIncorrectAccessModifierException: Human.eat(food, args, allergy, kwargs) mismatches HumanInterface.eat() member access modifier.

Класс может имплементировать несколько (количество неограниченно) интерфейсов. Если класс имплементирует несколько интерфейсов, класс должен содержать все методы всех интерфейсов, включая входящие аргументы и модификаторы доступа. В примере ниже класс «Human» реализовывает метод «eat» интерфейса «HumanBasicsInterface», но не реализовывает метод «love» интерфейса «HumanSoulInterface».

from accessify import implements


class HumanSoulInterface:

    def love(self, who, *args, **kwargs):
        pass


class HumanBasicsInterface:

    @staticmethod
    def eat(food, *args, allergy=None, **kwargs):
        pass


if __name__ == '__main__':

    @implements(HumanSoulInterface, HumanBasicsInterface)
    class Human:

        def love(self, who, *args, **kwargs):
            pass

Скрипт завершит работу со следующей ошибкой:

Traceback (most recent call last):
  File "examples/interfaces/multiple.py", line 19, in <module>
    @implements(HumanSoulInterface, HumanBasicsInterface)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 66, in decorator
    interface_method_arguments=interface_method.arguments_as_string,
accessify.errors.InterfaceMemberHasNotBeenImplementedException: class Human does not implement interface member HumanBasicsInterface.eat(food, args, allergy, kwargs)

Киллер фича — метод интерфейса может «заявить» какие ошибки должен «бросить» метод класса, который его имплементирует. В примере ниже «заявлено», что метод «love» интерфейса «HumanInterface» должен выбрасывать исключение «HumanDoesNotExistError» и
«HumanAlreadyInLoveError», но метод «love» класса «Human» не «бросает» одно из них.

from accessify import implements, throws


class HumanDoesNotExistError(Exception):
    pass


class HumanAlreadyInLoveError(Exception):
    pass


class HumanInterface:

    @throws(HumanDoesNotExistError, HumanAlreadyInLoveError)
    def love(self, who, *args, **kwargs):
        pass


if __name__ == '__main__':

    @implements(HumanInterface)
    class Human:

        def love(self, who, *args, **kwargs):

            if who is None:
                raise HumanDoesNotExistError('Human whom need to love does not exist')

Скрипт завершит работу со следующей ошибкой:

Traceback (most recent call last):
  File "examples/interfaces/throws.py", line 21, in <module>
    @implements(HumanInterface)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/accessify/interfaces.py", line 103, in decorator
    class_method_arguments=class_member.arguments_as_string,
accessify.errors.DeclaredInterfaceExceptionHasNotBeenImplementedException: Declared exception HumanAlreadyInLoveError by HumanInterface.love() member has not been implemented by Human.love(self, who, args, kwargs)

Подводя итоги, с помощью библиотеки:

  • Можно имплементировать один или несколько интерфейсов.
  • Интерфейсы комбинируются с модификаторами доступа.
  • Вы получите разделение интерфейсов и абстрактных классов (модуль abc в Python), теперь не надо использовать абстрактные классы как интерфейсы, если вы это делали (я делал).
  • К сравнению с абстрактными классами. Если вы не определили все аргументы метода из интерфейса — получите ошибку, используя абстрактный класс — нет.
  • К сравнению с абстрактными классами. Используя интерфейсы, вы получите ошибку во время создания класса (когда вы написали класс и вызвали файл *.py). В абстрактных классах вы получите ошибку уже на этапе вызова метода объекта класса.

Как это работает:

  1. В декораторе implements с помощью встроенной библиотеки inspect достаются все методы класса и его интерфейсов — inspect.getmembers(). За уникальный индекс метода принимается комбинация его имени и типа (staticmethod, property, и так далее).
  2. А с помощью inspect.signature() — аргументы метода.
  3. Проходим в цикле по всем методам интерфейса, и смотрим: есть ли такой метод (по уникальному индексу) в классе, который реализовывает интерфейс, одинаковые ли входящие аргументы, одинаковые ли модификаторы доступа, реализовывает ли метод объявленные ошибки в методе интерфейса.

Спасибо за внимание к статье. Ссылка на проект на Github.

  1. модификатор частного доступа в Python
  2. Объявить частный метод в Python

Частные методы в Python

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

private — ключевое слово для типа модификатора доступа, используемого в объектно-ориентированных языках программирования. Модификаторы доступа в определенной степени ограничивают видимость функции или переменной. Объявление вашей функции / переменной как частной ограничивает доступ только к инкапсулирующему ее классу.

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

модификатор частного доступа в Python

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

Чтобы объявить частный метод в Python, вставьте двойное подчеркивание в начало имени метода.

метод __init__()

Заметным частным методом в Python является метод __init__(), который используется как конструктор класса для объекта класса. Этот метод вызывается при создании экземпляра объекта класса в зависимости от аргументов метода.

Например, объявите класс Person с двумя полями и методом __init__():

class Person:
    name = ''
    age = 0
    
    def __init__(self, n, a):
        self.name = n
        self.age = a
    

Теперь, чтобы получить доступ к частному методу __init__() за пределами класса, нам потребуется доступ к нему из объекта самого класса после его создания.

Например, в другом файле в том же каталоге создайте экземпляр класса Person и вызовите конструктор по имени класса.

sys.path.append(".")

from personClass import Person

person = Person("John Doe", 25)

print(person.name, person.age)

Выход:

Примечание

Чтобы импортировать классы из другого файла в текущий файл, используйте sys.path.append() со строковым путем к каталогу класса, который вы хотите импортировать в качестве аргумента. В этом случае оба файла находятся в одной папке, поэтому точка . достаточно. После этого импортируйте класс (Person) из файла .py (personClass.py).

Метод __init__() может быть вызван явно после создания экземпляра класса Person в переменной для повторного создания экземпляра объекта.

Например:

person = Person("John Doe", 25)
person.__init__("Jane Doe", 29)

print(person.name, person.age)

Выход:

Также метод __init()__ может быть вызван явно, вызвав его из самого класса. Хотя для этого подхода вам нужно будет явно указать в аргументах первый параметр self.

person = Person("John Doe", 25)
Person.__init__(person, "Jack Sparrow", 46)   #person is the 'self' argument

print(person.name, person.age)

Выход:

Все эти подходы сохраняют частную собственность метода __init__().

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

Объявить частный метод в Python

Чтобы объявить частный метод, поставьте перед рассматриваемым методом двойное подчеркивание __. В противном случае он будет рассматриваться как общедоступный метод по умолчанию.

Давайте расширим класс Person из предыдущего примера и создадим подкласс Employee, который основывает свой конструктор на классе Person.

Кроме того, создайте два новых метода в классе person: общедоступный и частный.

class Person:
    name = ''
    age = 0
    
    def __init__(self, name, age):
        self.name = name
        self.age = age
    
    def walk(self):
        print("Walking")
        
    def __call(self):
        print("Taking a call")

Теперь создайте производный класс или подкласс Employee, расширяющий Person:

class Employee(Person):
    occupation = 'Unemployed'
    salary = 0
    
    def __init__(self, name, age, occupation, salary):
        Person.__init__(self, name, age)
        self.occupation = occupation
        self.salary = salary
        
    def work(self):
        print("Employee is working")
        self.walk()
        
    def takeCall(self):
        self.__call()
        print("Employee is taking a call")

Примечание

Чтобы расширить класс до другого класса, добавьте в объявление класса аргумент, который является именем класса родительского класса. В данном случае аргументом является класс Person.

<div class="alert alert-warning" role="alert"><p>В этом классе методы <code>work()</code> и <code>takeCall()</code> извне вызывают классы <code>walk()</code> и <code>__call()</code> из родительского класса <code>Person</code> соответственно.</p>

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

Например, учитывая объявления класса выше:

employee_1 = Employee("John Doe", 25, "Software Engineer", 40000)

employee_1.work()
employee_1.takeCall()

Выход:

Employee is working
Walking
Traceback (most recent call last):
  File "python/demo.py", line 35, in <module>
    employee_1.takeCall()
  File "python/demo.py", line 29, in takeCall
    self.__call()
AttributeError: 'Employee' object has no attribute '_Employee__call'

Вызов метода work() успешно выполнен, распечатывая операторы из методов work() и walk(). Однако вызов takeCall() вызывает AttributeError, потому что он не распознает метод __call() из класса Person как метод класса Employee. Расширение класса до другого класса не включает в себя его собственные частные методы.

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

Encapsulation is one of the fundamental concepts in object-oriented programming (OOP) in Python. It describes the idea of wrapping data and the methods that work on data within one unit. This puts restrictions on accessing variables and methods directly and can prevent the accidental modification of data. A class is an example of encapsulation as it encapsulates all the data that is member functions, variables, etc. Now, there can be some scenarios in which we need to put restrictions on some methods of the class so that they can neither be accessed outside the class nor by any subclasses. To implement this private methods come into play.

Private functions in Python

Consider a real-life example, a car engine, which is made up of many parts like spark plugs, valves, pistons, etc. No user uses these parts directly, rather they just know how to use the parts which use them. This is what private methods are used for. It is used to hide the inner functionality of any class from the outside world. Private methods are those methods that should neither be accessed outside the class nor by any base class. In Python, there is no existence of Private methods that cannot be accessed except inside a class. However, to define a private method prefix the member name with the double underscore__”. Note: The __init__ method is a constructor and runs as soon as an object of a class is instantiated. 

Python3

class Base:

    def fun(self):

        print("Public method")

    def __fun(self):

        print("Private method")

class Derived(Base):

    def __init__(self):

        Base.__init__(self)

    def call_public(self):

        print("nInside derived class")

        self.fun()

    def call_private(self):

        self.__fun()

obj1 = Base()

obj1.fun()

obj2 = Derived()

obj2.call_public()

Output:

Public method

Inside derived class
Public method
Traceback (most recent call last):
  File "/home/09d6f91fdb63d16200e172c7a925dd7f.py", line 43, in 
    obj1.__fun() 
AttributeError: 'Base' object has no attribute '__fun'

Traceback (most recent call last):
  File "/home/0d5506bab8f06cb7c842501d9704557b.py", line 46, in 
    obj2.call_private() 
  File "/home/0d5506bab8f06cb7c842501d9704557b.py", line 32, in call_private
    self.__fun()
AttributeError: 'Derived' object has no attribute '_Derived__fun'

The above example shows that private methods of the class can neither be accessed outside the class nor by any base class. However, private methods can be accessed by calling the private methods via public methods. 

Example: 

Python3

class A:

    def fun(self):

        print("Public method")

    def __fun(self):

        print("Private method")

    def Help(self):

        self.fun()

        self.__fun()

obj = A()

obj.Help()

Output:

Public method
Private method

Name mangling

Python provides a magic wand that can be used to call private methods outside the class also, it is known as name mangling. It means that any identifier of the form __geek (at least two leading underscores or at most one trailing underscore) is replaced with _classname__geek, where the class name is the current class name with a leading underscore(s) stripped. 

Example: 

Python3

class A:

    def fun(self):

        print("Public method")

    def __fun(self):

        print("Private method")

obj = A()

obj._A__fun()

Output:

Private method

Python gives us the ability to create ‘private’ methods and variables within a class by prepending double underscores to the name, like this: __myPrivateMethod(). How, then, can one explain this

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

What’s the deal?!

I’ll explain this a little for those who didn’t quite get that.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

I create a class with a public method and a private method and instantiate it.

Next, I call its public method.

>>> obj.myPublicMethod()
public method

Next, I try and call its private method.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

Everything looks good here; we’re unable to call it. It is, in fact, ‘private’. Well, actually it isn’t. Running dir() on the object reveals a new magical method that Python creates magically for all of your ‘private’ methods.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

This new method’s name is always an underscore, followed by the class name, followed by the method name.

>>> obj._MyClass__myPrivateMethod()
this is private!!

So much for encapsulation, eh?

In any case, I’d always heard Python doesn’t support encapsulation, so why even try? What gives?

Python gives us the ability to create ‘private’ methods and variables within a class by prepending double underscores to the name, like this: __myPrivateMethod(). How, then, can one explain this

>>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

>>> obj.myPublicMethod()
public method

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

>>> obj._MyClass__myPrivateMethod()
this is private!!

What’s the deal?!

I’ll explain this a little for those who didn’t quite get that.

>>> class MyClass:
...     def myPublicMethod(self):
...             print 'public method'
...     def __myPrivateMethod(self):
...             print 'this is private!!'
...
>>> obj = MyClass()

I create a class with a public method and a private method and instantiate it.

Next, I call its public method.

>>> obj.myPublicMethod()
public method

Next, I try and call its private method.

>>> obj.__myPrivateMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute '__myPrivateMethod'

Everything looks good here; we’re unable to call it. It is, in fact, ‘private’. Well, actually it isn’t. Running dir() on the object reveals a new magical method that Python creates magically for all of your ‘private’ methods.

>>> dir(obj)
['_MyClass__myPrivateMethod', '__doc__', '__module__', 'myPublicMethod']

This new method’s name is always an underscore, followed by the class name, followed by the method name.

>>> obj._MyClass__myPrivateMethod()
this is private!!

So much for encapsulation, eh?

In any case, I’d always heard Python doesn’t support encapsulation, so why even try? What gives?

Совет украинцам!

Что делать если к вам пришли мужики с автоматами что бы вручить вам повестку на фронт ? — Что что, убивать их! вы имеете полное право защищать свою жизнь и свою свободу всеми доступными для вас способами, можно военкома пырнуть ножом, можно вжать ему вилкой в глаз, носите с собой в кармане хотя бы всегда чайную ложечку или карандаш, как только к вам подходят военкомы, не ждите, не разговаривайте, не выясняйте не разъясняйте не чего, резким движением достаете карандаш из кармана и всаживаете его в глаз военкому, и сразу бегите, у вас будит ровно минуты три чтобы убежать, из за неожиданности и резкой паники все кто был с военкомом будут в ступоре, это ваш шанс выжить, в ином случаи вас насильно увезут на фронт и вы там умрете, второй вариант вы станете рабом бесплатного труда на 25 лет. Военкомов мало. Первому второму третьему глаз вышибите и уже все никто не будит ходить по домам и раздавать приглашение на смерть и принуждать на грехи которым никогда не будит прощения. Запомните украинцы пока вы своим «панам» позволяете себя убивать вас будут убивать. И вы не думайте что война эта пройдет на экранах ваших телефонов, нет ребята, это реальность в которой вы можете оказаться спустя два часа как только прочитали это сообщение. Лучше покалечить здоровье сатанисту раздающему билеты в ад нежили оказаться в аду, вы поймите что вы все равно на фронте вынуждены будите тыкать людям вилкой в глаза. Эта суровая неизбежность нынешних событий.
Убив одного военкома Вы спасаете 1000 жизней молодых ребят от 18 до 25 лет, а это уже священный долг каждого мужчины и отца!

No Hi-Tech Чacтыe cцeнapии Python в / ЛАЙФХАК

Рaccмoтpим чacтыe cцeнapии пpи нaпиcaнии циклoв.

Пoдcчeт кoличecтвa

Нepeдкo нужнo, чтoбы нaши пpoгpaммы пoдcчитывaли cкoлькo paз чтo-либo пpoизoшлo. К пpимepу видeo игpa мoжeт пoдcчитывaть кoличecтвo пoвopoтoв пepcoнaжa или мaтeмaтичecкaя пpoгpaммa мoжeт cчитaть кaк мнoгo чиceл oблaдaют нeкoтopым cвoйcтвoм. Ключ к пoдcчeту — иcпoльзoвaниe пepeмeннoй cчeтчикa.

Нaпишeм пpoгpaмму, кoтopaя cчитывaeт 10 чиceл и oпpeдeляeт cкoлькo из ниx бoльшe 10.

Пpимep кoдa

Пpимep кoдa

Кaждый paз кoгдa мы cчитывaeм чиcлo бoльшee 10, мы дoбaвляeм 1 к нaшeму тeкущeму знaчeнию пepeмeннoй counter. В пpoгpaммe этo peaлизoвaнo в cтpoкe counter = counter + 1. Обpaтитe внимaниe нa нaчaльнoe знaчeниe пepeмeннoй cчeтчикa counter = 0. Бeз нaчaльнoгo знaчeния мы пoлучили бы oшибку, пocкoльку дoйдя дo cтpoки counter = counter + 1 Python ничeгo нe знaл бы o пepeмeннoй counter .

Стpoкa кoдa counter = counter + 1 oзнaчaeт: вoзьми cтapoe знaчeниe пepeмeннoй counter, пpибaвь к нeму 1 и пepeпpиcвoй пepeмeннoй этo знaчeниe. Еcли нe пpидaть пepeмeннoй нaчaльнoe знaчeниe, тo нeпoнятнo, к чeму пpибaвлять 1 в caмый пepвый paз.

Пoдcчeт кoличecтвa – этo oчeнь чacтый cцeнapий. Он cocтoит из двуx шaгoв:

  1. Сoздaниe пepeмeннoй cчeтчикa и пpидaниe eй пepвoнaчaльнoгo знaчeния: counter = 0;
  2. Увeличeниe пepeмeннoй cчeтчикa нa 1: counter = counter + 1.

Чacтo пpи нaпиcaнии пpoгpaмм тpeбуeтcя иcпoльзoвaть нecкoлькo cчeтчикoв. Мoдифициpуeм пpeдыдущую пpoгpaмму: пocчитaeм eщe и кoличecтвo нулeй cpeди ввeдeнныx чиceл.

Пpимep кoдa c иcпoльзoвaниeм циклa for

Пpимep кoдa c иcпoльзoвaниeм циклa for

Рaccмoтpим eщe oдин пpимep: пoдcчитaть кoличecтвo чиceл из диaпaзoнa [1;100], квaдpaт кoтopыx oкaнчивaeтcя нa 4.

Нaxoждeниe чиceл oкaнчивaющиxcя нa 4 в диaпaзoнe

Нaxoждeниe чиceл oкaнчивaющиxcя нa 4 в диaпaзoнe

Мы иcпoльзуeм функцию range() c двумя пapaмeтpaми для гeнepaции пocлeдoвaтeльнocти чиceл oт 1 дo 100. Пepeмeннaя i пocлeдoвaтeльнo пpинимaeт знaчeния oт 1 дo 100, мы пpoвepяeм, уcлoвиe: квaдpaт чиcлa i oкaнчивaeтcя нa 4 c пoмoщью уcлoвия i**2 % 10 == 4.

Для пepeмeннoй cчeтчикa удoбнo иcпoльзoвaть имя counter.

Вычиcлeниe cуммы и пpoизвeдeния

Нapaвнe c пoдcчeтoм кoличecтвa пo чacтoтe cтoит зaдaчa вычиcлeния cуммы. К пpимepу видeo игpa дoлжнa cчитaть cумму oчкoв. В тaкoм cлучae нaчaльнoe знaчeниe пepeмeннoй будeт paвнo 0, a дaлee oнo будeт увeличивaтьcя нa нeкoтopoe кoличecтвo зapaбoтaнныx oчкoв, cкaжeм нa 10. Мы пишeм cлeдующий кoд:

score = 0 …
score = score + 10

Нaпишeм пpoгpaмму, кoтopaя cчитывaeт 10 чиceл и oпpeдeляeт cумму тex из ниx, кoтopыe бoльшe 10.

Нaxoждeниe cуммы чиceл ecли знaчeниe вышe 10

Нaxoждeниe cуммы чиceл ecли знaчeниe вышe 10

Кaждый paз кoгдa пpoгpaммa cчитывaeт чиcлo бoльшee 10, oнa дoбaвляeт eгo к тeкущeму знaчeнию пepeмeннoй total. Этo peaлизoвaнo в cтpoкe total = total + num. Обpaтитe внимaниe нa нaчaльнoe знaчeниe пepeмeннoй cуммaтopa total = 0.

Бeз нaчaльнoгo знaчeния, мы пoлучили бы oшибку, пocкoльку дoйдя дo cтpoки total = total + num Python ничeгo нe знaл бы o пepeмeннoй total .

Стpoкa кoдa total = total + num oзнaчaeт вoзьми cтapoe знaчeниe пepeмeннoй total, пpибaвь к нeму num и пepeпpиcвoй пepeмeннoй этo знaчeниe. Еcли нe пpидaть пepeмeннoй нaчaльнoe знaчeниe, тo нe к чeму пpибaвлять num в caмый пepвый paз.

Пoдcчeт cуммы cocтoит из двуx шaгoв:

  1. Сoздaниe пepeмeннoй cуммaтopa и пpидaниe eй пepвoнaчaльнoгo знaчeния: total = 0;
  2. Увeличeниe пepeмeннoй cуммaтopa нa нужнoe чиcлo: total = total + num.

Нaпишeм пpoгpaмму, кoтopaя cчитaeт cумму нaтуpaльныx чиceл oт 1 дo 100:

Нaxoждeниe cуммы чиceл

Нaxoждeниe cуммы чиceл

Рaccмoтpим eщe oдин пpимep: нaпишeм пpoгpaмму, кoтopaя зaпpaшивaeт 10 цeлыx чиceл и нaxoдит иx cpeднee знaчeниe:

Нaxoждeниe cpeднeгo знaчeния cуммы чиceл

Нaxoждeниe cpeднeгo знaчeния cуммы чиceл

Анaлoгичным oбpaзoм вычиcляeтcя пpoизвeдeниe. Пpи вычиcлeнии пpoизвeдeния, нaчaльнoe знaчeниe пepeмeннoй мультипликaтopa мы уcтaнaвливaeм paвным 1, в oтличии oт cуммaтopa, гдe oнo paвнo 0.

Для пepeмeннoй cуммaтopa и мультипликaтopa удoбнo иcпoльзoвaть имя total.

Обмeн знaчeний пepeмeнныx

Очeнь чacтo нaм тpeбуeтcя oбмeнять знaчeния двуx пepeмeнныx x и y. Нaчинaющиe пpoгpaммиcты инoгдa пишут тaкoй кoд:

x = y
y = x

Однaкo oн нe paбoтaeт. Пpeдпoлoжим, чтo x = 3 и y = 5. Пepвaя cтpoкa пpиcвoит пepeмeннoй x знaчeниe 5, чтo пpaвильнo, oднaкo втopaя cтpoкa уcтaнoвит знaчeниe пepeмeннoй y в 5, пocкoльку знaчeниe x ужe paвнo 5. Для peшeния зaдaчи мы мoжeм иcпoльзoвaть вpeмeнную пepeмeнную:

temp = x
x = y
y = temp

Тaкoй кoд пишут пoчти вo вcex языкax пpoгpaммиpoвaния. Однaкo в Python ecть и бoлee пpocтoй cпocoб. Мы мoжeм нaпиcaть тaк:

x, y = y, x

В peзультaтe выпoлнeния тaкoгo кoдa Python пoмeняeт знaчeния пepeмeнныx x и y мecтaми.

Сигнaльныe мeтки

Сигнaльнaя мeткa (флaжoк) мoжeт иcпoльзoвaтьcя, кoгдa нaдo чтoбы oднa чacть пpoгpaммы узнaлa, o пpoиcxoдящeм в дpугoй чacти пpoгpaммы.
Нaпишeм пpoгpaмму, oпpeдeляющую, чтo нaтуpaльнoe чиcлo являeтcя пpocтым:

Иcпoльзoвaниe cигнaльнoй мeтки в пpoгpaммe

Иcпoльзoвaниe cигнaльнoй мeтки в пpoгpaммe

Нaпoмним, чтo чиcлo являeтcя пpocтым, ecли oнo нe имeeт дeлитeлeй, кpoмe 1 и caмoгo ceбя. Вышeпpивeдeннaя пpoгpaммa paбoтaeт cлeдующим oбpaзoм: нaчaльнoe знaчeниe пepeмeннoй флaгa paвнo True, чтo гoвopит o тoм, чтo чиcлo являeтcя пpocтым. Зaтeм мы пepeбиpaeм вce чиcлa oт 2 дo num — 1. Еcли oднo из этиx знaчeний oкaзывaeтcя дeлитeлeм чиcлa num, тoгдa чиcлo num являeтcя cocтaвным и мы уcтaнaвливaeм знaчeниe флaгa False. Кaк тoлькo цикл зaвepшeн, мы пpoвepяeм, уcтaнoвлeн флaг или нeт. Еcли этo тaк, мы знaeм, чтo был дeлитeль, и чиcлo нe являeтcя пpocтым. В пpoтивнoм cлучae чиcлo дoлжнo быть пpocтым.

Флaгoвыe пepeмeнныe мoгут имeть бoлee ocмыcлeннoe нaзвaниe. Нaпpимep, в cлучae c пpoвepкoй чиcлa нa пpocтoту, нaзвaниe флaгoвoй пepeмeннoй мoглo бы быть is_prime.

Мaкcимум и минимум

Пoиcк нaибoльшeгo или нaимeньшeгo знaчeния в нeкoтopoй пocлeдoвaтeльнocти чиceл, тaкжe чacтaя зaдaчa в пpoгpaммиpoвaнии. Нaпишeм пpoгpaмму, кoтopaя cчитывaeт 10 пoлoжитeльныx чиceл и нaxoдит cpeди ниx нaибoльшee чиcлo.

Нaxoждeниe нaибoльшeгo знaчeния чиcлa

Нaxoждeниe нaибoльшeгo знaчeния чиcлa

Мы уcтaнaвливaeм нaчaльнoe знaчeниe пepeмeннoй largest в -1. Дaлee пpoгpaммa cчитывaeт 10 чиceл, и ecли кaкoe-тo из ниx oкaзывaeтcя бoльшe тeкущeгo знaчeния largest, пepeпpиcвaивaeт eгo. В кaчecтвe нaчaльнoгo знaчeния взятo чиcлo -1, пocкoльку мы знaeм, чтo вce чиcлa пoлoжитeльны, тaким oбpaзoм ужe пepвoe cpaвнeниe пpивeдeт к пepeпpиcвaивaнию.

Рacпpocтpaнeн пoдxoд, кoгдa в кaчecтвe нaчaльнoгo знaчeния пepeмeннoй, cpaзу пpинимaeтcя пepвый элeмeнт пocлeдoвaтeльнocти. Нaпишeм пpoгpaмму, кoтopaя cчитывaeт 10 чиceл (нeoбязaтeльнo пoлoжитeльныx) и нaxoдит cpeди ниx нaибoльшee:

Пpиcвaивaниe мaибoльшeгo знaчeния

Пpиcвaивaниe мaибoльшeгo знaчeния

Для нaxoждeния нaимeньшeгo знaчeния пocлeдoвaтeльнocти cлeдуeт пoмeнять знaк нepaвeнcтвa (>) нa пpoтивoпoлoжный (<). В тaкoм cлучae нaзвaниe пepeмeннoй largest cтoит зaмeнить нa smallest.

Для пepeмeнныx, xpaнящиx нaибoльшee и нaимeньшee знaчeния, пoдxoдят имeнa largest и smallest.

Рacшиpeнныe oпepaтopы пpиcвaивaния

Дoвoльнo чacтo пpoгpaммы имeют инcтpукции пpиcвaивaния, в кoтopыx пepeмeннaя нa лeвoй cтopoнe oт oпepaтopa = тaкжe пoявляeтcя нa пpaвoй oт нeгo cтopoнe. Нaпpимep,

counter = counter + 1

Нa пpaвoй cтopoнe oпepaтopa пpиcвaивaния 1 пpибaвляeтcя к пepeмeннoй counter. Пoлучeнный peзультaт зaтeм пpиcвaивaeтcя пepeмeннoй counter, зaмeняя пepвoнaчaльнoe знaчeниe. Пo cути, этo cтpoкa кoдa дoбaвляeт 1 к counter. Ещe oдин пpимep тaкoй инcтpукции мы видeли пpи пoдcчeтe cуммы:

total = total + num

Этa инcтpукция пpиcвaивaeт знaчeниe выpaжeния total + num пepeмeннoй total. В peзультaтe иcпoлнeния этoй инcтpукции чиcлo num пpибaвляeтcя к знaчeнию total.

Инcтpукции и oпиcaниe пpиcвaивaния пepeмeннoй знaчeния

Инcтpукции и oпиcaниe пpиcвaивaния пepeмeннoй знaчeния

Эти типы oпepaций нaxoдят шиpoкoe пpимeнeниe в пpoгpaммиpoвaнии. Для удoбcтвa Python пpeдлaгaeт pacшиpeнныe oпepaтopы пpиcвaивaния. Рacшиpeнныe oпepaтopы нe тpeбуют, чтoбы пpoгpaммиcт двaжды нaбиpaл имя пepeмeннoй. Пpивeдeнную нижe инcтpукцию:

total = total + num

мoжнo пepeпиcaть кaк

total += num

Тoчнo тaк жe инcтpукцию

counter = counter + 1

мoжнo пepeпиcaть кaк

counter += 1

Нecкoлькo дoпoлнитeльныx oпepaтopoв

Нecкoлькo дoпoлнитeльныx oпepaтopoв

Пpимeчaния

Пpимeчaниe 1. Анaлoгичным oбpaзoм мoжнo мeнять мecтaми знaчeния тpex и бoлee пepeмeнныx.

Пpимeчaниe 2. Очeнь чacтo cигнaльныe мeтки нaзывaют flag.

Пpимeчaниe 3. Пocкoльку в Python ecть вcтpoeнныe функции max() и min(), тo дaвaть тaкиe нaзвaния для мaкcимaльнoгo и минимaльнoгo знaчeния нe oчeнь xopoшo. Кудa лучшe иcпoльзoвaть нaзвaния largest и smallest.

Пpимeчaниe 4. Сумму чиceл oт 1 дo 100, мoжнo вычиcлить и бeз циклa: Суммa=(1+100)/2*100 = 5050.

Дeйcтвитeльнo, чиcлa oт 1 дo 100, мoжнo paзбить нa 50 пap, cуммa в кoтopыx paвнa 101 :

1 + 100 = 101 ; 2 + 99 = 101 ; 3 + 98 = 101… ; 50 + 51 = 101.

В нaчaльнoй шкoлe, гдe училcя мaтeмaтик Кapл Фpидpиx Гaуcc (6 лeт), учитeль, чтoбы зaнять клacc нa пpoдoлжитeльнoe вpeмя caмocтoятeльнoй paбoтoй, дaл зaдaниe учeникaм  вычиcлить cумму вcex нaтуpaльныx чиceл oт 1 дo 100. Мaлeнький Гaуcc oтвeтил нa вoпpoc пoчти мгнoвeннo, пpимeнив укaзaнный cпocoб пoдcчeтa, чeм нeвepoятнo удивил вcex и, пpeждe вceгo, учитeля.

Чacтыe cцeнapии в Python

Зaключeниe

В дaннoй тeмe paccмoтpeли нeкoтopыe cцeнapии пpи нaпиcaнии циклoв c пpимepaми кoдa для упpoщeния paбoты или мaтeмaтичecкиx вычиcлeний.

Пocмoтpитe и дpугиe мoи публикaции ecли иx пpoпуcтили:

Python: цикл for — функция range

Python: цикл for

Python: Стpoкoвый тип дaнныx

Python: Лoгичecкиe oпepaции.

Python: Цeлoчиcлeннaя apифмeтикa

Python: Цeлoчиcлeннaя apифмeтикa. чacть 2

Python: sep, end, пepeмeнныe, PEP 8

/ ЛАЙФХАК

● Русский инстаграм Instagram Росграм NOW NEW ! кликай…

● Обманут Лядовой, у экс-жены принимал роды, а счастье обрёл с молоденькой. Настоящий самородок Александр Яценко ВКУС ПОПУЛЯРНОСТИ

● Как выглядят актеры, озвучивавшие «Трех богатырей» Афиша.дети

● Показываю как правильно отремонтировать сколы на капоте и бампере своими руками, хватает на годы Блог автоперекупщика

● Найти управу на соседских квартирантов стало проще: реальные примеры Юридические тонкости

● За что? Часть 7. Истории из жизни

● Почему я более 3 лет покупала в «Ермолино», но уже полгода как прохожу мимо O-milla

● «Попробуй скажи!»: Необычная настольная игра, где нужно брать в рот. И это, ядрёна, не кликбейт — здесь правда есть загубники 👄 #КсенВещает

● Иконы чудотворящие. Мочище, Новосибирская область. MalyshFalko

● Детство балерин. Балетные лагеря Балет наизнанку

● Сошел с ума на минутку, убил, но не виновен: Легендарная реальная история «Анатомия убийства» Black Maria Кино 🎬

Спасибо что Вы с нами!

2023-02-03 03:59:49

Внимание! авторам, имеющих авторское право на тот или иной текст бренд или логотип, для того чтобы ваша авторская информация свободно не распространялась в ресурсах интернета вы должны ее удалить с таких ресурсов как vk.com ok.ru dzen.ru mail.ru telegram.org instagram.com facebook.com twitter.com youtube.com и т.д в ином случаи размещая информацию на данных ресурсах вы согласились с тем что переданная вами информация будет свободно распространятся в любых ресурсах интернета. Все тексты которые находятся на данном сайте являются неотъемлемым техническим механизмом данного сайта, и защищены внутренним алфавитным ключом шифрования, за любое вредоносное посягательство на данный ресурс мы можем привлечь вас не только к административному но и к уголовному наказанию.

Согласно статье 273 УК РФ

Пожаловаться на эту страницу!

2759 тыс.

I would like to have a function in my class, which I am going to use only inside methods of this class. I will not call it outside the implementations of these methods. In C++, I would use a method declared in the private section of the class. What is the best way to implement such a function in Python?

I am thinking of using a static decorator for this case. Can I use a function without any decorators and the self word?

Peter Mortensen's user avatar

asked Jun 19, 2013 at 14:08

freude's user avatar

4

Python doesn’t have the concept of private methods or attributes. It’s all about how you implement your class. But you can use pseudo-private variables (name mangling); any variable preceded by __(two underscores) becomes a pseudo-private variable.

From the documentation:

Since there is a valid use-case for class-private members (namely to
avoid name clashes of names with names defined by subclasses), there
is limited support for such a mechanism, called name mangling. Any
identifier of the form __spam (at least two leading underscores, at
most one trailing underscore) is textually replaced with
_classname__spam, where classname is the current class name with leading underscore(s) stripped. This mangling is done without regard
to the syntactic position of the identifier, as long as it occurs
within the definition of a class.

class A:
    def __private(self):
       pass

So __private now actually becomes _A__private.

Example of a static method:

>>> class A:
...     @staticmethod         # Not required in Python 3.x
...     def __private():
...         print 'hello'
...
>>> A._A__private()
hello

Peter Mortensen's user avatar

answered Jun 19, 2013 at 14:14

Ashwini Chaudhary's user avatar

Ashwini ChaudharyAshwini Chaudhary

240k56 gold badges453 silver badges501 bronze badges

7

Python doesn’t have the concept of ‘private’ the way many other languages do. It is built on the consenting adult principle that says that users of your code will use it responsibly. By convention, attributes starting with a single or double leading underscore will be treated as part of the internal implementation, but they are not actually hidden from users. Double underscore will cause name mangling of the attribute name though.

Also, note that self is only special by convention, not by any feature of the language. Instance methods, when called as members of an instance, are implicitly passed the instance as a first argument, but in the implementation of the method itself, that argument can technically be named any arbitrary thing you want. self is just the convention for ease of understanding code. As a result, not including self in the signature of a method has no actual functional effect other than causing the implicit instance argument to be assigned to the next variable name in the signature.

This is of course different for class methods, which receive the instance of the class object itself as an implicit first argument, and static methods, which receive no implicit arguments at all.

Peter Mortensen's user avatar

answered Jun 19, 2013 at 14:13

Silas Ray's user avatar

Silas RaySilas Ray

25.4k5 gold badges47 silver badges61 bronze badges

0

Python just doesn’t do private. If you like you can follow convention and precede the name with a single underscore, but it’s up to other coders to respect that in a gentlemanly† fashion

† or gentlewomanly

answered Jun 19, 2013 at 14:14

John La Rooy's user avatar

John La RooyJohn La Rooy

290k51 gold badges361 silver badges501 bronze badges

There is plenty of great stuff here with obfuscation using leading underscores. Personally, I benefit greatly from the language design decision to make everything public as it reduces the time it takes to understand and use new modules.

However, if you’re determined to implement private attributes/methods and you’re willing to be unpythonic, you could do something along the lines of:

from pprint import pprint


# CamelCase because it 'acts' like a class
def SneakyCounter():

    class SneakyCounterInternal(object):

        def __init__(self):
            self.counter = 0

        def add_two(self):
            self.increment()
            self.increment()

        def increment(self):
            self.counter += 1

        def reset(self):
            print 'count prior to reset: {}'.format(self.counter)
            self.counter = 0

    sneaky_counter = SneakyCounterInternal()

    class SneakyCounterExternal(object):

        def add_two(self):
            sneaky_counter.add_two()

        def reset(self):
            sneaky_counter.reset()

    return SneakyCounterExternal()


# counter attribute is not accessible from out here
sneaky_counter = SneakyCounter()

sneaky_counter.add_two()
sneaky_counter.add_two()
sneaky_counter.reset()

# `increment` and `counter` not exposed (AFAIK)
pprint(dir(sneaky_counter))

It is hard to imagine a case where you’d want to do this, but it is possible.

Peter Mortensen's user avatar

answered Apr 24, 2017 at 3:52

circld's user avatar

circldcircld

6021 gold badge6 silver badges13 bronze badges

1

You just don’t do it:

  • The Pythonic way is to not document those methods/members using docstrings, only with «real» code comments. And the convention is to append a single or a double underscore to them;

  • Then you can use double underscores in front of your member, so they are made local to the class (it’s mostly name mangling, i.e., the real name of the member outside of the class becomes: instance.__classname_membername). It’s useful to avoid conflicts when using inheritance, or create a «private space» between children of a class.

  • As far as I can tell, it is possible to «hide» variables using metaclasses, but that violates the whole philosophy of Python, so I won’t go into details about that.

Peter Mortensen's user avatar

answered Jun 19, 2013 at 14:13

zmo's user avatar

zmozmo

24.2k4 gold badges53 silver badges87 bronze badges

3

Let me preface this article by emphasizing that understanding object-oriented programming (OOP) is crucial if you want to learn Python.

One aspect of OOP is to learn how to define and use private methods.

In this article, I will teach you how to create private methods, when to use them, and why they are necessary.

Warning: this is going to be a long in-depth article about private methods but if you only want to know how to define private methods in Python, here is the tl;dr.

tl;dr Prefix your attribute or method names with a single underscore. However, be aware that Python doesn’t support encapsulation, so nothing is really private.

Interested in becoming an expert in object-oriented programming in Python?

Check out my in-depth Python OOP course.

What are Private Methods?

A private method is a Class method that can only be called from inside the Class where it is defined.

This means that you can’t (and shouldn’t) access or call these methods from outside of the Class.

They are the opposite of public methods which are, as you might have guessed, methods that can be accessed from inside the class as well as outside the class.

Let’s look at a simple example of a private method in a programming language other than Python, say Java. (You will understand why later)

class Hello {
  private void printHello() {
    System.out.println("Hello world");
  }
}

In Java, the private keyword is used to declare a private method. So in this example, we define a private method called printHello() in class Hello.

If you try to call this method from outside of the class, it would just not work.

class Hello { 
  private void printHello() { 
    System.out.println("Hello world");
  } 
}

public class HelloWorld{
  public static void main(String []args){
    Hello h = new Hello();
    h.printHello();
  }
}

If you execute the above code, you get this self-explanatory compile error message.

$javac HelloWorld.java
error: printHello() has private access in Hello
  h.printHello();
   ^
1 error

However, you can still access the private method from within the class. Let’s define a new public method that accesses our private method internally.

class Hello {
  public void print() {
    printHello();
  }
  private void printHello() { 
    System.out.println("Hello world");
  } 
}

public class HelloWorld{
  public static void main(String []args){
    Hello h = new Hello();
    h.print();
  }
}

Now if you execute the above program, you won’t get any errors and you will get the string “Hello world” printed on the screen.

Notice that the private method printHello() was only called from within the class and the main program only called the public print() method.

Well, that’s cool and all. You probably knew that already. The main question is why do we need private methods in the first place? and when should we use them?

Let me explain.

When Should You Use Private Methods?

First things first, remember that encapsulation is one of the tenets of object-oriented programming (OOP).

But what is encapsulation really?

In object-oriented programming, encapsulation means hiding the internal implementation of an object from the outside world.

This means that the only way to interact with an object is through the object’s well-defined interface.

In other words, think of an object as a black box that you can interact with through a well-defined interface without having to worry about how the black box is actually implemented.

For example, imagine an object that represents a car, a simple car that only allows you to drive() it by pressing on the gas pedal or stop() it by pressing on the brakes.

In this case, we say that drive() and stop() are the interfaces between you (the user of the car) and the car instance.

You don’t have to worry about how the car actually moves or stops. This is not your problem. This is what the designer of the car cares about. For you, all you want to do is either drive or stop the car. This is what encapsulation is in a nutshell.

That’s cool and all, but let’s not talk about cars and talk about software now.

Let’s answer these two questions.

First: I mentioned that encapsulation hides the object’s implementation from the outside world. What is the outside world?

The outside world is basically other developers who are going to be using the Class that you are designing (it could be you).

It is NOT the end-user who is going to consume your binary (those will have either a user interface or a CLI), but encapsulation (at least in the OOP world) is about developer consumers.

Second: Why is encapsulation useful? why does it matter?

Great question. let’s go back to the car example that we explained earlier.

Imagine you want to replace the engine of your car with a newer, more powerful engine.

Do you (the user of the car) need to learn anything new to be able to drive the car after you had replaced the engine?

Absolutely not. Still, all you need to do is press on the gas pedal and the car will move.

This abstraction is critical in order to write maintainable code.

In other (more realistic) words, when you write your classes and libraries with solid, well-defined interfaces, this allows you (the designer of the class) to change the implementation details at a later time without affecting how other developers interact with your class.

This is because, as long as the interface doesn’t change, then everything is good. Nothing breaks.

However, if you don’t have a well-defined interface, then every time you change your code, you introduce a breaking change that will require all the users of your class to change their code. This is a code maintainability nightmare.

In object-oriented programming, you define this interface by declaring public attributes and methods.

And you achieve encapsulation by declaring private attributes and methods.

With this introduction, now we can start the article 🙂

Attributes and Methods in Python: A Refresher

Before moving to private methods and attributes, let’s start with a simple example.

Let’s construct a basic Class.

class MyClass:
  def __init__(self):
    self.var = 1

  def get_var(self):
    return self.var

In this example, we defined a Class called MyClass.

Inside this Class, within the __init__ method, we defined one attribute var that is initialized with the value 1 and a get_var method that returns the value of var.

Now let’s read and then change the value of var.

>> my_object = MyClass() # Create an instance of MyClass
>> my_object.var   # Call the attribute “var”
1                  # The output is “1”, as expected
>> my_object.get_var()
1
>> my_object.var = 2
>> my_object.var
2
>> my_object.get_var()
2

As you can see, we easily changed the value of var from 1 to 2.

We were able to do that because we have ACCESS to the attribute var from the outside.

But what if we want to hide this attribute from external users?

In the next section, I will teach you how to make this attribute private.

Defining Private Attributes and Methods in Python

To define private attributes or methods in Python, here is what you need to do.

Just prefix the name with a single underscore.

It is that simple.

Now let’s rewrite the above example to make var as well as get_var private.

class MyClass:
  def __init__(self):
    self._var = 1
  def _get_var(self):
    return self._var

Cool. Now let’s see what happens when we try to access this private attribute.

>> my_object = MyClass()  # Create an instance of MyClass
>> my_object._var  # Read _var
1
>> my_object._get_var()
1

Umm, wait! What?

I thought we can’t access private attributes or private methods! How is that possible?

Here me out, I promise I didn’t trick you 🙂

In Python, private access to private attributes (and methods) is not enforced.

So when we say that attributes which start with a single underscore are “private”, that is just a convention. But it is not enforced.

Python has no support for encapsulation. I love encapsulation, but the designers of the language decided not to support it. Oh well.

By saying that encapsulation is not enforced, that doesn’t mean you should access attributes and methods that are prefixed with an underscore.

Don’t do it because you are not supposed to.

In addition to that, if you are designing your own class or library, and you want to hint to your library users that they shouldn’t access specific attributes or methods, prefix the variable names with a single underscore.

Normally, this article should end here. However, there is one more thing I need to talk about before this article is fully complete.

We talked about what happens when you prefix method and attribute names with one underscore, but I am sure you have seen names with two leading underscores (and no trailing underscores).

What do these double leading underscores do?

Prefixing with Double Underscores (Name Mangling)

Let’s go back to our Class, and define our var and get_var(), but this time using double underscores instead of just one.

class MyClass:
  def __init__(self):
    self.__var = 1

  def __get_var(self):
    return self.__var

Now let’s see what happens when we try to access __var like before.

>> my_object = MyClass()
>> my_object.__var

AttributeError: 'MyClass' object has no attribute '__var'

It seems that Python can’t find the attribute __var, although we have just defined it in our Class.

Similarly, if you try to access __get_var(), you get the same error.

>> my_object.__get_var()

AttributeError: 'MyClass' object has no attribute '__get_var'

What’s going on?

One thing we could possibly do to investigate what’s going on is to print the content of dir(my_object)

dir() lists all the attributes (and methods) that an object has

>> dir(my_object)
['_MyClass__get_var', '_MyClass__var',...]

Interesting! It seems like Python renamed the variable __var and __get_var to _MyClass__var and _MyClass__get_var respectively.

This behavior of changing the attribute or method names is called Name Mangling.

Name Mangling makes it harder to access the variables from outside the Class, but it is still accessible through _MyClass__var.

>> my_object._MyClass__var = 3
>> my_object._MyClass__var
3

Similarly, you can access __get_var with its mangled name _MyClass__get_var.

In other words, outside the Class you would need to use the mangled name of the attribute, but inside the Class, you can still access the attribute in the normal way. (look how we accessed __var from inside __get_var())

It is worth mentioning though that some developers mistakenly use name mangling to denote private attributes and methods.

This is not right as this is not what name mangling is used for.

Name mangling is primarily used when you have inherited classes, but this is another story for another time.

What you should do is that you should follow the convention and use a single leading underscore to denote something as private.

Conclusion

To conclude, Python doesn’t support encapsulation. You should still prefix your private attributes and methods with one leading underscore so that users of your class know that they shouldn’t directly access these attributes. On the other hand, if you are the user of a class, don’t access attributes or methods that start with a leading underscore.

Learning Python?

Check out the Courses section!

Featured Posts

  • The Python Learning Path (From Beginner to Mastery)
  • Learn Computer Science (From Zero to Hero)
  • Coding Interview Preparation Guide
  • The Programmer’s Guide to Stock Market Investing
  • How to Start Your Programming Blog?

Are you Beginning your Programming Career?

I provide my best content for beginners in the newsletter.

  • Python tips for beginners, intermediate, and advanced levels.
  • CS Career tips and advice.
  • Special discounts on my premium courses when they launch.

And so much more…

Subscribe now. It’s Free.

Понравилась статья? Поделить с друзьями:
  • Цитаты про праздник день матери
  • Частные праздники это
  • Цитаты про ожидание праздника
  • Частная школа праздник плюс
  • Цитаты про народные праздники