Объект «ChildClassName» не имеет атрибута «_ParentClassName» [дубликат]

Попробуйте:

<([^\s]+)(\s[^>]*?)?(?<!/)>

Он похож на ваш, но последний > не должен быть после косой черты, а также принимает h1.

1022
задан 8 revs, 6 users 67% 12 February 2017 в 15:15
поделиться

14 ответов

Single Underscore

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

Чтобы процитировать PEP-8 :

_single_leading_underscore: слабый индикатор «внутреннего использования». Например. from M import * не импортирует объекты, чье имя начинается с символа подчеркивания.

Double Underscore (Name Mangling)

Из документов Python :

Любой идентификатор формы __spam (по крайней мере два ведущих символа подчеркивания, не более одного подчеркивания подчеркивания) заменяется на текст на _classname__spam, где classname - это текущее имя класса с ведущими подчеркивание (ы) раздели. Это манипулирование выполняется без учета синтаксической позиции идентификатора, поэтому его можно использовать для определения переменных класса, класса, переменных, хранящихся в глобальных переменных, и даже переменных, хранящихся в экземплярах. частный для этого класса на экземплярах других классов.

И предупреждение с той же страницы:

Назначение имени предназначено, чтобы дать классам простой способ определить «частные» переменные экземпляра и методы без приходится беспокоиться о переменных экземпляра, определяемых производными классами, или обманывать переменные экземпляра кодом вне класса. Обратите внимание, что правила манипуляции предназначены главным образом для предотвращения несчастных случаев; [7]

Пример

>>> class MyClass():
...     def __init__(self):
...             self.__superprivate = "Hello"
...             self._semiprivate = ", world!"
...
>>> mc = MyClass()
>>> print mc.__superprivate
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: myClass instance has no attribute '__superprivate'
>>> print mc._semiprivate
, world!
>>> print mc.__dict__
{'_MyClass__superprivate': 'Hello', '_semiprivate': ', world!'}
922
ответ дан Honest Abe 15 August 2018 в 23:13
поделиться
  • 1
    Что делать, если имя переменной указано с 2 символами подчеркивания, которые не входят в класс? Это просто нормальная переменная, затем правильно? – Dhruv Ramani 27 July 2015 в 08:10
  • 2
    в чем смысл простого __ двойного подчеркивания как имени переменной? как a, __ = foo() – Clayton 3 December 2015 в 07:24
  • 3
    Этот ответ чрезвычайно вводит в заблуждение, поскольку он заставляет читателя полагать, что dunderscore используется для создания атрибутов экземпляра «superprivate». Это not случай, как , описанный здесь Раймондом Хеттингером, который прямо указывает, что dunderscore неверно используется для обозначения членов private, в то время как он был разработан как противоположный частному , – Markus Meskanen 17 May 2016 в 10:01
  • 4
    @MarkusMeskanen Я не согласен, ответ явно указывает на использование dunderscore для создания экземпляров переменных класса и методов класса. Хотя dunderscore был разработан таким образом, чтобы эти методы и переменные легко перезаписывались подклассами (делая их общедоступными), использование dunderscore сохраняет частный экземпляр для использования в этом классе. – arewm 5 July 2016 в 15:11
  • 5
    @MarkusMeskanen: свобода заключается в том, что подклассы используют те же имена, что и суперкласс, не сбивая суперкласс - в других словах имена суперклассов становятся частными для себя. – Ethan Furman 15 July 2016 в 17:48

Получение фактов _ и __ довольно легко; другие ответы выражают их довольно хорошо. Использование намного сложнее определить.

Вот как я это вижу:

_

Следует использовать, чтобы указать, что функция не предназначена для публичного использования, например, для API. Это и ограничение импорта заставляют его вести себя так же, как internal в c #.

__

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

==>

Если вы хотите указать, что что-то не для общего пользования, но оно должно действовать как protected использовать _. Если вы хотите указать, что что-то не для общего пользования, но оно должно действовать как private use __.

Это также цитата, которая мне очень нравится:

Проблема заключается в том, что автор класса может законно думать, что «это имя атрибута / метода должно быть закрытым, доступным только из этого определения класса» и использовать соглашение __private. Но в дальнейшем пользователь этого класса может сделать подкласс, который законно нуждается в доступе к этому имени. Поэтому либо надкласс должен быть изменен (что может быть сложно или невозможно), либо код подкласса должен использовать вручную искаженные имена (что в лучшем случае является уродливым и хрупким).

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

0
ответ дан 2 revs 15 August 2018 в 23:13
поделиться

._variable является полуприватым и подразумевается только для соглашения

.__variable часто неправильно считается суперприватом, в то время как фактическое значение просто для предотвращения случайного доступа [1]

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

Вы можете получить доступ к .__mangled переменным, если вы отчаянно хотите. Двойное подчеркивание просто намещает или переименовывает переменную в нечто вроде instance._className__mangled

Пример:

class Test(object):
    def __init__(self):
        self.__a = 'a'
        self._b = 'b'

>>> t = Test()
>>> t._b
'b'

t._b доступен, поскольку он скрыт только по соглашению

>>> t.__a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Test' object has no attribute '__a'

t .__ a не найден потому, что он больше не существует из-за namemangling

>>> t._Test__a
'a'

. При доступе к instance._className__variable вместо имени двойного подчеркивания вы можете получить доступ к скрытое значение

177
ответ дан 2 revs, 2 users 93% 15 August 2018 в 23:13
поделиться
  • 1
    Кто узнал что-то новое сегодня? меня. – coderatchet 4 October 2016 в 21:38
  • 2
    Ваш ответ помог мне очень хорошо понять название. Благодарю. – Larynx 23 November 2016 в 04:22
  • 3
    но как насчет того, если «__ a» была переменной класса, тогда вы не можете получить к ней доступ даже с инструкциями из документов python .. – Vitaliy Terziev 6 July 2017 в 07:07

Подчеркивание (_) в Python

Ниже приведены разные места, где _ используется в Python:

Single Underscore:

  • In Interpreter
  • После имени
  • Перед именем

Double Underscore:

  • __ leading_double_underscore
  • ] before_after
  • Single Underscore

В интерпретаторе:

_ возвращает значение последнего выполненного выражения в Python REPL ]

>>> a = 10
>>> b = 10
>>> _
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_' is not defined
>>> a+b
20
>>> _
20
>>> _ * 2
40
>>> _
40
>>> _ / 2
20

Для игнорирования значений:

Несколько раз мы не хотим, чтобы возвращаемые значения в это время присваивали эти значения wnderscore. Он использовался как переменная throwaway.

# Ignore a value of specific location/index
for _ in rang(10)
    print "Test"

# Ignore a value when unpacking
a,b,_,_ = my_method(var1)

После имени

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

Пример:

>>> class MyClass():
...     def __init__(self):
...             print "OWK"

>>> def my_defination(var1 = 1, class_ = MyClass):
...     print var1
...     print class_

>>> my_defination()
1
__main__.MyClass
>>>

Перед именем

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

Здесь префикс имени by underscore рассматривается как непубличный. Если указать из Import *, все имя начинается с _, то не будет импортироваться.

Python не указывает действительно закрытый, так что это могут быть вызовы непосредственно из других модулей, если они указаны во всех, Мы также называем это слабым Частный

class Prefix:
...     def __init__(self):
...             self.public = 10
...             self._private = 12
>>> test = Prefix()
>>> test.public
10
>>> test._private
12
Python class_file.py

def public_api():
    print "public api"

def _private_api():
    print "private api"

Вызов файла из REPL

>>> from class_file import *
>>> public_api()
public api

>>> _private_api()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name '_private_api' is not defined

>>> import class_file
>>> class_file.public_api()
public api
>>> class_file._private_api()
private api
Double Underscore(__)

__ leading_double_underscore

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

class Myclass():
    def __init__(self):
        self.__variable = 10

Вызов из REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__variable
Traceback (most recent call last):
File "", line 1, in
AttributeError: Myclass instance has no attribute '__variable'
nce has no attribute 'Myclass'
>>> obj._Myclass__variable
10

В Mangling интерпретатор python измените имя переменной на ___. Таким образом, множественное время используется как частный член, потому что другой класс не может напрямую обращаться к этой переменной. Основной целью __ является использование переменной / метода только в классе. Если вы хотите использовать его вне класса, вы можете сделать общедоступным api

class Myclass():
    def __init__(self):
        self.__variable = 10
    def func(self)
        print self.__variable

Вызов из REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.func()
10

__ BEFORE_AFTER __

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

Python предоставляет это соглашение для различения определяемой пользователем функции с функцией модуля

class Myclass():
    def __add__(self,a,b):
        print a*b

. Вызов из REPL

>>> import testFile
>>> obj = testFile.Myclass()
>>> obj.__add__(1,2)
2
>>> obj.__add__(5,2)
10

Ссылка

10
ответ дан 2 revs, 2 users 98% 15 August 2018 в 23:13
поделиться

Одиночное подчеркивание в начале:

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

class BaseForm(StrAndUnicode):

    def _get_errors(self):
        "Returns an ErrorDict for the data provided for the form"
        if self._errors is None:
            self.full_clean()
        return self._errors

    errors = property(_get_errors)

фрагмент кода, взятый из исходного кода django (django / forms / forms.py). Это означает, что ошибки являются свойством, и это часть модуля, но метод, который это свойство вызывает, _get_errors, является «закрытым», поэтому вы не должны обращаться к нему.

Два подчеркивания в начале:

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

class A(object):
    def __test(self):
        print "I'm test method in class A"

    def test(self):
        self.__test()

a = A()
a.test()

Выход:

$ python test.py
I'm test method in class A

Теперь создайте подкласс B и выполните настройку для метода __test

class B(A):
    def __test(self):
        print "I'm test method in class B"

b = B()
b.test()

Выход будет be ....

$ python test.py
I'm test method in class A

Как мы видели, A.test () не называл методы B .__ test (), как и следовало ожидать. Но на самом деле это правильное поведение для __. Поэтому, когда вы создаете метод, начинающийся с __, это означает, что вы не хотите, чтобы кто-либо мог его переопределить, он будет доступен только изнутри собственного класса.

Два подчеркивания в начале и в начале в конце:

Когда мы видим такой метод, как __this__, не называйте его. Потому что это означает, что это метод, который питон звонит, а не вы. Давайте посмотрим:

>>> name = "test string"
>>> name.__len__()
11
>>> len(name)
11

>>> number = 10
>>> number.__add__(40)
50
>>> number + 50
60

Всегда есть оператор или нативная функция, которая вызывает эти магические методы. Иногда это просто вызовы с пинтовыми вызовами в определенных ситуациях. Например, __init__() вызывается, когда объект создается после вызова __new__() для сборки экземпляра ...

Давайте возьмем пример ...

class FalseCalculator(object):

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

    def __add__(self, number):
        return self.number - number

    def __sub__(self, number):
        return self.number + number



number = FalseCalculator(20)
print number + 10      # 10
print number - 20      # 40

Для подробнее Руководство по PEP-8 поможет больше.

Здесь вы найдете более магические методы в python. https://github.com/RafeKettler/magicmethods/blob/master/magicmethods.pdf

86
ответ дан 7 revs, 7 users 94% 15 August 2018 в 23:13
поделиться

Отличные ответы до сих пор, но некоторые лакомые кусочки отсутствуют. Единственное главное подчеркивание - это не совсем только соглашение: если вы используете from foobar import *, а модуль foobar не определяет список __all__, имена, импортированные из модуля, не включают те с лидирующим подчеркиванием. Предположим, что это в основном конвенция, поскольку этот случай является довольно неясным углом; -).

Соглашение с ведущим-подчеркиванием широко используется не только для private , но также и то, что C ++ вызывал protected - например, имена методов, которые полностью предназначены для переопределения подклассами (даже те, которые должны быть переопределены, поскольку в базовом классе они raise NotImplementedError! -) часто являются именами одного и того же нижнего подчеркивания, указывающие на код с использованием экземпляров этого класса (или подклассов), в котором упомянутые методы не предназначены для прямого вызова.

Например, для создайте поточно-безопасную очередь с другой дисциплиной очередей, чем FIFO, один импортирует Queue, subclasses Queue.Queue и переопределяет такие методы, как _get и _put; «клиентский код» никогда не вызывает эти методы («крючок»), а скорее («организующие») общедоступные методы, такие как put и get (это известно как шаблон дизайна Template Method ] - см., например, здесь для интересной презентации, основанной на видеоролике моего разговора по этому вопросу, с добавлением кратковременных расшифровки стенограммы).

268
ответ дан Alex 15 August 2018 в 23:13
поделиться
  • 1
    Итак, как вы решаете, использовать ли _var_name или использовать var_name + исключая его из __all__? – endolith 30 January 2017 в 16:39
  • 2
    @endolith Используйте знак подчеркивания, чтобы сообщить читателю вашего кода, что они, вероятно, не должны его использовать (например, потому что вы можете изменить его в версии 2.0 или даже 1.1); используйте явный __all__ всякий раз, когда вы хотите сделать модуль from spam import * дружественным (в том числе и интерактивным интерпретатором). Поэтому большую часть времени ответ как . – abarnert 25 April 2018 в 17:15
  • 3
  • 4

«Частные» переменные экземпляра, к которым невозможно получить доступ, кроме как внутри объекта, не существует в Python. Тем не менее, существует соглашение, за которым следует большинство кода Python: имя с префиксом подчеркивания (например, _spam) должно рассматриваться как непубличная часть API (будь то функция, метод или элемент данных) , Он должен рассматриваться как деталь реализации и может быть изменен без предварительного уведомления.

ссылка https://docs.python.org/2/tutorial/classes.html#private-variables-and-class -локальных ссылка

3
ответ дан aptro 15 August 2018 в 23:13
поделиться
  • 1
    _ гораздо более похож на, например, внутренний в c #, а затем на частный. Двойное подчеркивание это гораздо больше похоже на личное, а подчеркивание - личное, я бы сказал. – Invader 4 November 2017 в 01:38

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

class PrivateVarC(object):

    def get_x(self):
        pass

    def set_x(self, val):
        pass

    rwvar = property(get_p, set_p)  

    ronly = property(get_p) 

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

7
ответ дан Dev Maha 15 August 2018 в 23:13
поделиться

Вот простой иллюстративный пример того, как свойства двойного подчеркивания могут влиять на унаследованный класс. Итак, со следующей настройкой:

class parent(object):
    __default = "parent"
    def __init__(self, name=None):
        self.default = name or self.__default

    @property
    def default(self):
        return self.__default

    @default.setter
    def default(self, value):
        self.__default = value


class child(parent):
    __default = "child"

, если вы затем создадите дочерний экземпляр в REPL python, вы увидите ниже

child_a = child()
child_a.default            # 'parent'
child_a._child__default    # 'child'
child_a._parent__default   # 'parent'

child_b = child("orphan")
## this will show 
child_b.default            # 'orphan'
child_a._child__default    # 'child'
child_a._parent__default   # 'orphan'

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

1
ответ дан Marc 15 August 2018 в 23:13
поделиться

__foo__: это просто соглашение, способ использования системы Python для имен, которые не будут конфликтовать с именами пользователей.

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

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

В мире Python нет другой формы подчеркивания.

Нет никакой разницы между классом, переменной, глобальным и т. д. эти соглашения.

246
ответ дан Ned Batchelder 15 August 2018 в 23:13
поделиться
  • 1
    Просто натолкнулся на __foo и любопытно. Как он может перекрываться с похожими именами методов с другими классами? Я имею в виду, что вы все равно должны получить к нему доступ, как instance.__foo() (если он не был переименован интерпретатором), правильно? – Bibhas Debnath 9 May 2013 в 09:03
  • 2
    Этот парень утверждает, что from module import * не импортирует объекты с префиксами с подчеркиванием. Поэтому _foo - это не просто соглашение. – dotancohen 13 June 2013 в 14:28
  • 3
    @Bibhas: если класс B подклассы класса A и оба реализуют foo(), то B.foo() переопределяет .foo(), унаследованный от A. Экземпляр B будет иметь доступ только к B.foo(), кроме как через super(B).foo(). – naught101 26 January 2015 в 04:11

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

Двойные ведущие и завершающие символы подчеркивания используются для встроенных методов, таких как __init__, __bool__ и т. д.

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

5
ответ дан SilentGhost 15 August 2018 в 23:13
поделиться

Иногда у вас есть то, что кажется кортежем с ведущим подчеркиванием, как в

def foo(bar):
    return _('my_' + bar)

. В этом случае происходит то, что _ () является псевдонимом для функции локализации, которая работает текст, чтобы перевести его на правильный язык и т. д. на основе языка. Например, Sphinx делает это, и вы найдете среди импорта

from sphinx.locale import l_, _

и в sphinx.locale, _ () назначается как псевдоним некоторой функции локализации.

15
ответ дан Tim D 15 August 2018 в 23:13
поделиться

Ваш вопрос хорош, речь идет не только о методах. Функции и объекты в модулях обычно имеют префикс с одним символом подчеркивания и могут быть префиксными двумя.

Но имена __double_underscore, например, не обрабатываются именами в модулях. Случается, что имена, начинающиеся с одного (или более) подчеркивания, не импортируются, если вы импортируете все из модуля (из импорта модуля *), а также имена, указанные в справке (модуль).

3
ответ дан u0b34a0f6ae 15 August 2018 в 23:13
поделиться
  • 1
    Кроме того, имена, начинающиеся с одного или нескольких символов подчеркивания, которые имеют два или более конечных подчеркивания, снова ведут себя как любое другое имя. – Bentley4 7 April 2012 в 16:19
0
ответ дан 2 revs 29 October 2018 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: