Zanurkuj w Pythonie/Wprowadzanie do dialect.py: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Piotr (dyskusja | edycje)
mNie podano opisu zmian
Nie podano opisu zmian
Linia 1:
<!-- Jeśli chcesz tłumaczyć, usuń poniższy komentarz i zostaw samo {{WEdycji}} -->
<!-- {{WEdycji}} -->
<!-- {{Python/Do tłumaczenia}} -->
 
== IntroducingWprowadzenie do dialect.py ==
 
<tt>Dialectizer</tt> is ajest simpleprostym (andi sillyniezbyt mądrym) descendantpotomkiem ofklasy <tt>BaseHTMLProcessor</tt>. ItDokonuje runson blocksna ofbloku texttekstu throughserii a series of substitutionspodstawień, butale itwszystko makesco sureznajduje thatsię anythingwewnątrz within abloku <nowiki><pre>...</pre></nowiki> block passes throughpozostawia unalteredniezmienione.
 
ToAby handleobsłużyć thebloki <nowiki><pre></nowiki> blocks,definiujemy youw define two methods inklasie <tt>Dialectizer</tt> metody: <tt>start_pre</tt> andi <tt>end_pre</tt>.
 
'''ExamplePrzykład 8.17. HandlingObsługa specificokreślonych tagsznaczników'''
 
def start_pre(self, attrs): #(1)
Linia 19:
self.verbatim -= 1 #(6)
 
# <tt>start_pre</tt> isjest calledwołana everyza timekażdym razem, gdy <tt>SGMLParser</tt> findsznajdzie aznacznik <nowiki><pre></nowiki> tagw in theźródle HTML source-a. (InZa achwilę minutezobaczysz dokładnie, you'll see exactlyjak howto thissię happensdzieje.) TheTa methodmetoda takesprzyjmuje ajeden single parameter,parametr: <tt>attrs</tt>, which contains the attributesktóry ofzawiera theatrybuty tagznacznika (ifjeśli anyjakieś są). <tt>attrs</tt> isjest alistą listkrotek ofpostaci keyklucz/value tupleswartość, justtaką likesamą unknown_starttagjaką takesprzyjmuje <tt>unknown_starttag</tt>.
# InW themetodzie reset method, youinicjalizujemy initializeatrybut, aktóry datasłuży attribute that serves as ajako counterlicznik forznaczników <nowiki><pre></nowiki> tags. EveryZa timekażdym yourazem, hitgdy anatrafiamy na znacznik <nowiki><pre></nowiki> tag, youzwiększamy incrementlicznik, thenatomiast counter;gdy everynatrafiamy timena you hit aznacznik <nowiki></pre></nowiki> tag, you'll decrement thezmniejszamy counterlicznik. (YouMoglibyśmy couldteż justużyć usepo thisprostu asflagi ai flagustawiać and setna it towartość 1, and reset ita tonastępnie 0, butale it'snasz justsposób asjest easyrównie to do it this wayłatwy, and thisa handlesdodatkowo theobsługujemy odddziwny (butale possiblemożliwy) caseprzypadek ofzagnieżdżonych nestedznaczników <nowiki><pre></nowiki> tags.) In a minute, you'll see howZa thischwilę counterzobaczysz isjak putmożna towykorzystać goodten uselicznik.
# That'sTo it,jest that'sta thejedyna onlyakcja specialwykonywana processingdla you do forznaczników <nowiki><pre></nowiki> tags. NowPrzekazujemy youtu passlistę theatrybutów list of attributes alongdo tometody unknown_starttag, soaby it can dowykonała theona defaultdomyślną processingakcję.
# Metoda <tt>end_pre</tt> isjest calledwołana everyza timekażdym razem, gdy <tt>SGMLParser</tt> findsznajdzie aznacznik <nowiki></pre></nowiki> tag. SincePonieważ endznaczniki tagskońcowe cannie notmogą containmieć attributesatrybutów, theta metoda methodnie takesprzyjmuje nożadnych parametersparametrów.
# Po pierwsze, chcemy wykonać domyślną akcję dla znacznika końcowego.
# First, you want to do the default processing, just like any other end tag.
# SecondPo drugie, youzmniejszamy decrementnasz yourlicznik, counterco tosygnalizuje signalnam thatzamknięcie thisbloku <nowiki><pre></nowiki> block has been closed.
 
AtW thistym point,momencie it'swarto worthsię diggingzagłębić anieco littlebardziej furtherw intoklasę <tt>SGMLParser</tt>. I'veTwierdziłem claimed repeatedlywielokrotnie (anda you'veTy takenjak itna onrazie faithmusiałeś somi farzaufać), thatże <tt>SGMLParser</tt> lookswyszukuje fori andwywołuje callsspecyficzne specificmetody methodsdla forkażdego each tagznacznika, ifjeśli theytakowe exististnieją. ForNp. instance,właśnie youwidziałeś justdefinicje saw the definition ofmetod <tt>start_pre</tt> andi <tt>end_pre</tt> todo handleobsługi <nowiki><pre></nowiki> andi <nowiki></pre></nowiki>. ButAle howjak doesto thissię happendzieje? WellNo cóż, it'sto notnie magic,jest żadna magia. To jest po prostu it'sdobry justkawałek goodkodu Pythonw codingPythonie.
 
Example 8.18. SGMLParser
 
ExamplePrzykład 8.18. <tt>SGMLParser</tt>
 
def finish_starttag(self, tag, attrs): #(1)
Linia 49 ⟶ 51:
method(attrs) #(8)
 
# W tym momencie <tt>SGMLParser</tt> znalazł już początkowy znacznik i sparsował listę atrybutów. Ostatnia rzecz jaka została do zrobienia, to ustalenie czy istnieje specjalna metoda obsługi dla tego znacznika lub czy powinniśmy skorzystać z metody domyślnej (<tt>unknown_starttag</tt>).
# At this point, SGMLParser has already found a start tag and parsed the attribute list. The only thing left to do is figure out whether there is a specific handler method for this tag, or whether you should fall back on the default method (unknown_starttag).
# TheZa “magic”"magią" ofklasy <tt>SGMLParser</tt> isnie nothingkryje moresię thannic yourwięcej oldniż friend,nasz stary przyjaciel <tt>getattr</tt>. WhatMoże youjeszcze maytego notwcześniej havenie realized before iszauważyłeś, thatale <tt>getattr</tt> willposzukuje findmetod methodszdefiniowanych definedzarówno inw descendantsdanym ofobiekcie anjak objecti asw welljego as the object itselfpotomkach. Here theTutaj objectobiektem isjest <tt>self</tt>, thebieżąca current instanceinstancja. SoA ifwięc tagjeśli isznacznikiem jest 'pre', thisto call towywołanie <tt>getattr</tt> will lookbędzie forposzukiwało ametody <tt>start_pre</tt> methodw onbieżącej the current instanceinstancji, whichktórą isjest aninstancja instance of theklasy <tt>Dialectizer class</tt>.
# Metoda <tt>getattr</tt> raiseszgłasza anwyjątek <tt>AttributeError</tt> ifjeśli themetoda methodktórej it'sszuka lookingnie foristnieje doesn'tw existdanym inobiekcie the(oraz objectw (orżadnym anyz ofjego its descendantspotomków), butale that'sto okay,jest becausew youporządku, wrappedponieważ theotoczyliśmy call towywołanie <tt>getattr</tt> inside ablokiem try...except block and explicitlyi caughtprzechwyciliśmy thewyjątek <tt>AttributeError</tt>.
# Ponieważ nie znaleźliśmy metody <tt>start_xxx</tt>, sprawdzamy jeszcze metodę <tt>do_xxx</tt> zanim się poddamy. Ta alternatywna grupa metod generalnie służy do obsługi znaczników samodzielnych, jak np. <nowiki><br></nowiki>, które nie mają znacznika końcowego. Jednak możemy używać metod z obu grup. Jak widać SGMLParser sprawdza obie grupy dla każdego znacznika. (Jednak nie powinieneś definiować obu metod obsługi <tt>start_xxx</tt> i <tt>do_xxx</tt> dla tego samego znacznika; i tak zostanie wywołana tylko <tt>start_xxx</tt>.)
# Since you didn't find a start_xxx method, you'll also look for a do_xxx method before giving up. This alternate naming scheme is generally used for standalone tags, like <br>, which have no corresponding end tag. But you can use either naming scheme; as you can see, SGMLParser tries both for every tag. (You shouldn't define both a start_xxx and do_xxx handler method for the same tag, though; only the start_xxx method will get called.)
# AnotherNastępny wyjątek <tt>AttributeError</tt>, whichktóry meansoznacza, thatże thekolejne call towywołanie <tt>getattr</tt> failedodnośnie with<tt>do_xxx</tt> do_xxxzawiodło. SincePonieważ younie foundznaleźliśmy neitherani ametody <tt>start_xxx</tt> nor aani <tt>do_xxx</tt> methoddla fortego this tagznacznika, youprzechwytujemy catchwyjątek thei exceptionwycofujemy andsię falldo backmetody on the default method,domyślnej <tt>unknown_starttag</tt>.
# RememberPamiętaj, bloki <tt>try...except</tt> blocksmogą canmieć havetakże anklauzulę <tt>else clause</tt>, whichktóra isjest calledwywoływana ifjeśli nonie exceptionwystąpi isżaden raisedwyjątek duringwewnątrz thebloku <tt>try...except block</tt>. LogicallyLogiczne, thatto meansoznacza, thatże youznaleźliśmy did find ametodę <tt>do_xxx</tt> methoddla fortego this tagznacznika, soa you're going towięc callwywołujemy it.
# A tak przy okazji nie przejmuj się tymi różnymi zwracanymi wartościami; teoretycznie one coś oznaczają, ale w praktyce nie są wykorzystywane. Nie martw się także tym <tt>self.stack.append(tag)</tt>; <tt>SGMLParser</tt> śledzi samodzielnie czy znaczniki początkowe są zrównoważone z odpowiednimi znacznikami końcowymi, ale jednocześnie do niczego tej informacji nie wykorzystuje. Teoretycznie moglibyśmy wykorzystać ten moduł do sprawdzania czy znaczniki są całkowicie zrównoważone, ale prawdopodobnie nie warto i wykracza to poza zakres tego rozdziału. W tej chwili masz lepsze powody do zmartwienia.
# By the way, don't worry about these different return values; in theory they mean something, but they're never actually used. Don't worry about the self.stack.append(tag) either; SGMLParser keeps track internally of whether your start tags are balanced by appropriate end tags, but it doesn't do anything with this information either. In theory, you could use this module to validate that your tags were fully balanced, but it's probably not worth it, and it's beyond the scope of this chapter. You have better things to worry about right now.
# Metody <tt>start_xxx</tt> i <tt>do_xxx</tt> nie są wywoływane bezpośrednio; Znacznik, metoda i atrybuty są przekazywane do tej funkcji: <tt>handle_starttag</tt>, aby klasy potomne mogły ją nadpisać i tym samym zmienić sposób obsługi znaczników początkowych. Nie potrzebujemy aż tak niskopoziomowej kontroli, a więc pozwalamy tej metodzie zrobić swoje, czyli wywołać metody (<tt>start_xxx</tt> lub <tt>do_xxx</tt>) z listą atrybutów. Pamiętaj, argument <tt>method</tt> jest funkcją zwróconą przez <tt>getattr</tt> a funkcje są obiektami. (Wiem, wiem, zaczynasz mieć dość słuchania tego w kółko. Obiecuję że natychmiast przestanę to powtarzać jak tylko zabraknie mi sposobów na wykorzystanie tego faktu.) Tutaj obiekt funkcji jest przekazywany do metody jako argument a ta metoda wywołuje tę funkcję. W tym momencie nie istotne jest co to jest za funkcja, jak się nazywa, gdzie jest zdefiniowana; jedyna rzecz jaka jest ważna, to to że jest ona wywoływana z jednym argumentem, <tt>attrs</tt>.
# start_xxx and do_xxx methods are not called directly; the tag, method, and attributes are passed to this function, handle_starttag, so that descendants can override it and change the way all start tags are dispatched. You don't need that level of control, so you just let this method do its thing, which is to call the method (start_xxx or do_xxx) with the list of attributes. Remember, method is a function, returned from getattr, and functions are objects. (I know you're getting tired of hearing it, and I promise I'll stop saying it as soon as I run out of ways to use it to my advantage.) Here, the function object is passed into this dispatch method as an argument, and this method turns around and calls the function. At this point, you don't need to know what the function is, what it's named, or where it's defined; the only thing you need to know about the function is that it is called with one argument, attrs.
 
NowA backteraz towracając ourdo regularlynaszego scheduled programprogramu: <tt>Dialectizer</tt>. WhenGdy yougo leftzostawiliśmy, youbyliśmy werew intrakcie thedefiniowania processmetod ofobsługi definingdla specific handler methods forznaczników <nowiki><pre></nowiki> andi <nowiki></pre></nowiki> tags. There'sPozostała onlyjuż onetylko thingjedna left torzecz do zrobienia, anda thatmianowicie isprzetworzenie tobloków processtekstu textprzy blockspomocy withzdefiniowanych the pre-defined substitutionspodstawień. ForW that,tym youcelu needmusimy tonadpisać override themetodę <tt>handle_data method</tt>.
 
Example 8.19. Overriding the handle_data method
Przykład 8.19. Nadpisanie metody <tt>handle_data</tt>
 
def handle_data(self, text): #(1)
self.pieces.append(self.verbatim and text or self.process(text)) #(2)
 
# Metoda <tt>handle_data</tt> isjest calledwołana withz onlytylko onejednym argumentargumentem, the texttekstem todo processprzetworzenia.
# InW theklasie ancestornadrzędnej <tt>BaseHTMLProcessor,</tt> themetoda <tt>handle_data</tt> methodpo simplyprostu appendeddodawała thetekst textdo towyjściowego the output buffer,bufora <tt>self.pieces</tt>. HereTutaj thelogika logicjest istylko onlytrochę slightlybardziej more complicatedskomplikowana. If you're in theJeśli middlejesteśmy ofw abloku <nowiki><pre>...</pre></nowiki> block, <tt>self.verbatim</tt> willbędzie bemiało somejakąś valuewartość greaterwiększą thanod 0, andi youtekst wanttrafi todo putbufora thewyjściowego textnie in the output buffer unalteredzmieniony. Otherwise,W youprzeciwnym willrazie callwywołujemy aoddzielną separatemetodę methoddo towykonania processpodstawień thei substitutions, then put the result of thatrezultat intoumieszczamy thew outputbuforze bufferwyjściowym. InTo Python,jest this is ajednolinijkowiec (one-liner,) usingw thePythonie wykorzystujący trik and-or trick.
 
Już jesteś blisko całkowitego zrozumienia <tt>Dialectizer</tt>. Ostatnim brakującym ogniwem jest sam charakter podstawień w tekście. Jeśli znasz Perla, to wiesz, że kiedy wymagane są kompleksowe zmiany w tekście, to jedynym prawdziwym rozwiązaniem są wyrażenia regularne. Klasy w dalszej części <tt>dialect.py</tt> definiują serię wyrażeń regularnych, które operują na tekście pomiędzy znacznikami HTML. Ale Ty już czytałeś cały rozdział o wyrażeniach regularnych. Zapewne nie masz ochoty znowu mozolić się z wyrażeniami regularnymi, prawda? Nauczyłeś się już wystarczająco jak na jeden rozdział.
 
You're close to completely understanding Dialectizer. The only missing link is the nature of the text substitutions themselves. If you know any Perl, you know that when complex text substitutions are required, the only real solution is regular expressions. The classes later in dialect.py define a series of regular expressions that operate on the text between the HTML tags. But you just had a whole chapter on regular expressions. You don't really want to slog through regular expressions again, do you? God knows I don't. I think you've learned enough for one chapter.
 
<noinclude>