Simple function classes - Introduction to classes in Python

文章推薦指數: 80 %
投票人數:10人

Any class method must have self as first argument. · self represents an (arbitrary) instance of the class. · To access any class attribute inside class methods, ... $$ \newcommand{\tp}{\thinspace.} $$ IntroductiontoclassesinPython Contents Tableofcontents Simplefunctionclasses    Challenge:functionswithparameters       Problem       Abadsolution:globalvariables    Representingafunctionasaclass       Implementation       Usageanddissection       Extensionoftheclass       Usingmethodsasordinaryfunctions       New-styleclassesversusclassicclasses       Docstrings    Theselfvariable    Anotherfunctionclassexample       Remark    Alternativefunctionclassimplementations    Makingclasseswithouttheclassconstruct       Firstremark       Secondremark    Closures Moreexamplesonclasses    Bankaccounts    Phonebook    Acircle       Verification       Remark Specialmethods    Thecallspecialmethod    Example:Automagicdifferentiation       Problem       Solution       Verification       Application:Newton'smethod       SolutionutilizingSymPy    Example:Automagicintegration       Asimpleimplementation       Verificationviasymboliccomputing       Remark    Turninganinstanceintoastring    Example:Phonebookwithspecialmethods       Remark    Addingobjects    Example:Classforpolynomials       Implementation       Usage       Prettyprintofpolynomials       Verifyingtheimplementation    Arithmeticoperationsandotherspecialmethods    Specialmethodsforstringconversion       Recreatingobjectsfromstrings Example:Classforvectorsintheplane    Somemathematicaloperationsonvectors    Implementation    Usage       Comment Example:Classforcomplexnumbers    Implementation    Illegaloperations    Mixingcomplexandrealnumbers    Dynamic,static,strong,weak,andducktyping    Specialmethodsfor``right''operands       Remark    Inspectinginstances Staticmethodsandattributes Summary    Chaptertopics       Classes       Specialmethods       Terminology    Example:intervalarithmetic       Problem       Solution Exercises    Exercise1:Makeafunctionclass    Exercise2:Addadataattributetoaclass    Exercise3:Addfunctionalitytoaclass       Remarks    Exercise4:Makeclassesforarectangleandatriangle    Exercise5:Makeaclassforquadraticfunctions    Exercise6:Makeaclassforstraightlines    Exercise7:Flexiblehandlingoffunctionarguments    Exercise8:Wrapfunctionsinaclass    Exercise9:Flexiblehandlingoffunctionarguments    Exercise10:Deduceaclassimplementation    Exercise11:Implementspecialmethodsinaclass    Exercise12:Makeaclassforsummationofseries    Exercise13:Applyanumericaldifferentiationclass    Exercise14:Implementanadditionoperator    Exercise15:Implementin-place+=and-=operators    Exercise16:Implementaclassfornumericaldifferentiation    Exercise17:Examineaprogram    Exercise18:Modifyaclassfornumericaldifferentiation    Exercise19:MakeaclassfortheHeavisidefunction    Exercise20:Makeaclassfortheindicatorfunction    Exercise21:Makeaclassforpiecewiseconstantfunctions    Exercise22:Speeduprepeatedintegralcalculations    Exercise23:Applyaclassforpolynomials    Exercise24:Findabuginaclassforpolynomials    Exercise25:Implementsubtractionofpolynomials    Exercise26:Testthefunctionalityofprettyprintofpolynomials    Exercise27:Vectorizeaclassforpolynomials       Remarks    Exercise28:Useadicttoholdpolynomialcoefficients    Exercise29:ExtendclassVec2Dtoworkwithlists/tuples    Exercise30:ExtendclassVec2Dto3Dvectors    Exercise31:UseNumPyarraysinclassVec2D    Exercise32:Imprecisenessofintervalarithmetics       Remarks    Exercise33:Makeclassesforstudentsandcourses    Exercise34:Findlocalandglobalextremaofafunction    Exercise35:Findtheoptimalproductionforacompany References     ThischapteristakenfromthebookAPrimeronScientificProgrammingwithPythonbyH.P.Langtangen,5thedition,Springer,2016. Simplefunctionclasses Classescanbeusedformanythingsinscientificcomputations,but oneofthemostfrequentprogrammingtasksistorepresent mathematicalfunctionsthathaveasetofparametersinadditionto oneormoreindependentvariables.ThesectionChallenge:functionswithparameters explainswhysuchmathematicalfunctionsposedifficultiesfor programmers,andthesectionRepresentingafunctionasaclassshowshowtheclassidea meetsthesedifficulties.ThesectionsAnotherfunctionclassexamplepresents anotherexamplewhereaclassrepresentsamathematicalfunction. Moreadvancedmaterialaboutclasses,whichforsomereadersmay clarifytheideas,butwhichcanalsobeskippedinafirstreading, appearsinthesectionsAlternativefunctionclassimplementationsandthesectionMakingclasseswithouttheclassconstruct. Challenge:functionswithparameters Tomotivatefortheclassconcept,wewilllookatfunctionswith parameters.Oneexampleis\(y(t)=v_0t-\frac{1}{2}gt^2\).Conceptually, inphysics,the\(y\)quantityisviewedasafunctionof\(t\),but\(y\) alsodependsontwootherparameters,\(v_0\)and\(g\),althoughitis notnaturaltoview\(y\)asafunctionoftheseparameters.Wemay write\(y(t;v_0,g)\)toindicatethat\(t\)istheindependentvariable, while\(v_0\)and\(g\)areparameters.Strictlyspeaking,\(g\)isafixed parameter(aslongasweareonthesurfaceoftheearthandcanview \(g\)asconstant),soonly\(v_0\)and\(t\)canbearbitrarilychosenin theformula.Itwouldthenbebettertowrite\(y(t;v_0)\). Inthegeneralcase,wemayhaveafunctionof\(x\)thathas\(n\) parameters\(p_1,\ldots,p_n\): \(f(x;p_1,\ldots,p_n)\). Oneexamplecouldbe $$ \begin{equation*}g(x;A,a)=Ae^{-ax}\thinspace.\end{equation*} $$ Howshouldweimplementsuchfunctions?Oneobviouswayistohave theindependentvariableandtheparametersasarguments: defy(t,v0): g=9.81 returnv0*t-0.5*g*t**2 defg(x,a,A): returnA*exp(-a*x) Problem Thereisonemajorproblemwiththissolution.Manysoftwaretoolswecanuse formathematicaloperationsonfunctionsassumethatafunctionofone variablehasonlyoneargumentinthecomputerrepresentationofthe function.Forexample,wemayhaveatoolfordifferentiatingafunction \(f(x)\)atapoint\(x\),usingtheapproximation $$ \begin{equation} f'(x)\approx{f(x+h)-f(x)\overh} \tag{1} \end{equation} $$ codedas defdiff(f,x,h=1E-5): return(f(x+h)-f(x))/h Thedifffunctionworkswithanyfunctionfthattakes oneargument: defh(t): returnt**4+4*t dh=diff(h,0.1) frommathimportsin,pi x=2*pi dsin=diff(sin,x,h=1E-6) Unfortunately,diffwillnotworkwithoury(t,v0) function.Callingdiff(y,t)leadstoanerrorinsidethe difffunction,becauseittriestocallouryfunctionwith onlyoneargumentwhiletheyfunctionrequirestwo. Writinganalternativedifffunctionfor ffunctionshavingtwoargumentsisabadremedyasit restrictsthesetofadmissibleffunctionstotheveryspecial caseofafunctionwithoneindependentvariableandoneparameter. Afundamentalprincipleincomputerprogrammingistostrivefor softwarethatisasgeneralandwidelyapplicableaspossible. Inthepresentcase,itmeansthatthedifffunctionshouldbe applicabletoallfunctionsfofonevariable,andletting ftakeoneargumentisthenthenaturaldecisiontomake. Themismatchoffunctionarguments,asoutlinedabove,isamajor problembecausealotofsoftwarelibrariesareavailablefor operationsonmathematicalfunctionsofonevariable:integration, differentiation,solving\(f(x)=0\),findingextrema,etc. Alltheselibrarieswilltryto callthemathematicalfunctionweprovidewithonlyoneargument. Whenourfunctionhasmorearguments,thecodeinsidethelibrary abortsinthecalltoourfunction,andsucherrorsmaynotalways beeasytotrackdown. Abadsolution:globalvariables Therequirementisthus todefinePythonimplementationsofmathematicalfunctions ofonevariablewithoneargument,theindependentvariable. Thetwoexamplesabovemustthenbeimplementedas defy(t): g=9.81 returnv0*t-0.5*g*t**2 defg(t): returnA*exp(-a*x) Thesefunctionsworkonlyif v0,A,andaareglobalvariables, initializedbeforeoneattemptstocallthefunctions. Herearetwosamplecallswherediffdifferentiatesyandg: v0=3 dy=diff(y,1) A=1;a=0.1 dg=diff(g,1.5) Theuseofglobalvariablesisingeneralconsideredbadprogramming. Whyglobalvariablesareproblematicinthepresentcase canbeillustratedwhenthereisneedtoworkwithseveral versionsofafunction.Supposewewanttoworkwithtwoversions of\(y(t;v_0)\),onewith\(v_0=1\)andonewith\(v_0=5\). Everytimewecallywemustrememberwhichversionofthefunction weworkwith,andsetv0accordinglypriortothecall: v0=1;r1=y(t) v0=5;r2=y(t) Anotherproblemisthat variableswithsimplenameslikev0,a,andAmay easilybeusedasglobalvariablesinotherpartsoftheprogram. Thesepartsmaychangeourv0inacontextdifferentfromthe yfunction,butthechangeaffectsthecorrectnessofthe yfunction.Insuchacase,wesaythatchangingv0has sideeffects,i.e.,thechangeaffectsotherpartsoftheprogram inanunintentionalway. Thisisonereasonwhyagoldenruleofprogrammingtellsustolimitthe useofglobalvariablesasmuchaspossible. Anothersolutiontotheproblemofneedingtwo\(v_0\)parameters couldbetointroducetwoyfunctions,eachwith adistinct\(v_0\)parameter: defy1(t): g=9.81 returnv0_1*t-0.5*g*t**2 defy2(t): g=9.81 returnv0_2*t-0.5*g*t**2 Nowweneedtoinitializev0_1andv0_2once,andthen wecanworkwithy1andy2. However,ifweneed100\(v_0\)parameters,weneed100functions. Thisistedioustocode,errorprone,difficulttoadminister,and simplyareallybadsolutiontoaprogrammingproblem. So,isthereagoodremedy?Theanswerisyes:theclassconcept solvesalltheproblemsdescribedabove! Representingafunctionasaclass Aclasscontainsasetofvariables(data) andasetoffunctions,heldtogetherasoneunit. Thevariablesarevisibleinallthefunctionsintheclass.Thatis, wecanviewthevariablesas"global"inthesefunctions. Thesecharacteristicsalsoapplytomodules,andmodulescanbe usedtoobtainmanyofthesameadvantagesasclassesoffer(see commentsinthesectionMakingclasseswithouttheclassconstruct).However,classes aretechnicallyverydifferentfrommodules.Youcanalsomakemany copiesofaclass,whiletherecanbeonlyonecopyofamodule. Whenyoumasterboth modulesandclasses,youwillclearlyseethesimilaritiesanddifferences. Nowwecontinuewithaspecificexampleofaclass. Considerthefunction\(y(t;v_0)=v_0t-\frac{1}{2}gt^2\). Wemaysaythat\(v_0\)and\(g\),representedbythevariables v0andg,constitutethedata.APythonfunction, sayvalue(t),isneededtocomputethevalueof \(y(t;v_0)\)andthisfunction musthaveaccess tothedatav0andg,whiletisanargument. Aprogrammerexperiencedwithclasseswillthensuggesttocollect thedatav0andg,andthefunctionvalue(t), togetherasaclass.Inaddition,aclassusuallyhasanotherfunction, calledconstructorforinitializing thedata.Theconstructor isalwaysnamed__init__. Everyclassmusthaveaname,oftenstartingwithacapital,sowe chooseYasthenamesincetheclassrepresentsamathematical functionwithname\(y\). Figure1sketchesthecontentsofclassY asaso-calledUMLdiagram,herecreated withaidofthe programclass_Y_v1_UML.py. TheUMLdiagramhastwo"boxes",onewherethefunctionsarelisted, andonewherethevariablesarelisted. OurnextstepistoimplementthisclassinPython. Figure1:UMLdiagramwithfunctionanddatainthesimpleclassYforrepresentingamathematicalfunction\(y(t;v_0)\). Implementation Thecompletecodeforour classYlooksasfollowsinPython: classY: def__init__(self,v0): self.v0=v0 self.g=9.81 defvalue(self,t): returnself.v0*t-0.5*self.g*t**2 ApuzzlementfornewcomerstoPythonclassesistheself parameter,whichmaytakesomeeffortsandtimetofullyunderstand. Usageanddissection Beforewedigintowhateachlineintheclassimplementation means,westartbyshowinghowtheclasscanbeusedtocomputevaluesof themathematicalfunction\(y(t;v_0)\). Aclasscreatesanewdatatype,hereofnameY, sowhenweusetheclasstomake objects,thoseobjectsareoftypeY.(Actually, allthestandardPythonobjects,suchas lists,tuples,strings,floating-pointnumbers,integers, etc.,arebuilt-in Pythonclasses,withnameslist,tuple, str,float, int,etc.) Anobjectofauser-definedclass(likeY)isusuallycalled aninstance. Weneedsuchaninstanceinordertousethedataintheclassandcallthe valuefunction. Thefollowingstatementconstructsaninstanceboundtothevariable namey: y=Y(3) Seemingly,wecalltheclassYasifitwereafunction. Actually,Y(3)isautomaticallytranslatedbyPythonto acalltotheconstructor__init__inclassY. Theargumentsinthecall,hereonlythenumber3, arealwayspassedonas argumentsto__init__aftertheself argument.Thatis,v0getsthevalue3andself isjustdroppedinthecall.Thismaybeconfusing,butitisarule thattheselfargumentisneverusedincallsto functionsinclasses. Withtheinstancey,wecancomputethevalue\(y(t=0.1;v_0=3)\)bythe statement v=y.value(0.1) Herealso,theselfargumentisdroppedinthecalltovalue. Toaccessfunctionsandvariablesinaclass,wemustprefixthe functionandvariablenamesbythenameoftheinstanceandadot: thevaluefunctionisreachedasy.value,andthe variablesarereachedasy.v0andy.g.Wecan,forexample, printthevalueofv0intheinstanceybywriting printy.v0 Theoutputwillinthiscasebe3. Wehavealreadyintroducedtheterm"instance''fortheobjectofaclass. Functionsinclassesarecommonlycalledmethods, andvariables(data)inclassesarecalled dataattributes.Methodsarealsoknownasmethodattributes. Fromnowonwewillusethisterminology.InoursampleclassY wehavetwomethodsormethodattributes,__init__andvalue,two dataattributes,v0andg,and fourattributes intotal(__init__,value,v0,andg). Thenamesofattributescanbechosenfreely,justas namesofordinaryPythonfunctionsandvariables.However,theconstructor musthavethename__init__,otherwiseitisnotautomatically calledwhenwecreatenewinstances. Youcandowhateveryouwantinwhatevermethod,butitisa commonconvention tousetheconstructorforinitializingthevariablesintheclass. Extensionoftheclass Wecanhaveasmanyattributesaswelikeinaclass,so letusaddanewmethodtoclassY.Thismethodiscalled formulaandprintsastringcontainingtheformulaof themathematicalfunction\(y\).Afterthisformula,weprovidethe valueof\(v_0\).Thestringcanthenbe constructedas 'v0*t-0.5*g*t**2;v0=%g'%self.v0 whereselfisaninstanceofclassY. Acallofformuladoesnotneedanyarguments: printy.formula() shouldbeenoughtocreate,return,andprintthestring. However,eveniftheformulamethoddoesnotneedanyarguments,it musthaveaselfargument,whichisleftoutinthecall butneededinsidethemethodtoaccesstheattributes. Theimplementationofthemethodistherefore defformula(self): return'v0*t-0.5*g*t**2;v0=%g'%self.v0 Forcompleteness,thewholeclassnowreads classY: def__init__(self,v0): self.v0=v0 self.g=9.81 defvalue(self,t): returnself.v0*t-0.5*self.g*t**2 defformula(self): return'v0*t-0.5*g*t**2;v0=%g'%self.v0 Exampleonusemaybe y=Y(5) t=0.2 v=y.value(t) print'y(t=%g;v0=%g)=%g'%(t,y.v0,v) printy.formula() withtheoutput y(t=0.2;v0=5)=0.8038 v0*t-0.5*g*t**2;v0=5 Becarefulwithindentationinclassprogramming. Acommonmistakedonebynewcomerstotheclassconstructionistoplace thecodethatappliestheclassatthesameindentationastheclassmethods. Thisisillegal.Onlymethoddefinitionsandassignmentsto so-calledstaticdataattributes (thesectionStaticmethodsandattributes)canappearintheindentedblockunder theclassheadline. Ordinarydataattributeassignmentmustbedoneinsidemethods. Themainprogramusingtheclassmustappearwiththesameindentas theclassheadline. Usingmethodsasordinaryfunctions Wemaycreateseveral\(y\)functionswithdifferentvaluesof\(v_0\): y1=Y(1) y2=Y(1.5) y3=Y(-3) Wecantreaty1.value,y2.value,and y3.valueasordinaryPythonfunctionsoft,andthenpass themontoanyPythonfunctionthatexpectsafunctionofonevariable. Inparticular,wecansendthefunctionstothediff(f,x)function fromthesectionChallenge:functionswithparameters: dy1dt=diff(y1.value,0.1) dy2dt=diff(y2.value,0.1) dy3dt=diff(y3.value,0.2) Insidethediff(f,x)function,theargument fnowbehavesasafunction ofonevariablethatautomatically carrieswithittwovariablesv0andg. Whenfrefersto(e.g.)y3.value,Pythonactually knowsthatf(x) meansy3.value(x),andinsidethey3.valuemethod selfisy3,andwehave accesstoy3.v0andy3.g. New-styleclassesversusclassicclasses WhenusePythonversion2andwriteaclasslike classV: ... wegetwhatisknownasanold-styleorclassicclass.Arevised implementationofclassesinPythoncameinversion2.2with new-styleclasses.Thespecificationofanew-styleclassrequires (object)aftertheclassname: classV(object): ... New-styleclasseshavemorefunctionality,anditisingeneralrecommended toworkwithnew-styleclasses. WeshallthereforefromnowwriteV(object)ratherthanjustV. InPython3,allclassesarenew-stylewhetherwewriteVorV(object). Docstrings Afunctionmayhaveadocstringrightafterthe functiondefinition,seethesectionref{sec:basic:docstring}. Theaimofthedocstringistoexplainthepurposeofthefunction and,forinstance,whattheargumentsandreturnvaluesare. Aclasscanalsohaveadocstring,itisjustthefirststringthat appearsrightaftertheclassheadline. Theconventionistoenclosethedocstringintripledoublequotes""": classY(object): """Theverticalmotionofaball.""" def__init__(self,v0): ... Morecomprehensiveinformationcanincludethemethodsandhowthe classisusedinaninteractivesession: classY(object): """ Mathematicalfunctionfortheverticalmotionofaball. Methods: constructor(v0):setinitialvelocityv0. value(t):computetheheightasfunctionoft. formula():printouttheformulafortheheight. Dataattributes: v0:theinitialvelocityoftheball(time0). g:accelerationofgravity(fixed). Usage: >>>y=Y(3) >>>position1=y.value(0.1) >>>position2=y.value(0.3) >>>printy.formula() v0*t-0.5*g*t**2;v0=3 """ Theselfvariable Nowwewillprovidesomemoreexplanationoftheselfparameterand howtheclassmethodswork.Insidetheconstructor__init__,the argumentselfisavariableholdingthenewinstancetobe constructed.Whenwewrite self.v0=v0 self.g=9.81 wedefinetwonewdataattributesinthisinstance.Theselfparameter isinvisiblyreturnedtothecallingcode.WecanimaginethatPython translatesthesyntaxy=Y(3)toacallwrittenas Y.__init__(y,3) Now,selfbecomesthenewinstanceywewanttocreate,sowhenwe doself.v0=v0intheconstructor,weactuallyassignv0to y.v0.TheprefixwithY.illustrateshowtoreachaclassmethod withasyntaxsimilartoreachingafunctioninamodule(justlike math.exp).IfweprefixwithY.,weneedtoexplicitlyfeedinan instancefortheselfargument,likeyinthecodelineabove,but ifweprefixwithy.(theinstancename)theselfargumentis droppedinthesyntax,andPythonwillautomaticallyassignthey instancetotheselfargument.Itisthelatter"instancename prefix"whichweshallusewhencomputingwith classes.(Y.__init__(y,3)willnotworksinceyisundefinedand supposedtobeanYobject.However,ifwefirstcreatey=Y(2) andthencallY.__init__(y,3),thesyntaxworks,andy.v0is3 afterthecall.) Letuslookatacalltothevaluemethodtoseeasimilar useoftheselfargument.Whenwewrite value=y.value(0.1) Pythontranslatesthistoacall value=Y.value(y,0.1) suchthattheselfargumentinthevaluemethodbecomes theyinstance.Intheexpressioninsidethevaluemethod, self.v0*t-0.5*self.g*t**2 selfisysothisisthesameas y.v0*t-0.5*y.g*t**2 Theuseofselfmaybecomemoreapparentwhenwehavemultipleclass instances.Wecanmakeaclassthatjusthasoneparametersowe caneasilyidentifyaclassinstancebyprintingthevalueofthis parameter.Inaddition,everyPythonobjectobjhasaunique identifierobtainedbyid(obj)thatwecanalsoprinttotrack whatselfis. classSelfExplorer(object): def__init__(self,a): self.a=a print'init:a=%g,id(self)=%d'%(self.a,id(self)) defvalue(self,x): print'value:a=%g,id(self)=%d'%(self.a,id(self)) returnself.a*x Hereisaninteractivesessionwiththisclass: >>>s1=SelfExplorer(1) init:a=1,id(self)=38085696 >>>id(s1) 38085696 Weclearlyseethatselfinsidetheconstructoristhesame objectass1,whichwewanttocreatebycallingtheconstructor. Asecondobjectismadeby >>>s2=SelfExplorer(2) init:a=2,id(self)=38085192 >>>id(s2) 38085192 Nowwecancallthevaluemethodusingthestandardsyntaxs1.value(x) andthe"morepedagogical"syntaxSelfExplorer.value(s1,x). Usingboths1ands2illustrateshowselftakeondifferent values,whilewemaylookatthemethodSelfExplorer.valueas asinglefunctionthatjustoperatesondifferentselfandx objects: >>>s1.value(4) value:a=1,id(self)=38085696 4 >>>SelfExplorer.value(s1,4) value:a=1,id(self)=38085696 4 >>>s2.value(5) value:a=2,id(self)=38085192 10 >>>SelfExplorer.value(s2,5) value:a=2,id(self)=38085192 10 Hopefully,theseillustrationshelptoexplainthatselfisjust theinstanceusedinthemethodcallprefix,heres1ors2. Ifnot,patientworkwithclassprogramminginPythonwillover timerevealanunderstandingofwhatselfreallyis. Rulesregardingself. Anyclassmethodmusthaveselfasfirstargument.(Thenamecanbeanyvalidvariablename,butthenameselfisawidelyestablishedconventioninPython.) selfrepresentsan(arbitrary)instanceoftheclass. Toaccessanyclassattributeinsideclassmethods,wemustprefixwithself,asinself.name,wherenameisthenameoftheattribute. selfisdroppedasargumentincallstoclassmethods. Anotherfunctionclassexample LetusapplytheideasfromtheYclasstothefunction $$ \begin{equation*} v(r)=\left({\beta\over2\mu_0}\right)^{{1/n}} {n\overn+1}\left(R^{1+1/n}-r^{1+1/n}\right), \end{equation*} $$ where\(r\)istheindependentvariable. Wemaywritethisfunctionas\(v(r;\beta,\mu_0,n,R)\)to explicitlyindicatethat thereisoneprimaryindependentvariable(\(r\))andfourphysical parameters\(\beta\),\(\mu_0\),\(n\),and\(R\). Theclasstypicallyholds thephysicalparametersasvariablesandprovidesanvalue(r)method forcomputingthe\(v\)function: classV(object): def__init__(self,beta,mu0,n,R): self.beta,self.mu0,self.n,self.R=beta,mu0,n,R defvalue(self,r): beta,mu0,n,R=self.beta,self.mu0,self.n,self.R n=float(n)#ensurefloatdivisions v=(beta/(2.0*mu0))**(1/n)*(n/(n+1))*\ (R**(1+1/n)-r**(1+1/n)) returnv Thereisseemingly onenewthinghereinthatweinitializeseveralvariablesonthe sameline: self.beta,self.mu0,self.n,self.R=beta,mu0,n,R Thecomma-separatedlistofvariablesontheright-hand sideformsatuplesothisassignmentisjusttheavalidconstructionwhere asetofvariablesontheleft-handsideissetequaltoalistortuple ontheright-handside,elementbyelement.An equivalentmulti-linecodeis self.beta=beta self.mu0=mu0 self.n=n self.R=R Inthevaluemethoditisconvenienttoavoidthe self.prefixinthemathematicalformulasandinsteadintroduce thelocalshortnamesbeta,mu0,n,andR. Thisisingeneralagoodidea,becauseitmakesiteasiertoreadthe implementationoftheformulaandcheckitscorrectness. Remark Anothersolutiontotheproblemofsendingfunctionswithparameters toagenerallibraryfunctionsuchasdiffisprovidedin thedocumentVariablenumberof functionargumentsinPython [2].Theremedythereistotransferthe parametersasarguments"through"thedifffunction.Thiscanbe doneinageneralwayasexplainedinthatappendix. Alternativefunctionclassimplementations Toillustrateclassprogrammingfurther,wewillnowrealizeclass YfromthesectionRepresentingafunctionasaclassinadifferentway. Youmayconsiderthissectionasadvancedandskipit,butfor somereadersthematerialmightimprovetheunderstandingof classYandgivesomeinsightinto classprogrammingingeneral. Itisagoodhabitalwaystohaveaconstructorinaclassandto initializethedataattributesintheclasshere,butthisisnota requirement.Letusdroptheconstructorandmakev0anoptional argumenttothevaluemethod.Iftheuserdoesnotprovidev0in thecalltovalue,weuseav0valuethatmusthavebeenprovided inanearliercallandstoredasadataattributeself.v0.Wecan recognizeiftheuserprovidesv0asargumentornotbyusingNone asdefaultvalueforthekeywordargumentandthentestifv0is None. OuralternativeimplementationofclassY,namedY2,nowreads classY2(object): defvalue(self,t,v0=None): ifv0isnotNone: self.v0=v0 g=9.81 returnself.v0*t-0.5*g*t**2 Thistimetheclasshasonlyonemethodandonedataattributeaswe skippedtheconstructorandletgbealocalvariablein thevaluemethod. Butifthereisnoconstructor,howisaninstancecreated? Pythonfortunatelycreatesanemptyconstructor.Thisallowsustowrite y=Y2() tomakeaninstancey.Sincenothinghappensintheautomatically generatedemptyconstructor,yhasnodataattributesatthisstage. Writing printy.v0 thereforeleadstotheexception AttributeError:Y2instancehasnoattribute'v0' Bycalling v=y.value(0.1,5) wecreateanattributeself.v0insidethevaluemethod. Ingeneral,wecancreateanyattributenameinanymethodbyjustassigning avaluetoself.name.Nowtryinga printy.v0 willprint5. Inanewcall, v=y.value(0.2) thepreviousv0value(5)isusedinsidevalueas self.v0unlessav0argumentisspecifiedinthecall. Thepreviousimplementationisnotfoolproofifwefailtoinitialize v0.Forexample,thecode y=Y2() v=y.value(0.1) willterminateinthevaluemethodwiththeexception AttributeError:Y2instancehasnoattribute'v0' Asusual,itisbettertonotifytheuserwithamoreinformativemessage. Tocheckifwehaveanattributev0,wecanusethePython functionhasattr.Callinghasattr(self,'v0')returns Trueonlyiftheinstanceselfhasanattribute withname'v0'.Animprovedvaluemethodnowreads defvalue(self,t,v0=None): ifv0isnotNone: self.v0=v0 ifnothasattr(self,'v0'): print'Youcannotcallvalue(t)withoutfirst'\ 'callingvalue(t,v0)tosetv0' returnNone g=9.81 returnself.v0*t-0.5*g*t**2 Alternatively,wecantryto accessself.v0inatry-exceptblock,and perhapsraiseanexceptionTypeError(whichiswhatPythonraisesif therearenotenoughargumentstoafunctionormethod): defvalue(self,t,v0=None): ifv0isnotNone: self.v0=v0 g=9.81 try: value=self.v0*t-0.5*g*t**2 exceptAttributeError: msg='Youcannotcallvalue(t)withoutfirst' 'callingvalue(t,v0)tosetv0' raiseTypeError(msg) returnvalue NotethatPythondetectsanAttributeError,butfromauser's pointofview,notenoughparametersweresuppliedinthecallso aTypeErrorismoreappropriatetocommunicatebacktothe callingcode. WethinkclassYisabetterimplementationthanclassY2, becausetheformerissimpler.Asalreadymentioned,it isagoodhabittoinclude aconstructorandsetdatahereratherthan"recordingdataonthefly" aswetrytoinclassY2.ThewholepurposeofclassY2 isjusttoshowthatPythonprovidesgreatflexibilitywithrespect todefiningattributes,andthattherearenorequirementstowhat aclassmustcontain. Makingclasseswithouttheclassconstruct Newcomerstotheclassconceptoftenhaveahardtimeunderstanding whatthisconceptisabout.Thepresentsectiontriestoexplainin moredetailhowwecanintroduceclasseswithouthavingthe classconstructinthecomputerlanguage. Thisinformationmayormay notincreaseyourunderstandingofclasses.Ifnot,programming withclasseswilldefinitelyincreaseyourunderstandingwithtime,so thereisnoreasontoworry.Infact,youmaysafelyjumpto thesectionSpecialmethodsasthereareno importantconceptsinthissectionthatlatersectionsbuildupon. Aclasscontainsacollectionofvariables(data)andacollection ofmethods(functions).Thecollectionofvariablesisuniquetoeach instanceoftheclass.Thatis,ifwemaketeninstances,eachofthem hasitsownsetofvariables.Thesevariablescanbethoughtofas adictionarywithkeysequaltothevariablenames.Eachinstance thenhasitsowndictionary,andwemayroughlyviewtheinstance asthis dictionary.(Theinstancecanalsocontainstaticdataattributes (thesectionStaticmethodsandattributes),butthesearetobeviewedasglobal variablesinthepresentcontext.) Ontheotherhand,themethodsareshared amongtheinstances.Wemaythinkofamethodinaclass asastandardglobal functionthattakesaninstanceintheformofadictionary asfirst argument.Themethodhasthenaccesstothevariablesintheinstance (dictionary)providedinthecall. FortheYclassfromthesectionRepresentingafunctionasaclass andaninstancey, themethodsareordinary functionswiththefollowingnamesandarguments: Y.value(y,t) Y.formula(y) Theclassactsasanamespace, meaningthatallfunctions mustbeprefixedbythenamespacename,hereY. Twodifferentclasses,sayC1andC2,mayhavefunctions withthesamename,sayvalue,butwhenthevaluefunctions belongtodifferentnamespaces,theirnamesC1.valueand C2.valuebecomedistinct. Modulesarealsonamespacesforthefunctionsandvariablesinthem (thinkofmath.sin,cmath.sin,numpy.sin). TheonlypeculiarthingwiththeclassconstructinPythonisthat itallowsustouseanalternativesyntaxformethodcalls: y.value(t) y.formula() Thissyntaxcoincideswiththetraditionalsyntaxofcallingclass methodsandprovidingarguments,asfoundinothercomputerlanguages, suchasJava,C#,C++,Simula,andSmalltalk. Thedotnotationisalsousedtoaccessvariablesinaninstance suchthatweinsideamethodcanwriteself.v0insteadof self['v0'](selfreferstoythroughthefunctioncall). Wecouldeasily implementasimpleversionoftheclassconceptwithouthavingaclass constructioninthelanguage.Allweneedisadictionarytypeand ordinaryfunctions.Thedictionaryactsastheinstance,andmethodsare functionsthattakethisdictionaryasthefirstargumentsuchthat thefunctionhasaccessto allthevariablesintheinstance. OurYclasscouldnowbeimplementedas defvalue(self,t): returnself['v0']*t-0.5*self['g']*t**2 defformula(self): print'v0*t-0.5*g*t**2;v0=%g'%self['v0'] ThetwofunctionsareplacedinamodulecalledY. Theusagegoesasfollows: importY y={'v0':4,'g':9.81}#makean"instance" y1=Y.value(y,t) Wehavenoconstructorsincetheinitializationofthevariablesis donewhendeclaringthedictionaryy,butwecouldwellinclude someinitializationfunctionintheYmodule definit(v0): return{'v0':v0,'g':9.81} Theusageisnowslightlydifferent: importY y=Y.init(4)#makean"instance" y1=Y.value(y,t) Thiswayofimplementingclasseswiththeaidofadictionaryand asetofordinaryfunctionsactuallyformsthebasisforclassimplementations inmanylanguages.PythonandPerleven haveasyntaxthatdemonstratesthistypeof implementation.Infact,everyclassinstanceinPythonhasadictionary __dict__asattribute,whichholdsallthe variablesintheinstance.Hereisademothatprovestheexistenceofthis dictionaryinclassY: >>>y=Y(1.2) >>>printy.__dict__ {'v0':1.2,'g':9.8100000000000005} Tosummarize:APythonclasscanbethoughtofassomevariablescollected inadictionary,andasetoffunctionswherethisdictionaryisautomatically providedasfirstargumentsuchthatfunctionsalwayshavefullaccessto theclassvariables. Firstremark Wehaveinthissectionprovidedaviewof classesfromatechnicalpointofview.Othersmayviewaclass asawayofmodelingtheworldintermsofdataandoperationson data.However,insciencesthatemploythelanguageofmathematics, themodelingoftheworldisusuallydonebymathematics,andthe mathematicalstructuresprovideunderstandingoftheproblemand structureofprograms.Whenappropriate,mathematicalstructurescan convenientlybemappedontoclassesinprogramstomakethesoftware simplerandmoreflexible. Secondremark Theviewofclassesinthissectionneglectsveryimportanttopics suchasinheritanceanddynamicbinding (explainedinthedocumentObject-orientedprogramming[1]). Formorecompletenessofthepresentsection, wethereforebrieflydescribehowourcombinationofdictionariesandglobal functionscandealwithinheritanceanddynamicbinding (butthiswillnotmakesenseunlessyouknowwhat inheritanceis). Datainheritancecanbeobtainedbylettingasubclassdictionary doanupdatecallwiththesuperclassdictionaryasargument. Inthiswayalldatainthesuperclassarealsoavailableinthe subclassdictionary.Dynamicbindingofmethodsismorecomplicated,but onecanthinkofcheckingifthemethodisinthesubclassmodule (usinghasattr),andifnot,oneproceedswithcheckingsuper classmodulesuntilaversionofthemethodisfound. Closures ThissectionfollowsupthediscussioninthesectionMakingclasseswithouttheclassconstruct andpresentsamoreadvancedconstructionthatmayserveasalternative toclassconstructionsinsomecases. OurmotivatingexampleisthatwewantaPythonimplementationof amathematicalfunction\(y(t;v_0)=v_0t-\frac{1}{2}gt^2\)to have\(t\)astheonlyargument,butalsohaveaccesstotheparameter\(v_0\). Considerthefollowingfunction,whichreturnsafunction: >>>defgenerate_y(): ...v0=5 ...g=9.81 ...defy(t): ...returnv0*t-0.5*g*t**2 ...returny ... >>>y=generate_y() >>>y(1) 0.09499999999999975 Theremarkablepropertyoftheyfunctionisthatitremembersthe valueofv0andg,althoughthesevariablesarenotlocalto theparentfunctiongenerate_yandnotlocaliny.Inparticular, wecanspecifyv0asargumenttogenerate_y: >>>defgenerate_y(v0): ...g=9.81 ...defy(t): ...returnv0*t-0.5*g*t**2 ...returny ... >>>y1=generate_y(v0=1) >>>y2=generate_y(v0=5) >>>y1(1) -3.9050000000000002 >>>y2(1) 0.09499999999999975 Here,y1(t)hasaccesstov0=1whiley2(t)hasaccesstov0=5. Thefunctiony(t)weconstructandreturnfromgenerate_yis calledaclosureanditremembersthevalueofthesurrounding localvariablesintheparentfunction(atthetimewecreatethe yfunction).Closuresareveryconvenientformany purposesinmathematicalcomputing. ExamplesappearinthesectionExample:Automagicdifferentiation. Closuresarealsocentralin aprogrammingstylecalledfunctionalprogramming. Generatingmultipleclosuresinafunction. Assoonasyougettheideaofaclosure,youwillprobablyuseit alotbecauseitisaconvenientwaytopackafunctionwithextra data.However,therearesomepitfalls.Thebiggestisillustrated below,butthisisconsideredadvancedmaterial! Letusgenerateaseriesoffunctionsv(t)forvarious valuesofaparameterv0.Eachfunctionjustreturns atuple(v0,t)suchthatwecaneasilyseewhattheargumentand theparameterare.Weuselambdatoquicklydefine eachfunction,andweplacethefunctionsinalist: >>>defgenerate(): ...return[lambdat:(v0,t)forv0in[0,1,5,10]] ... >>>funcs=generate() Now,funcsisalistoffunctionswithoneargument. Callingeachfunctionandprinting thereturnvaluesv0andtgives >>>forfuncinfuncs: ...printfunc(1) ... (10,1) (10,1) (10,1) (10,1) Aswesee,allfunctionshavev0=10,i.e.,theystoredthemostrecent valueofv0beforereturn.Thisisnotwhatwewanted. Thetrickistoletv0beakeywordargumentineachfunction, becausethevalueofakeywordargumentisfrozenatthetimethe functionisdefined: >>>defgenerate(): ...return[lambdat,v0=v0:(v0,t) ...forv0in[0,1,5,10]] ... >>>funcs=generate() >>>forfuncinfuncs: ...printfunc(1) ... (0,1) (1,1) (5,1) (10,1) ←Prev Next→



請為這篇文章評分?