Zanurkuj w Pythonie/Tworzenie oddzielnych funkcji obsługi względem typu węzła: Różnice pomiędzy wersjami
Usunięta treść Dodana treść
Nie podano opisu zmian |
przetłumaczone |
||
Linia 2:
== Tworzenie oddzielnych funkcji obsługi względem typu węzła ==
Trzecim użytecznym chwytem podczas przetwarzania XML-a jest podzielenie kodu w logiczny sposób na funkcje oparte na typie węzła i nazwie elementu. Parsując dokument przetwarzamy rozmaite typy węzłów, które są reprezentowane przez obiekty Pythona. Poziom główny dokumentu jest bezpośrednio reprezentowany przez obiekt
'''Przykład 10.17. Nazwy klas parsowanych obiektów XML'''
Linia 16:
# Załóżmy na moment, że <tt>kant.xml</tt> jest w bieżącym katalogu.
# Jak powiedzieliśmy w ''podrozdziale 9.2'', “Pakiety”, obiekt zwrócony przez parsowany dokument jest
# Ponadto, <tt>__name__</tt> jest wbudowanym atrybutem każdej klasy Pythona. Atrybut ten przechowuje napis, a napis ten nie jest niczym tajemniczym, jest po prostu nazwą danej klasy. (Zobacz ''podrozdział 5.3'', “Definiowanie klas”.)
To fajnie, możemy pobrać nazwę klasy dowolnego węzła XML-a (ponieważ węzły są reprezentowane przez Pythonowe obiekty). Jak można wykorzystać tę zaletę, aby rozdzielić logikę parsowania dla każdego typu węzła? Odpowiedzią jest <tt>getattr</tt>, który pierwszy raz zobaczyliśmy w ''podrozdziale 4.4'', “Pobieranie referencji do obiektu”.
'''
def parse(self, node):
parseMethod = getattr(self, "parse_%s" % node.__class__.__name__) #(1) (2)
parseMethod(node) #(3)
# Od razu, zauważ, że konstruujemy dłuższy napis oparty na nazwie klasy przekazanego węzła (jako argument <tt>node</tt>). Zatem, jeśli przekażemy węzeł <tt>Document</tt>-u, konstruujemy napis <tt>'parse_Document'</tt> itd.
# Teraz, jeśli potraktujemy tę nazwę jako nazwę funkcji, otrzymamy dzięki <tt>getattr</tt> referencję do funkcji.
# Ostatecznie, możemy wywołać tę funkcję, przekazując sam <tt>node</tt> jako argument. Następny przykład przedstawia definicję tych funkcji.
'''
def parse_Document(self, node): #(1)
self.parse(node.documentElement)
def parse_Text(self, node): #(2)
text = node.data
Linia 52:
handlerMethod(node)
# <tt>parse_Document</tt>
# <tt>parse_Text</tt> jest wywoływany tylko na węzłach reprezentujących fragmenty tekstu. Funkcja wykonuje kilka specjalnych operacji związanych z automatycznym wstawianiem dużej litery na początku słowa pierwszego zdania, ale w innym wypadku po prostu dodaje reprezentowany tekst do listy.
# <tt>parse_Comment</tt> jest tylko "przejażdżką"; metoda ta nic nie robi, ponieważ nie musimy się troszczyć o komentarze wstawione w plikach definiującym gramatykę. Pomimo tego, zauważ, że nadal musimy zdefniować funkcję i wyraźnie stwierdzić, żeby nic nie robiła. Jeśli funkcja nie będzie istniała, funkcja <tt>parse</tt> nawali tak szybko, jak napotka się na komentarz, ponieważ będzie próbowała znaleźć nieistniejącą funkcję <tt>parse_Comment</tt>. Definiując oddzielną funkcję dla każdego typu węzła, nawet jeśli nam ta funkcja nie jest potrzebna, pozwalamy ogólnej funkcji parsującej być prostą i krótką.
# Metoda <tt>parse_Element</tt> jest faktycznie funkcją pośredniczącą, opartą na nazwie znacznika elementu. Idea jest taka sama: weź odróżniające się od siebie elementy (elementy, które różnią się nazwą znacznika) i wyślij je do odpowiedniej, odrębnej funkcji. Konstruujemy napis typu <tt>'do_xref'</tt> (dla znacznika <tt><xref></tt>), znajdujemy funkcję o takiej nazwie i wywołujemy ją. I tak dalej, dla każdego innej nazwy znacznika, która zostanie znaleziona, oczywiście w pliku gramatyki (czyli znaczniki <tt><nowiki><p></nowiki></tt>, czy też <tt><choice></tt>).
W tym przykładzie funkcja pośrednicząca <tt>parse</tt> i <tt>parse_Element</tt> po prostu znajdują inne metody w tej samej klasie. Jeśli przetwarzanie jest bardzo złożone (lub mamy bardzo dużo nazw znaczników), powinieneś rozdzielić swój kod na kilka oddzielnych modułów i wykorzystać dynamiczne importowanie, aby zaimportować każdy moduł, a następnie wywołać wszystkie potrzebne nam funkcje. Dynamiczne importowanie zostanie omówione w ''Rozdziale 16'', ''Programowanie funkcyjne''.
<noinclude>
|