AttributeError, утверждающее, что явно существующий атрибут не существует. Почему я получаю это? (Проблема с подклассами)

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

line 154, in __ExtINT
    DebugVar=Self.__Preset # Originally, I had Self.__Preset directly in an if statement. I added this line and put DebugVar in the if statement, so I could be sure what was causing the error.
AttributeError: '__Readitem' object has no attribute '_ReadItem__Preset'

Я был уверен, что это было установлено в функции __init__, и потратил некоторое время, пытаясь понять, почему я получаю эту ошибку. Когда я обнаружил, что python использует словарь для хранения всех своих переменных, я поставил print(Self.__dict__) перед строкой, вызвавшей ошибку, чтобы я мог видеть, какие атрибуты сделал существуют. Я был удивлен, увидев в словаре , '_Readitem__Preset': True}. Почему тогда в ошибке говорится, что его не существует?

Я попробовал DebugVar=Self.__dict__['_Readitem__Preset'] вместо DebugVar=Self.__Preset и получил:

line 154, in __ExtINT
    DebugVar=Self.__dict__['_Readitem__Preset']
KeyError: '_Readitem__Preset'

Затем я попытался поставить self.__Preset=False сразу после __init__, чтобы быть уверенным, что он действительно существует.

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

Есть ли кто-нибудь, кто сам сталкивался с этой проблемой или имеет какое-либо представление о том, почему это происходит?

ReadItem! = Readitem, обратите внимание на заглавную I. (в первом исключении)

Rohi 02.05.2018 16:35

Тогда почему «я» может относиться к другому случаю? Помните, я написал только «Я» (изначально). Почему мой класс будет отображаться с разными именами? @Rohi

Super S 02.05.2018 17:32

На всякий случай, не могли бы вы указать свои переменные без искажения (т.е. без «__»).

Rohi 02.05.2018 17:36

Укажите переменную как Preset, а не как __Preset. Немного сложно отладить без всего кода, но я думаю, что это может быть проблема, связанная с искажением имени. Попробуйте и дайте мне знать. И я знаю, что это может быть далеко не все, но взгляните на это: stackoverflow.com/questions/20261517/…, опять же, это немного сложно, не видя всего кода.

Rohi 02.05.2018 17:52

@Rohi Спасибо, что заметили неправильный регистр для "I". Теперь я смог исправить код. По какой-то причине для моего атрибута использовался неправильный префикс. В качестве ответа я объяснил ошибку, но до сих пор не уверен, почему использовался неправильный префикс.

Super S 04.05.2018 11:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
435
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это было больно.

Мне удалось несколько разобраться, почему я получаю ошибку, и исправить свой код. Вот описание того, как я получил ошибку и как я ее преодолел на случай, если кому-то интересно, или получить эту ошибку самостоятельно:

В моем коде есть класс, который по сути является категорией. Он хранит атрибуты, например, предопределен ли он или определен пользователем, содержит ли он какие-либо подкатегории, любые подкатегории, которые он может иметь, и т. д. Эти подкатегории представляют собой список, который содержит больше экземпляров этого класса. Затем мне пришлось создать другую его версию, которая записывает в файл при инициализации. Если бы я сделал то же самое, что и раньше, он бы записал данные, которые должны быть записаны в файл только один раз, в файл несколько раз. Я решил создать «подкласс», который будет работать немного иначе, чем его основной класс. Вот простой код, показывающий структуру, которую я пытался достичь:

class Main():
    class __Sub():
        def __init__(self,file,dat):
            if isinstance(dat,tuple):
                self.__trace=()
                if False in (isinstance(i,int)for i in dat):self.__trace+=tuple((Main.__Sub(file,i),)for i in dat)
                else:
                    self.__trace=dat
                    file.write(bytes(dat))
            else:
                self.__trace=(dat,)
                file.write(bytes([dat]))
    def __init__(self,file,dat):
        File=open(file,"wb")
        self.__trace=()
        self.__trace+=tuple((Main.__Sub(File,i),)for i in dat)
        File.close()
Main(input("Enter file name: "),(4,8,((32,71),255)))

Как я уже сказал в вопросе, python хранит свои переменные в словаре, и вы можете проверить атрибуты объекта с помощью .__dict__. Если вы сделаете это, вы увидите, что каждый атрибут имеет имя своего класса в качестве префикса. Если вы попытаетесь запустить приведенный выше код, по какой-то причине он выйдет из строя, потому что он пытается использовать неправильный префикс для поиска атрибута.

Мое решение заключалось в том, чтобы удалить подкласс и сделать это с моим кодом:

class Main():
    def __init__(self,file,dat):
        if "BadPractice" in globals():
            if isinstance(dat,tuple):
                self.__trace=()
                if False in (isinstance(i,int)for i in dat):self.__trace+=tuple((Main(file,i),)for i in dat)
                else:
                    self.__trace=dat
                    file.write(bytes(dat))
            else:
                self.__trace=(dat,)
                file.write(bytes([dat]))
        else:
            global BadPractice
            BadPractice=None
            self.__trace=()
            self.__trace+=tuple((Main(file,i),)for i in dat)
            file.close()
Main(open(input("Enter file name: "),"wb"),(4,8,((32,71,),255,),),)

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

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

Rohi 04.05.2018 18:49

Другие вопросы по теме