118x Filetype PDF File size 0.23 MB Source: st.inf.tu-dresden.de
Object-oriented programming with Python Anintroduction into OOP and design patterns with Python MaxLeuthäuser s7060241@mail.zih.tu-dresden.de TUDresden Abstract 1. TheBasics Whileprogrammingitselfisarelatively young discipline, you may Asmentionedaboveyoushouldalreadybefamiliarwithbasicslike finditsurprisingthatobject-orientedprogramming(OOPfromnow the following ones, so this is simply a small summary to repeat and on)actuallygoesbackasfarasthe1960’s.Simula1 isconsideredto keep things in mind. Advanced users might skip this and continue bethefirst object-oriented programming language. This paper tries reading the "Advanced language extensions" part or dive directly to dive quickly into OOP with Python and give a small introduction into "Design Patterns with Python". into important basics. Later we find more advanced techniques 1.1 Whatisanobject? with design patterns. This paper assumes a minimal knowledge of Python syntax. If you know how to create the basic data-types and Weare in the domain of programming - so an object is a concept. call functions, but want to know more about objects, classes, design Calling elements of our programs objects is a metaphor - a useful patterns and advanced built-in language extensions you may find way of thinking about them. In Python the basic elements of pro- this helpful. gramming are things like strings, dictionaries, integers, functions, 6 and so on. They are all objects . Introduction 1.2 Asmallreference to procedural programming Using a procedural style of programming, programs are often split OOPitself is a controversial paradigm, in fact it is not even clear into reusable "chunks" called functions and methods. The resulting what a strict definition of OOP is. Actually some people think that code is easier to maintain. These chunks are callable at different OOP has nearly had its days, and we need to find the post OOP places in your program so improving one method or function will paradigm2. So it is not very surprising that others like Paul Gra- enhancetheperformanceonseveralplaces. Anotherimportantfact ham3 think it was never necessary in the first place. But in general to keep in mind when talking about OOP comes from procedural OOPisbasicallyastandard.Mostlinesofcodenowadaysarewrit- programmingaswell. It maintains a strict separation between your 4 code and your data. You have variables, which contain your data, ten with object-oriented (and semi object orientated) languages . It is not the task of this paper to underline all the advantages of Python andprocedures.Youpassyourvariablestoyourprocedures-which now, but some basic facts are important. The whole design philos- act on themandperhapsmodifythem.Ifafunctionwantstomodify ophy of Python encourages a clean programming style. Its basic the content of a variable by passing it to another function it needs datatypes and system of namespaces makes it easier to write ele- access to both the variable and the function it’s calling. If you are gant, modular code5. These factors and the unique block structure performing complex operations this could be lots of variables and byindentation rules are very helpful for reading and understanding lots of functions. code. Actually the basic principles of object-oriented programming 1.3 Talking about python basics are relatively easy to learn. Like other aspects of Python they are nicely implemented and well thought out. TraditionallyessentialelementsofOOPareencapsulationandmes- The remaining part of this paper is organized as follows: The sagepassing.ThePythonequivalentsarenamespacesandmethods. next two sections introduce the object orientated programming Pythondoesnotsubscribetoprotectingthecodefromtheprogram- paradigm and its basics - especially with Python. After this some mer, like some of the more BSD languages. Python does encapsu- importantfactswithinheritanceandadditionallanguageextensions late objects as a single namespace but it is a translucent encapsu- are discussed. This is concluded with some simple measurements lation. The following introductions are visualized using the string and some broader observations on using design patterns in Python. object as an example. This paper is full of examples written in Python and C++ and/or 1.3.1 Using objects Java. Feel free to compile them, they may help to understand what wasmeantinthetext. Asalready mentioned above it turns out that lots of operations are commontoobjects of the same type. For example most languages have built-in ways to create a lowercase version of a string. Actu- 1 http://en.wikipedia.org/wiki/Simula ally there are a lot of standard operations to interact with strings. 2 http://www.americanscientist.org/Issues/Comsci03/03-03Hayes.html Building an uppercase version, splitting and concatenating, and so 3 http://www.paulgraham.com/noop.html on. In an object-oriented language we can build these in as prop- 4 erties of the string object. In Python we call these methods. Every http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html 5 Python’s system of modules and packages as well - these are related to 6Like Smalltalk - which is sometimes spoken of as the archetypal object- namespaces, and are the envy of other languages. oriented language. 1 string object has a standard set of methods. This is true for all kinds Last thing in this section is making use of some simple dictionary of objects in Python. Consider the following example (code taken methods. from [1]): a_dict = { original_string = ’ some text ’ ’ key ’ : ’ value ’ , # remove leading and trailing whitespace ’ key2 ’ : ’ value2 ’ string1 = original_string . strip () } a_dict_2 = a_dict .copy() # make uppercase print a_dict == a_dict_2 string2 = string1 . upper () True print string2 a_dict . clear () > SOME TEXT print a_dict {} # make lowercase print a_dict . clear string2 . lower () == string1True x0012E540> print type( a_dict . clear ) Python uses the dot syntax (like Java or C#) to access attributes of objects. The statement string2.lower() means call the lower The clear method of a_dict was used by calling a_dict.clear(). method of the object string2. This method returns a new string When we printed clear, instead of calling it, we can see that it is - the result of calling the method. So every string is actually a just another object. It is a method object of the appropriate type. string object - and has all the methods of a string object. In Python terminology we say that all strings are of the string type. In the 1.3.3 Using functions as objects object model the functions (methods) and other attributes that are Todemonstratethatfunctionscanbeobjectsconsiderthefollowing associated with a particular kind of object become part of the code. You may have written something like this before in some object. The data and the functions for dealing with it are no longer other language: separate - but are bound together in one object. 1.3.2 Creating objects i f value == ’one’: In Python there is a blueprint string object called the string type. Its # do something actual name is str. It has all the methods and properties associated function1 () with the string as already described above. Each single time a elif value == ’two’: new string is created, the blueprint is used to create a new object # do something else with all the properties of the blueprint. All the built-in datatypes function2 () have their own blueprint, e.g. the integer (int), the float (float), elif value == ’three ’: booleans (bool), lists (list), dictionaries (dict), and some more. For # do something else this datatypes it is possible to use the standard Python syntax to function3 () create them or we can use the blueprint itself - the type. Other languages (e.g. Java ) have a construct called switch that # create a dictionary the normal way makes writing code like that a bit easier. In Python we can achieve a_dict = { thesamething(inlesslinesofcode)usingadictionaryoffunctions. ’ key ’ : ’ value ’ , Asanexample, suppose we have three functions. You want to call ’ key2 ’ : ’ value2 ’ one of the functions, depending on the value in a variable called } choice. # use ’dict ’ to create one def function1 () : l i s t _ o f _ t u p l e s = [( ’key ’ , ’value ’) , print ’You chose one. ’ ( ’ key2 ’ , ’ value2 ’) ] def function2 () : a_dict_2 = dict ( list_of_tuples ) print ’You chose two. ’ # def function3 () : print a_dict == a_dict_2 print ’You chose three . ’ True print type( a_dict ) # switch is our dictionary of functions switch = { print type(a_dict_2) ’ one ’ : function1 , ’two’: function2 , a_dict_2 was created by passing a list of tuples to dict. Very ’ t h r e e ’ : function3 , basic, but it illustrates that new objects are created from blueprints. } These objects have all the methods defined in the blueprint. The # choice can either be ’one ’, ’two ’, or ’ new object is called an instance and the process of creating it is t h r e e ’ called instantiation (meaning creating an instance). For the built- choice = raw_input( ’Enter one , two , or three in datatypes the blueprint is known as the type of the object. You 7 : ’ ) can test the type of an object by using the built-in function type. 7 Actually type is not a function - it is a type. Exactly the type of types # call one of the functions (type(type) is type). It is used as function here. try : 2 r e s u l t = switch[choice] instance is a reference to our new object. We access the printargs except KeyError: method of the instance object using instance.printargs. In order to print ’I did not understand your choice . access object attributes from within the __init__ method we need ’ a reference to the object within the method of the object itself. else : Whenever a method is called, a reference to the main object is r e s u l t ( ) passed as the first argument. By convention you always call this first argument to your methods self. Thepointofinterestis:result=switch[choice].Theswitch[choice] returns one of our function objects (or raises a KeyError). Finally 1.5 Conclusions for this section result() is called which does the trick. So what are the advantages of using OOP and what is so useful 1.4 Makinguseofuserdefinedclasses using objects? Much more interesting is that we can create our own blueprints. Objects combine data and the methods used to work with the These are called classes. We can define our own class of object - data. So it is possible to wrap complex processes - but present a andfromthiscreate as many instances of this class as we want. All simple interface to them. How these processes are done inside the the instances will be different - depending on what data they are object becomes a mere implementation detail. Anyone using the given when they are created. They will all have the methods (and object only needs to know about the methods and attributes. This is other properties) from the blueprint. Take a look at the following the real principle of encapsulation. Other parts of your application simple example. We define our own class using the class keyword. (or even other programmers) can use your classes and their public Methods are defined like functions - using the def keyword. They methods - but you can update the object without breaking the are indented to show that they are inside the class. interface they use. Youcanalso pass around objects instead of data. This is one of class OurClass( object ) : the most useful aspects of OOP. Once you have a reference to the def __init__ ( self , arg1 , arg2) : object you can access any of the attributes of the object. If you need self . arg1 = arg1 to perform a complex group of operations as part of a program you self . arg2 = arg2 could probably implement it with procedures and variables. You might either need to use several global variables for storing states def printargs ( self ) : (which are slower to access than local variables and not good if print self . arg1 a module needs to be reusable within your application) - or your print self . arg2 procedures might need to pass around a lot of variables. If you implement a single class that has many attributes repre- Nowitiseasytocreate an own instance: senting the state of your application, you only need to pass around a reference to that object. Any part of your code that has access to i n s t a n c e = OurClass( ’arg1 ’ , ’arg2 ’) the object can also access its attributes. print type( instance ) Themainadvantageofobjectsisthattheyareausefulmetaphor. It fits in with the way we think. In real life objects have certain i n s t a n c e . p r i n t a r g s ( ) properties and interact with each other. The more our programming arg1 language fits in with our way of thinking, the easier it is to use it to arg2 think creatively [1]. To go back to Python itself the "everything is an object" men- The arguments arg1 and arg2 are passed to the constructor as tality should be mentioned. arguments. Later they are printed using the method printargs(). To get a deeper understanding what happened here we need to know 2. Everything is an object moreabouttheconstructor and the things which are related to this. 1.4.1 The__init__ method As you now know already from above everything in Python is an object, and almost everything has attributes and methods. All The__init__ method (init for initialise) is called when the object is functions have a built-in attribute __doc__, which returns the doc instantiated. Instantiation is done by (effectively) calling the class. string (short usage documentation of the function) which is defined It is also known a the constructor as mentioned above. This is in the function’s source code. The sys module is an object having very similar to Java where the constructor has always the name as an attribute called path. And so forth. the class itself followed by the list of the arguments surrounded InPython,thedefinitionfor"object"isquiteweak;someobjects by brackets. The only thing leftover now is the confusing self haveneitherattributes nor methods and not all objects are subclass- parameter. able. But everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function. 1.4.2 Understanding the self parameter The arguments accepted by the __init__ method (known as the 2.1 First class functions methodsignature) are: Simplyspokenfirstclassfunctionsallowrun-timecreationoffunc- tions from functions. It do not have to be members of some class. def __init__ ( self , arg1 , arg2) : 8 Theexact definition is something like this : In computer science, a This is a little bit confusing. When we initiate the object we programming language is said to support first-class functions (also actually pass only two arguments: called function literals, function types) if it treats functions as first- class objects. Specifically, this means that the language supports i n s t a n c e = OurClass( ’arg1 ’ , ’arg2 ’) constructing new functions during the execution of a program, stor- ing them in data structures, passing them as arguments to other Sowheredoestheextraargumentcomesfrom?Whenweaccess attributes of an object we do it by name (or by reference). Here 8http://en.wikipedia.org/wiki/First-class_function 3 functions, and returning them as the values of other functions. This as follows: the corresponding class attribute is searched, descend- conceptdoesnotcoveranymeansexternaltothelanguageandpro- ing down the chain of base classes if necessary, and the method gram (meta programming), such as invoking a compiler or an eval reference is valid if this yields a function object. function to create a new function. Derived classes may override methods of their base classes. Because methods have no special privileges when calling other 2.2 Metaprogrammingwithon-the-flymethodpatching methods of the same object, a method of a base class that calls On-the-fly method patching, also known as bind unbound methods another method defined in the same base class may end up calling is some kind of attaching any method (which is actually a method a method of a derived class that overrides it. object) at a specific class in the way of meta programming. At An overriding method in a derived class may in fact want to this part I do not want to make use of some fancy explanation or extend rather than simply replace the base class method of the definition9. A simple example should visualize the functionality: same name. There is a simple way to call the base class method Wesimplycreate a class directly: just call BaseClassName.methodname(self, arguments). 10 This is occasionally useful to clients as well . class A: Pythonhastwobuilt-infunctionsthatworkwithinheritance[2]: b = 3 • Useisinstance() to check an instance’s type: isinstance(obj, int) and create an instance. will be True only if obj.__class__ is int or some class derived from int. a = A() • Use issubclass() to check class inheritance: issubclass(bool, print a.b int) is True since bool is a subclass of int. However, issub- 3 class(unicode, str) is False since unicode is not a subclass of Nowwecreateafirst-class function. str (they only share a common ancestor, basestring). def f( self , a) : 3.2 Small insertion - private variables return a + self .b "Private" instance variables that cannot be accessed except from in- sideanobjectdonotexistinPython.However,thereisaconvention Finally we install that function in the class. that is followed by most Python code: a name prefixed with an un- A. fred = f derscore (e.g. _spam) should be treated as a non-public part of the API(whetheritisafunction,amethodoradatamember).Itshould Socalling that function on the instance of A() does the trick. beconsideredanimplementationdetailandsubjecttochangewith- out notice [2]. print a. fred (4) Sincethereisavaliduse-caseforclass-privatemembers(namely 7 to avoid name clashes of names with names defined by subclasses), there is limited support for such a mechanism, called name man- gling 11. Any identifier of the form __spam (at least two leading 3. Inheritance underscores, at most one trailing underscore) is textually replaced with_classname__spam,whereclassnameisthecurrentclassname 3.1 Single inheritance with leading underscore(s) stripped. This mangling is done without Of course Python supports inheritance and even a limited form of regard to the syntactic position of the identifier, as long as it occurs multiple inheritance as well. The syntax looks basically like this: within the definition of a class. Note that the mangling rules are designed mostly to avoid acci- class DerivedClassName(BaseClassName): dents;itstill is possible to access or modify a variable that is consid- ered private. This can even be useful in special circumstances, such . . . as in the debugger. These rules are comparable to the Java keyword private but are completely voluntarily and are the responsibility of of the programmer. The name BaseClassName must be defined in a scope contain- ing the derived class definition. In place of a base class name, other 3.3 Multiple Inheritance arbitrary expressions are also allowed. This can be useful, for ex- Aclass definition with multiple base classes looks like this: ample, when the base class is defined in another module: class DerivedClassName(modname.BaseClassName class DerivedClassName(Base1 , Base2 , Base3) : ) : . . . Execution of a derived class definition is actually the same as
no reviews yet
Please Login to review.