Какая польза от искажения имени?

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

Существуют ли какие-либо конкретные случаи, когда эта функция требуется, или она просто перенесена из Java и C++?

Опишите вариант использования, в котором следует использовать изменение имени Python, если таковой имеется?

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


person cmcginty    schedule 21.07.2009    source источник


Ответы (4)


Отчасти это сделано для предотвращения случайного доступа к внутренним атрибутам. Вот пример:

В вашем коде, который является библиотекой:

class YourClass:
    def __init__(self):
        self.__thing = 1           # Your private member, not part of your API

В моем коде, в котором я наследую класс вашей библиотеки:

class MyClass(YourClass):
    def __init__(self):
        # ...
        self.__thing = "My thing"  # My private member; the name is a coincidence

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

person RichieHindle    schedule 21.07.2009
comment
ИМО, YourClass должен определять _thing вместо __thing. Это позволит MyClass получить к нему доступ. Во-вторых, я вижу преимущество использования '__thing' в MyClass, если есть опасения, что реализация YourClass изменится. Единственная проблема заключается в том, что если кто-то хочет создать подкласс MyClass, то вы усложнили им доступ к «MyClass.__thing». Такое ощущение, что вы жертвуете повторным использованием в будущем, чтобы защититься от воображаемой проблемы. Нет? - person cmcginty; 22.07.2009
comment
@Casey: Вы правы в том, что есть переменные-члены, которые вы хотите сделать видимыми для подклассов, и те, которые вы называете одним символом подчеркивания. Вы бы сделали их protected на C++. Но есть также члены, которые вы не хотите видеть для подклассов, потому что они являются частью частной реализации вашего класса (и, как вы говорите, они подлежат изменению реализации). ). Именно для них и предназначено искажение имен. Это не воображаемая проблема; На самом деле я сделал именно то, о чем говорю, с библиотекой, которая использовала одиночное подчеркивание, а не двойное для частного члена. - person RichieHindle; 22.07.2009
comment
@RichieHindle: Точно. За исключением того, что это ВНЕШНИЙ доступ. ;) Подкласс здесь рассматривается как внешний. - person Lennart Regebro; 22.07.2009
comment
Разве детали частной реализации не произвольны? Если я создавал базовый класс для распространения по всему миру и не могу представить себе все возможные сценарии использования, то как я могу надежно выбрать, какие атрибуты защищены, а какие закрыты. В конце концов, всегда будет причина, по которой кому-то может понадобиться доступ к переменной для расширения/улучшения класса. Использование искаженных имен атрибутов не принесет пользы и просто заставит следующего человека исправить их. - person cmcginty; 23.07.2009
comment
Я думаю, нам придется согласиться, чтобы не согласиться с этим. ИМХО, хорошо написанный библиотечный класс имеет два API: один для непосредственных пользователей этого класса, а другой — для классов, которые его наследуют. По соглашению первый использует имена без символов подчеркивания, а второй может обращаться к именам с одним подчеркиванием. Но класс по-прежнему имеет право скрывать некоторые детали своей реализации — те, которые не являются частью ни одного из API, — от обоих типов пользователей. В противном случае изменения внутренней работы класса становятся почти невозможными, потому что вы ничего не можете знать о том, как ваши члены используются подклассами. - person RichieHindle; 23.07.2009
comment
Пожалуйста, не могли бы вы привести пример - мое случайное повторное использование вашего имени сломало бы вашу библиотеку. Я пытаюсь понять это. - person variable; 05.12.2019
comment
Наследование от класса и случайное повторное использование частного имени в качестве совпадения примерно так же вероятно, как случайное повторное использование искаженного имени _YourClass__thing. Я действительно не понимаю, как это позволяет избежать этой проблемы, просто перемещает ее немного вправо. Если это было настоящим намерением, почему искаженное имя не является случайным UUID4 или чем-то еще? - person wim; 05.12.2019

Из PEP 8:

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

(выделение добавлено)

person too much php    schedule 21.07.2009

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

class Parent:
    def __init__(self):
       self.__help("will take child to school")
    def help(self, activities):
        print("parent",activities)

    __help = help   # private copy of original help() method

class Child(Parent):
    def help(self, activities, days):   # notice this has 3 arguments and overrides the Parent.help()
        self.activities = activities
        self.days = days
        print ("child will do",self.activities, self.days)


# the goal was to extend and override the Parent class to list the child activities too
print ("list parent & child responsibilities")
c = Child()
c.help("laundry","Saturdays")
person grepit    schedule 09.09.2018
comment
Это интересно, но нельзя ли использовать Parent.help() в Parent.__init__, не определяя __help? - person NirIzr; 03.06.2019
comment
Да, вы также можете сделать Parent.help(self, "will take child to school"). Я думаю, что смысл этого ответа в том, чтобы продемонстрировать, что он действительно позволяет родительскому классу отказаться от использования методов (или атрибутов), переопределенных в подклассе. - person wim; 05.12.2019

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

person Lennart Regebro    schedule 21.07.2009
comment
Я упомянул об этом в исходном вопросе. Вы говорите, что не согласны? - person cmcginty; 22.07.2009
comment
Я говорю, что это причина. Таким образом, у вас не будет случайных конфликтов имен при создании подкласса. - person Lennart Regebro; 22.07.2009