Пропустить до содержимого

Как использовать переменную_ в Python

[

Одиночные и двойные подчеркивания в именах Python

by Леоданис Посо Рамос 29 ноября 2023 года 1 комментарий Лучшие практики Продвинутые Python

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

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

В этом уроке вы узнаете:

  • О принципах именования Python использующих подчеркивания (_)
  • Различать публичные и непубличные имена с помощью одиночного подчеркивания
  • Использовать двойное подчеркивание для использования мэнглинг имен в классах Python
  • Изучить другие общие использования подчеркивания в именах Python

Публичные интерфейсы и принципы именования в Python

Как программист Python, вы часто будете работать с публичными интерфейсами или интерфейсами прикладного программирования (API). API является типом программного интерфейса, предоставляющего услуги другим частям программы или другим программам.

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

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

Одиночное ведущее подчеркивание в именах Python

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

class MyClass:
def __init__(self):
self._attribute = 10
def _private_method(self):
return self._attribute * 2

В приведенном выше примере, атрибут _attribute и метод _private_method() помечены одиночным ведущим подчеркиванием, что указывает на то, что они не являются частью публичного интерфейса класса MyClass. Эти объекты предназначены только для использования внутри класса и могут быть изменены или удалены в будущих версиях без влияния на внешний код, использующий класс.

Создание публичных и непубличных имен в Python

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

Ниже приведены общие правила:

  • Имена, начинающиеся с одиночного подчеркивания, обычно считаются непубличными и предназначены только для внутреннего использования в пределах модуля или пакета.
  • Имена без подчеркивания считаются публичными и могут быть использованы извне.
  • Имена, начинающиеся с двух подчеркиваний и не заканчивающиеся двумя подчеркиваниями, являются частными (непубличными) и могут использоваться только в пределах класса, в котором они определены.
class MyClass:
def __init__(self):
self.public_attribute = 10 # публичное имя
self._private_attribute = 20 # непубличное имя
def public_method(self):
return self.public_attribute * 2 # доступ к публичному атрибуту
def _private_method(self):
return self._private_attribute * 2 # доступ к непубличному атрибуту

В приведенном выше примере, атрибут public_attribute и метод public_method() являются публичными и могут быть использованы извне класса MyClass. Атрибут _private_attribute и метод _private_method() являются непубличными и предназначены только для внутреннего использования в пределах класса.

Использование публичных и непубличных имен в Python

Доступ к публичным и непубличным именам в Python осуществляется по-разному.

my_object = MyClass()
# Доступ к публичному атрибуту
print(my_object.public_attribute) # Выводит: 10
# Доступ к непубличному атрибуту
print(my_object._private_attribute) # Выводит: 20
# Доступ к публичному методу
print(my_object.public_method()) # Выводит: 20
# Доступ к непубличному методу
print(my_object._private_method()) # Выводит: 40

В данном примере, объект my_object является экземпляром класса MyClass. С использованием обозначения с точкой, мы можем получить доступ к публичным атрибутам и методам объекта, таким как public_attribute и public_method(), а также к непубличным атрибутам и методам, таким как _private_attribute и _private_method().

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

Публичные и непубличные имена в модулях и пакетах

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

Внутренние переменные и константы

my_module.py
_public_variable = 10 # публичная переменная
_internal_variable = 20 # внутренняя переменная
_internal_constant = 30 # внутренняя константа

В приведенном выше примере переменная _public_variable считается публичной и может быть использована внешним кодом. Переменные _internal_variable и _internal_constant являются внутренними и предназначены только для использования внутри модуля my_module.

Вспомогательные функции

my_module.py
_public_function():
return _private_function() * 2 # доступ к внутренней функции
def _private_function():
return 10 # внутренняя функция

В приведенном выше примере функция _public_function() является публичной и может быть использована внешним кодом. Функция _private_function() является внутренней и предназначена только для использования внутри модуля my_module.

Непубличные модули

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

Для создания непубличного модуля, просто добавьте _ перед именем модуля:

_helper_module.py
def helper_function():
return 10 # внутренняя функция
my_module.py
import _helper_module
print(_helper_module.helper_function()) # Выводит: 10

В данном примере модуль _helper_module является непубличным и доступен только из модуля my_module.

Импортирование через подстановочные символы и непубличные имена

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

from my_module import *
print(_internal_variable) # NameError: name '_internal_variable' is not defined

В данном примере, при использовании подстановочного символа *, публичные имена из модуля my_module импортируются в текущую область видимости, но непубличные имена, такие как _internal_variable, нет. Попытка обратиться к непубличному имени приведет к ошибке NameError.

Класс с непубличными членами

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

Непубличные атрибуты

class MyClass:
def __init__(self):
self.public_attribute = 10 # публичный атрибут
self._private_attribute = 20 # непубличный атрибут
def _private_method(self):
return self._private_attribute * 2 # доступ к непубличному атрибуту

В приведенном выше примере, атрибут _private_attribute является непубличным и доступен только внутри класса MyClass. Он не доступен извне класса.

Непубличные методы

class MyClass:
def __init__(self):
self.public_attribute = 10 # публичный атрибут
def public_method(self):
return self._private_method() * 2 # доступ к непубличному методу
def _private_method(self):
return self.public_attribute * 2 # внутренний метод

В приведенном выше примере метод _private_method() является непубличным и доступен только внутри класса MyClass. Он не может быть вызван извне класса.

Двойное ведущее подчеркивание в классах: Мэнглинг имен в Python

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

Понимание мэнглинга имени

class BaseClass:
def __init__(self):
self.__private_attribute = 10
def __private_method(self):
return self.__private_attribute * 2
class ChildClass(BaseClass):
def __init__(self):
super().__init__()
self.__private_attribute = 20
def __private_method(self):
return self.__private_attribute * 3

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

В результате, при попытке вызвать приватный атрибут __private_attribute или приватный метод __private_method в экземпляре класса ChildClass, будет вызван преобразованный метод ChildClass.__private_attribute или ChildClass.__private_method.

Использование мэнглинга имени в наследовании

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

my_object = ChildClass()
print(my_object._BaseClass__private_attribute) # Выводит: 10
print(my_object._BaseClass__private_method()) # Выводит: 20

В данном примере мы создаем экземпляр класса ChildClass и вызываем приватный атрибут __private_attribute и приватный метод __private_method с использованием исправленного имени BaseClass.__private_attribute и BaseClass.__private_method. Таким образом, мы обращаемся к унаследованным атрибутам и методам, которые были защищены от случайной перезаписи в классе ChildClass.

Подчеркивания в конце имен в Python

В Python иногда используются подчеркивания в конце имени объекта для избежания конфликтов с зарезервированными словами или именами объектов.

class MyClass:
def __init__(self):
self.open_ = 10 # избежание конфликта с ключевым словом
self.name_ = "John" # избежание конфликта с именем объекта

В приведенном выше примере переменные open_ и name_ оканчиваются на подчеркивание, чтобы избежать конфликтов с зарезервированным словом open и именем объекта name.

Дандер (Dunder) имена в Python

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

Ниже приведены некоторые из наиболее распространенных дандер методов:

  • __init__: Конструктор класса. Вызывается при создании нового объекта класса.
  • __str__: Возвращает строковое представление объекта. Вызывается при вызове встроенной функции str().
  • __repr__: Возвращает строковое представление объекта, которое репрезентативно для использования при отладке.
  • __len__: Возвращает длину объекта. Вызывается при вызове встроенной функции len().
class MyClass:
def __init__(self, name):
self.name = name
def __str__(self):
return f"Hello, {self.name}!"
def __repr__(self):
return f"MyClass({self.name})"
def __len__(self):
return len(self.name)
my_object = MyClass("John")
print(str(my_object)) # Выводит: Hello, John!
print(repr(my_object)) # Выводит: MyClass(John)
print(len(my_object)) # Выводит: 4

В данном примере класс MyClass определяет методы __str__(), __repr__() и __len__(), чтобы при вызове функций str(), repr() и len() можно было получить соответствующие значения.

Другие использования подчеркиваний в Python

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

  • Игнорирование значений: вследствие того, что подчеркивания не используются в дальнейшем, они могут использоваться для игнорирования определенных значений или переменных.
name, _ = get_name() # игнорирование второго значения
  • Избегание конфликтов имен: подчеркивания могут использоваться для предотвращения конфликтов имен с другими переменными или функциями в вашем коде.
open = 10 # Интерпретатор Python не ругается, но это может вызвать проблемы
open_ = 10 # безопасное имя переменной
  • Визуальное выделение: подчеркивания могут использоваться для визуального выделения определенных значений или переменных в вашем коде.
MAX_NUMBER = 100
_MIN_NUMBER = 0

Заключение

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