2013-05-24 3 views
3

Я в процессе изменения моей KML-библиотеки от python от 2 до 3, и здесь я попал в ловушку. Всякий раз, когда объект KML создается, например, с k = KML(), я получаю следующую ошибку: AttributeError: 'KML' object has no attribute 'doc' со ссылкой на последнюю строку данного кода. Я не могу сказать, что здесь происходит, поскольку я четко определил атрибут. Вот код.Почему я получаю этот атрибут?

import xml.etree.ElementTree as ET 

class KML(ET.Element): 
    def __init__(self): 
     super().__init__("kml") 
     self.doc = ET.Element("Doc") 
     super().append(self.doc)  #error points here 

Любая помощь была бы принята с благодарностью. Благодаря!

+2

Пожалуйста, опубликуйте все сообщение об ошибке со всей трассировкой стека. – BrenBarn

+1

Почему вы вызываете 'super()' дважды? вы хотели сделать 'self.append (...)'? – shx2

+1

@BrenBarn Вы можете просто запустить это в интерпретаторе, и он отбросит ошибку атрибута без реальной трассировки стека. В моем более длинном коде 'k = KML()' вызывается из другого файла, но я не думаю, что это актуально. @ shx2 Я определяю другое 'append' позже в коде, и я хочу запускать' ET.Element', а не 'KML'. – mwillsey

ответ

3

Коренная проблема заключается в том, что xml.etree.ElementTree.Element не предназначен для подкласса.

Я не думаю, что это было намеренно, они просто не ожидали, что кто-нибудь подклассифицирует его, и не думал об этом в любом случае. В Python 3 почти все, что вы пишете на чистом Python, прекрасно подклассифицируется, но класс C-API - это совсем другая история. И если вы посмотрите на xml.etree.ElementTree.Element, это фактически _elementtree.Element, что составляет implemented in C (как тривиальный порт cElementTree из 2.x).

Давайте урезанную реализацию, чтобы увидеть проблему:

import xml.etree.ElementTree as ET 

class KML(ET.Element): 
    def __init__(self, *args): 
     super().__init__('kml') 

k = KML() 
k.doc = 'Doc' 

Это поднимет AttributeError как только вы пытаетесь присвоить k.doc. Зачем? Ну, это вызывает __setattr__, который ни вы, ни ET.Element не реализовали, а реализация по умолчанию для встроенных функций не будет работать, потому что вы ни вы, ни ET.Element не установили себя как изменяемый встроенный класс, поэтому он поднимет AttributeError. Точно так же, как если бы вы пробовали это с помощью ET.Element вместо подкласса или с int.

Но:

class KML(ET.Element): 
    def __init__(self, *args): 
     super().__init__('kml') 
     self.doc = 'Doc' 

k = KML() 

Теперь нет исключений ... но он также не установлен атрибут, как вы можете видеть, пытаясь получить доступ к self.doc сразу после установки его, или k.doc сразу после его создания. Это связано с тем, что исключение создания атрибута проглатывается, когда оно находится внутри __new__ или __init__, что затрудняет отладку проблемы.

Итак, что вы делаете?


Возможна реализация только __setattr__.

Это не будет верно для всех без подклассов дружественных классов C-API, но в этом случае, вы на самом деле иметь надлежащую __dict__, что по умолчанию (object) осуществление __setattr__ и друзей использовать, вы просто надеваете» У меня есть такая реализация.

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

Но я думаю, что это гораздо проще просто написать его в явном виде:

def __setattr__(self, attr, value): 
    self.__dict__[attr] = value 
def __delattr__(self, attr): 
    del self.__dict__[attr] 

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

import _elementtree 
del _elementtree.Element 
import xml.etree.ElementTree as ET 

Наконец, вы можете использовать lxml реализацию ElementTree API, который имеет ряд других преимуществ по сравнению с STDLIB один. Конечно, у него также есть некоторые недостатки, главный из которых заключается в том, что вам необходимо вручную установить его (и это зависит от библиотеки C libxml2, которую также может потребоваться установить).

Смежные вопросы