Re: [Tutor] designing POOP
On Sat, Feb 9, 2008 at 9:46 AM, Alan Gauld [EMAIL PROTECTED] wrote: As I mentioned in an earlier mail it tends to oscillate in practice. You start off looking at the problem to identify the basic classes. Then you pick one or two and start designing those in detail and that identifies lower level classes. When you reach the point of being able to write some code you do so. The act of writing code brings up issues that get reflected back up the design - maybe even identifying new classes. Once you've written as much code as you can you go back up to the problem level, using your new found knowledge and design a bit more. Once you know enough to start coding go back into code mode again. This constant iteration between top level class discovery and low level class construction is what Grady Booch refers to in his book as Round Trip Gestalt Design and in practice is how most software other than the very biggest projects is built. I recently found the Grady Booch book: OBJECT ORIENTED DESIGN WITH APPLICATIONS. Benjamin Cummings, 1991. pg. 189: As Heinlein suggests, When faced with a problem you do not understand, do any part of it you do understand, then look at it again. This is just another way of describing round-trip gestalt design. pg. 517: round-trip gestalt design A style of design that emphasizes the incremental and iterative development of a system, through the refinement of different yet consistent logical and physical views of the system as a whole; the process of object-oriented design is guided by the concepts of round-trip gestalt design: round-trip gestalt design is a recognition of that fact that the big picture of a design affects its details, and that the details often reflect the big picture. Happy Programming. -- b h a a l u u at g m a i l dot c o m Kid on Bus: What are you gonna do today, Napoleon? Napoleon Dynamite: Whatever I feel like I wanna do. Gosh! ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Wed, Feb 20, 2008 at 7:53 PM, Alan Gauld [EMAIL PROTECTED] wrote: Michael Langford [EMAIL PROTECTED] wrote I'm firmly with Kent here: OO programming is not about simulation. Wooah! I'm partly on board here and do agree the noun/verb thing is a gross simplification. But it does work and is how probably the majority of OOP programmers started out - in the 80's and 90's at least. Certainly when I started on OOP around 1984 it was the de-facto introduction. And it is a still an effective way to identify objects if you aren't sure where to start. [snipped for brevity] Often it feels like the Model objects on real world objects is how people are taught so they get the idea of an object. Actually designing all code that way is a needless proscription that really really hurts many projects. I agree with this too. It has to be emphasised that it's only a starting point to identify object candidates, the final solution may look very different. But in my experience the bigger the project the closer the abstractions get to reality at least at the object identity level - the operations and data are likely to be very different, and underneath that layer will be a wealth of lower level abstractions unguessed at by nouns/verbs. But heh, if you get presented with a requirements spec of 400 pages and over 1000 user storiers (as I just have!) it's as good a place to start as any! (IMHO of course! :-) And hopefully no newbies on the tutor list is in any danger of that happening to them! -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld Which is currently dead awaiting a server repair, sorry! :-( Somewhere along the line (in the original thread) the idea of trying to teach a Beginner how to design an OOP in Python got lost in a bunch of java mumbo jumbo (at least, that's what it seemed like to me). After looking at a lot of stuff, and reading much more than I needed to, the technique that works best for me is the noun/verb technique. I think it is a good STARTING point! Now, I understand that there are many different levels of beginner. Some beginners are higher up the ladder than others, and they enjoy looking in windows higher up. However, I'm still on the bottom rung. The technique that I can relate to is the noun/verb technique. Does this mean that if I get a grasp of POOP with this technique that I'll be stuck on the bottom rung forever? I doubt it. No more than someone who is using whatever technique they are currently using is stuck with that technique forever. The universe unfolds perfectly. Time exists so it doesn't unfold all at once. I think the noun/verb technique is good for Absolute beginners. I haven't seen anything else that is so introductory. Too bad there isn't a graded tutorial that systematically uses the technique to build several working PYTHON OOPs. Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Michael Langford [EMAIL PROTECTED] wrote I'm firmly with Kent here: OO programming is not about simulation. Wooah! I'm partly on board here and do agree the noun/verb thing is a gross simplification. But it does work and is how probably the majority of OOP programmers started out - in the 80's and 90's at least. Certainly when I started on OOP around 1984 it was the de-facto introduction. And it is a still an effective way to identify objects if you aren't sure where to start. But it is not a good way to model software, with that I agree. But OOP is still about suimulation. A lot of OOP code - especially on very large scale projects is as close a simulation as possible to the real world problem as you can get. If you are going to work on 5-10 million lines of code you had better organise it according to some tangible model you can understand or you will have problems. Performance and efficiency come a long way behind comprehensibility at that scale. But on more normal projects, say 100K-1 million lines then other factors come to the fore, and flexibility of design is one big area where OOP techniques can help. RANT Unfortunately there seeems to be a lobby at work in OO these days (indeed in software engineering generally) that has forgotten about large scale stuff and treats the entire subject as if it were exclusively about small scale projects. This is unfortunate because software engineering was invented to tackle the large scale problems not the small, and this view also fails to recognise the very different approaches needed to cover both bases. Here in the Python community we rarely need to think big, I don't know of any really large projects being done in Python. But it is important to remember that topics like OOP cover all areas. /RANT are not modeling real world items. You are making code easier to maintain and making parts of code that have to do with one another be near one another. That's true of any design technique regardless of whether it is OOP or procedural or even of it's not software at all. However it's not somerthing that will help a beginner see objects in their code, especially since the resultant objects are often of the highly abstract or large grained variety. If you spend all your time trying to make your objects into real world things you're actually doing simulation, not programming. As a person who's actually done simulation, I'll state that 's not really a great way to structure code. You spend a lot of time arguing about highly abstract responsibilities of each object in your system, as well as how much it will actually model the real world. Neither one is especially helpful, This bit I do agree with. Model the real world to get a feel for the problem at hand, model the real world as an aid to identifying potential objects, model the real world while it helps solve the problem. But don't be a slave to it, you are writing a program to solve a problem not to model the world. Never forget which is the tool and which the result. But OTOH most of the programs I build or design are simulations, whether of a call centre, a manufacturing plant, a banking system or a local council, an airport traffic control system or a telephone switch - and the software invariably reflects that structure. It does not however model every feature of a PBX, lathe, teller etc It reflects the attributes of those objects that relate to the problem. programing. The Why of OO programming today is: To make code more maintainable/usable and to group and to use data in such a way the human mind can easily grasp all the abstract data types that a program operates on. And the latter point is one area where modelling based on real world entities can be a big plus. But based on them, not slavishly reproducing them. OO programing came from simulation people. They used a language (Simula) to do simulation. It allowed each object to have behavior linked to its type. And it is still used today within the simulation community. We have a fairly active Simula group at work doingnetwork analyses. Other people saw this (Smalltalk), then copied the system (which they were incidentally using to build Smalltalk at first), but not to simulate real world objects, Quite a lot of the early Smalltalk stuff did indeed copy real world objects but they also saw the potential in modelling virtual objects like the UI elements. They were using Smalltalk to teach/experiment with young children by that time and the correspondence between real objects - like pens - and computing devices was a beneficial side effect. When Bjarne Stroustrup made C++, he copied some of the ideas in order to make a better type system, where the functions that operated on a Yes, although he was actually using the tool to build a simulation. That's why he started with Simula... Object-oriented programming is programming using inheritance. Nit Pick I never agreed with Bjarne on that. There are a number
Re: [Tutor] designing POOP
I'm firmly with Kent here: OO programming is not about simulation. You are not modeling real world items. You are making code easier to maintain and making parts of code that have to do with one another be near one another. If you spend all your time trying to make your objects into real world things you're actually doing simulation, not programming. As a person who's actually done simulation, I'll state that 's not really a great way to structure code. You spend a lot of time arguing about highly abstract responsibilities of each object in your system, as well as how much it will actually model the real world. Neither one is especially helpful, as neither one is addressing the Why of OO programing. The Why of OO programming today is: To make code more maintainable/usable and to group and to use data in such a way the human mind can easily grasp all the abstract data types that a program operates on. OO programing came from simulation people. They used a language (Simula) to do simulation. It allowed each object to have behavior linked to its type. They were simulating combat and needed to model the behaviors of all the objects (ships) when they all interacted together. Other people saw this (Smalltalk), then copied the system (which they were incidentally using to build Smalltalk at first), but not to simulate real world objects, but to instead better group functions with the data that those functions operate on. Objects could be created on the fly in there system. They first coined the term Object Oriented Programming. They real novel thing they did with all of this was to build the first windowing GUI's and mice into a programming language. They were not modeling anything in the real world, they were putting all the components and methods pertaining to building a little square on the screen into a class, or all the methods pertaining to a mouse input into a class. When Bjarne Stroustrup made C++, he copied some of the ideas in order to make a better type system, where the functions that operated on a type were put together with the data into an abstract data type by his preprocessor (C++ was a preprocessor for many years before it was a compiler). In his own words: Object-oriented programming is programming using inheritance. Data abstraction is programming using user-defined types. With few exceptions, object-oriented programming can and ought to be a superset of data abstraction. The key feature of object is *that you make types* (and you put the methods with the type, as part of the type). That you can do polymorphism. Etc. OO is not a glorified simulation system, and you will feel pain if you overemphasize the generalization Model objects on real world objects. Objects do have to have an idea (Cohesion). It is just, that idea doesn't have to be congruous with something you can walk over to and pick up in the real world. Often it feels like the Model objects on real world objects is how people are taught so they get the idea of an object. Actually designing all code that way is a needless proscription that really really hurts many projects. --Michael On Fri, Feb 15, 2008 at 8:38 AM, Kent Johnson [EMAIL PROTECTED] wrote: Tiger12506 wrote: I like things to be explicit, and don't care for the level of abstraction common in MVC. I know it seems naive, but I like to be able to model object designs after tangible things, and to me, a View does not know how to keep a state or execute methods because it does not exist. A Controller does not exist alone of the model, and without the view it fails to work. I agree that this is a naive view, for the same reason I objected to Alan's find the nouns approach to OO design. For me considerations of cohesion, encapsulation, DRY, testability, and any required reuse or flexibility are far more important to design than correspondence with tangible objects. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor -- Michael Langford Phone: 404-386-0495 Consulting: http://www.RowdyLabs.com ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 [EMAIL PROTECTED] wrote Ah yes... I don't like the Model-View-Controller architecture. That the major reason why I dislike most information available on C++. This is a personal issue though. The Model-View-Controller is a very common thing, and everyone but me would be wise to use it. :-) Now I'm curious. MVC is one of the oldest, best established and well proven design patterns going. It first appeared in Smalltalk in the late 1970's and has been copied in almost every GUI and Web framework ever since. I've used it on virtually(*) every GUI I've ever built(**) to the extent that I don't even think about it much anymore, therefore: What do you dislike about it? And what do you use in its place? (*)The only exceptions were ObjectVision, a strange graphical Windows app builder from Borland and a weird scripting language for the very early X Windows toolkits(X10), which looked like csh and produced truly ugly GUIs very quickly. And, of course, native Tcl/Tk has a slightly different model. (**)Those include GUIs built in Smalltalk, Lisp, TurboPascal, Delphi, C/C++, ObjectiveC, Java, Python (of course) and even PL/SQL An alternative perspective is always interesting. Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Now I'm curious. MVC is one of the oldest, best established and well proven design patterns going. It first appeared in Smalltalk in the late 1970's and has been copied in almost every GUI and Web framework ever since. I've used it on virtually(*) every GUI I've ever built(**) to the extent that I don't even think about it much anymore, therefore: What do you dislike about it? And what do you use in its place? I may not be the most newbie around here, but I am certainly very newbish compared to you and Kent. That means that I do not have perhaps an adequate amount of experience in practical application, but I dislike the concept because in every situation that I have encountered so far, it has tripped me up. I like things to be explicit, and don't care for the level of abstraction common in MVC. I know it seems naive, but I like to be able to model object designs after tangible things, and to me, a View does not know how to keep a state or execute methods because it does not exist. A Controller does not exist alone of the model, and without the view it fails to work. Sure it helps tremendously in interchanging code pieces-reusability a big issue here, but for my purposes, it just seems extraneous. Seperating drawing and computations can be/cannot be convenient for me depending on the application, (my 'plotting' library is a code reusability mess) but in general my style of coding (more procedural) tends to get the job done and also tends to cut corners in just enough places to make me feel that the application is more efficient with resources. Asking what I use in its place very neatly makes me blush because I use no set model, but tend to mix them at my convenience. Have you noticed that I haven't posted code on this list in a long, long time??? Hehe. At any rate, I had noticed that I stepped past my line of authority and experience to the point at which I was significantly less capable to pose as an expert, and therefore I wrote everyone but me would be wise to use it. My apologies. (*)The only exceptions were ObjectVision, a strange graphical Windows app builder from Borland and a weird scripting language for the very early X Windows toolkits(X10), which looked like csh and produced truly ugly GUIs very quickly. And, of course, native Tcl/Tk has a slightly different model. (**)Those include GUIs built in Smalltalk, Lisp, TurboPascal, Delphi, C/C++, ObjectiveC, Java, Python (of course) and even PL/SQL An alternative perspective is always interesting. Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: This is fine and dandy but what if we want to find out the current value of a.value without calling inc? Thats where hetter/setter/direct access comes into the picture. In Java and some other languages the idiomatic thing to do is provide methods prefixed with get/set for each attribute class Counter(object): def __init__(self, initial=0, delta=1):... def inc(self)... def state(self):... def getDelta(self): return self.delta def getValue(self): return self.value def setValue(self, val): self.value = val def setDelta(self, val): self.delta = val Now this is a lot of typing! It also isn't necessary in Python because Python allows you to access the attributes diectly - direct access. To amplify and clarify a little: - Other languages can also give direct access to attributes, this is not unique to Python. Java and C++, at least (the languages I know), also have a way to *restrict* direct access to attributes which Python does not really have. - There is a good reason for using setters and getters in Java and C++ - they have no way to convert an attribute access into a method call. So if you start with attribute access and then realize you want to add some code to the access, you are stuck - you have to change the interface to the class. Python does not have this problem - attribute access can be converted to a method call using properties. For this reason, there is IMO (and as generally accepted usage) no advantage to using getters setters in Python for simple attribute access. Introduction to properties: http://personalpages.tds.net/~kent37/kk/8.html - Python does have a convention for documenting which attributes (including methods) are considered part of the public interface and which are not. Non-public attribute names are prefixed with _ (single underscore). This is a signal to users of the class that the attribute is considered an internal implementation detail and to use it at your own risk. This is consistent with the Python philosophy that we're all consenting adults here - i.e. that the users of a class don't need to be protected from shooting themselves in the foot - it is enough to put a warning sign on the gun and the foot :-) Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... Hmm. Not to me. The second version couples the game state with the display. I would rather have - a Game object that maintains the state of the game and has methods to manipulate the state - a Display object that displays the state of the game - a Controller object that mediates between user interaction, the Game and the Display. Something like: class Game(object): def __init__(self): self.score = 0 def handleSomethingGood(self): self.score += 1 class Display(object): def showScore(self, score): print score class Controller(object): def __init__(self, game, display): self.game = game self.display = display def handleButton(self): self.game.handleSomethingGood() self.display.showScore(self.game.score) Now Game.handleSomethingGood() is decoupled from both the display and the actual UI event that signals SomethingGood happened. This is an example of Model-View-Controller architecture (google it). Notice that the Game and Display are now reusable (maybe there are both GUI and text interfaces to the game, for example, or versions for wxPython and PyQt) and testable independently of each other. A more advanced design might register the Display as an observer of the Game score but I don't want to get into that... Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 [EMAIL PROTECTED] wrote Well, I don't know if this whole email was of use, but it makes the crux of the argument make sense to me. I thought it was pretty clear. And it highlights that the choices are like anything else in the world of engineering - a compromise. And the best compromise in any given situation might be different from the last time. Engineering is not an exact science. Alan G ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
To further document some points. This comes from PEP 8 (http://www.python.org/dev/peps/pep-0008/) For those who need authority : Author: Guido van Rossum guido at python.org, Barry Warsaw barry at python.org With this in mind, here are the Pythonic guidelines: - Public attributes should have no leading underscores. - If your public attribute name collides with a reserved keyword, append a single trailing underscore to your attribute name. This is preferable to an abbreviation or corrupted spelling. (However, notwithstanding this rule, 'cls' is the preferred spelling for any variable or argument which is known to be a class, especially the first argument to a class method.) Note 1: See the argument name recommendation above for class methods. - For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods. Keep in mind that Python provides an easy path to future enhancement, should you find that a simple data attribute needs to grow functional behavior. In that case, use properties to hide functional implementation behind simple data attribute access syntax. Note 1: Properties only work on new-style classes. Note 2: Try to keep the functional behavior side-effect free, although side-effects such as caching are generally fine. Note 3: Avoid using properties for computationally expensive operations; the attribute notation makes the caller believe that access is (relatively) cheap. - If your class is intended to be subclassed, and you have attributes that you do not want subclasses to use, consider naming them with double leading underscores and no trailing underscores. This invokes Python's name mangling algorithm, where the name of the class is mangled into the attribute name. This helps avoid attribute name collisions should subclasses inadvertently contain attributes with the same name. Note 1: Note that only the simple class name is used in the mangled name, so if a subclass chooses both the same class name and attribute name, you can still get name collisions. Note 2: Name mangling can make certain uses, such as debugging and __getattr__(), less convenient. However the name mangling algorithm is well documented and easy to perform manually. Note 3: Not everyone likes name mangling. Try to balance the need to avoid accidental name clashes with potential use by advanced callers. HTH ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. You just invalidated your own argument. Sure, the object's creator may have designated that the way to read the score is to take these screws out and measure the angle of these gears in ratio to those gears No, the object's creator designed that the way to get the score is to read it. but what are you really doing here? ...(you are thinking procedurally)... You are really just overlooking the fact that the object is being *read*, meaning that the *object itself returns a representation*. This tearing apart should be abstracted with a method. Why? Because you are used to do it that way? The meer fact that you say 'tearing open the case' YOU are saying it. I'm saying 'read the score'. as just another way to say 'read the score' suggests a method called readscore(). Maybe it suggests that to you, not to me. But hey, if it did suggest readscore() or getscore() then it might also suggest setscore() and then we might also make sure that score is an integer so we'd better declare it an integer and have an exception if it is ever used to hold another type, they we might just see the light and start programming Java. You are exactly right. It does not matter with what language you describe an action, because the interface should still remain the same whether you are reading an attribute, or calculating high level summation probabilities to find the score. You are still justvg.readscore() Nope, I'm just myVar = vg.score and there are even ways to make sure that when the user of the class writes that line he receives a high level summation probability just as if he'd called a method, remember this is Python. Your particular issue is with the simplicity of the attribute, we don't need a getter method. True. But that in agreement with the concept of OOP. Sorry, which concept? According to whom? If you decide to pick and choose whether an object does it or whether the developer does it, not only do you have inconsistency in your programming style, but you are no longer OBJECT-Oriented. Says who? Anyway, I'm no theoretician, I'm a mere programmer. We programmers deal with practical things so I don't really care if I'm in or out of your concept of object orientation. So long as my code is maintainable, extendable, and does what it's supposed to do I'm ok with it, object or non-object oriented. Anyway if you wish for better people than me to expose this to you I suggest you address the python-list ([EMAIL PROTECTED]) and post a message saying We should access properties through setters and getters, otherwise it is not TRUE OOP. I won't take responsibility for any flames. PS This is one of the big issues that developers have with the win32api. It is procedural in this section, OOP in this section, etc. and more time is spent actually look up these subtle differences to prevent errors than is used in actual coding. A perfect OOP library does not Need a reference book. A good OOP library should only need to propose a pattern. I like good references, I like good documentation. But hey, different strokes... The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). I completely disagree with your issue on REUSABILITY here. Are you familiar with the concept of subclassing? So if I subclass the class it's ok to mess with the property but if I use the class it's not? Why should that be so? What advantage would that give me? If I subclass it, then declare a getter that reads the property and
Re: [Tutor] designing POOP
This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. You just invalidated your own argument. Sure, the object's creator may have designated that the way to read the score is to take these screws out and measure the angle of these gears in ratio to those gears but what are you really doing here? ...(you are thinking procedurally)... You are really just overlooking the fact that the object is being *read*, meaning that the *object itself returns a representation*. This tearing apart should be abstracted with a method. The meer fact that you say 'tearing open the case' as just another way to say 'read the score' suggests a method called readscore(). You are exactly right. It does not matter with what language you describe an action, because the interface should still remain the same whether you are reading an attribute, or calculating high level summation probabilities to find the score. You are still justvg.readscore() Your particular issue is with the simplicity of the attribute, we don't need a getter method. True. But that in agreement with the concept of OOP. If you decide to pick and choose whether an object does it or whether the developer does it, not only do you have inconsistency in your programming style, but you are no longer OBJECT-Oriented. PS This is one of the big issues that developers have with the win32api. It is procedural in this section, OOP in this section, etc. and more time is spent actually look up these subtle differences to prevent errors than is used in actual coding. A perfect OOP library does not Need a reference book. A good OOP library should only need to propose a pattern. The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). I completely disagree with your issue on REUSABILITY here. Are you familiar with the concept of subclassing? Or if you wish to ignore the power of OOP, you can just add another method, which is still more realistic and intuitive than directly accessing an internal state variable. Perhaps your major issue here is whether or not score should be public? Alright. Give me one instance in daily usage of any video game where the score of a video game is changed without the video game knowing it. (example - cosmic rays change a bit in the storage of the score and the video game is not aware of it) This concept would allow a violation of a pure OOP VideoGame class, and allow an otherwise private internal state to be made public. PS - for fun. I can think of a more common reason why the score of video games would change without using the actual video game interface. I watched a tv episode of masterminds where the criminal thought up the perfect plan to trick a slot machine by directly accessing the physical chip that determined a winning combination. If the developer of the slot machine had wanted this to be the way that winning combinations are chosen, he should have provided a method which allowed for this. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 12, 2008 7:19 AM, Ricardo Aráoz [EMAIL PROTECTED] wrote: Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). Everything in this discussion seems relevant to designing Python OOP. (Python is not java, not javascript, not c++, not visual whatever etc.) We can see from this that Python does it the Python way. The Java examples are pretty much wasted on me. (I don't know anything about Java at all.) The POOP tutorials rarely get into design considerations. They introduce the mechanics of making a program, make a sample program, and keep on trucking. I'm trying to learn how to design a program with Python. So far, two beginner techniques have been shown: the noun/verb/adjective method (Alan), and the TDD (Test Driven Design) method (Kent). Of the two, the noun/verb/adjective method seems more approachable (to me). I think that once I have some experience doing that, then the TDD method may have something to offer. Baby steps first. Walk before running. 8^D Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 wrote: This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. Mmmm... that's not really so. If the object's creator meant the score to be read that way then it would not be 'Tear open the case' but just 'read the score'. The language with which we describe an action does matter. vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Did we think about REUSABILITY? What if in some other application I want to USE the score, not just display it? What if I want to display it in a different form (multiplying it by 100)? Then you are back to our original options : either check the score directly, define a getter, or a 'stater'(?) which returns the state of the object (in this case it would be a tuple with only the score in it, a getter in disguise if you ask me). AFAIK the python way is to just check the score, if later the object's author changes something he has ways built in in the language to keep the interface unchanged (yes, I think the score would be part of the interface, otherwise it would be _score). ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote States, getters-setters, direct access... I'm still in toilet-training here/ 8^D Can you provide some simple examples that illustrate exactly what and why there is any contention at all? I'll try. State is just a bit of jargon to describe the combined values of an objects attributes. Here is an example: class Counter(object): def __init__(self, initial=0, delta=1): self.value = initial self.delta = delta def inc(self) self.value += delta return self.value def state(self): return (self.value,self.delta) a = Counter() b = Counter(1) c = Counter(0,5) print a.state, b.state, c.state So all 3 objects have different combinations of values so they have different states. The state determines the value returned by the objects inc method x = a.inc() # x- 1 y = b.inc() # y - 2 z = c.inc() # z - 5 This is fine and dandy but what if we want to find out the current value of a.value without calling inc? Thats where hetter/setter/direct access comes into the picture. In Java and some other languages the idiomatic thing to do is provide methods prefixed with get/set for each attribute class Counter(object): def __init__(self, initial=0, delta=1):... def inc(self)... def state(self):... def getDelta(self): return self.delta def getValue(self): return self.value def setValue(self, val): self.value = val def setDelta(self, val): self.delta = val Now this is a lot of typing! It also isn't necessary in Python because Python allows you to access the attributes diectly - direct access. Like so: a.delta = 42 a.inc() print a.value This gives rise to a debate between the OOP purists who say that you should only access the internals of an object via a method(get/set) and the pragmatists who say its OK to use direct access. And old school OOPers like me say it would be better if you didn't need to use either since you should define the object in terms of higher level abstractions/methods. Now, with my pragmatic hat on I see no point whatsoever in writing reams of get/set code just for the salke of it, so if you must bypass the abstract methods use direct access. But what if you want all of the attributes - to print state say? Thats where the question of direct access versus a state() method comes in. My preference is to provide a single method that returns the values that you need (and in many cases thats less than all of the attributes!) rather than allowing, or even encouraging, direct access. The danger with direct access is that we use it not only for reading but also for directly modifying the attributes - and that is a bad OOP habit! (Remember: Objects do it to themselves!) For example we want to decrement a counter instead of incrementing. we could do it directly: c.value = c.value -5 But it would be better to do it in an OOP way. So the final issue (and Kent will no doubt have more to add from his perspective!) is if we do want to modify the Counter how do we do it (assuming we don't own the original class or too many other projects already use it to risk breaking them)? Well, the pure OOP way is by sub classing. Thus if we want a counter with a dec() method as well as an inc(), we can create one: class UpDownCounter(Counter): def dec(self): self.value -= self.delta return self.value Now if we make c an instance of UpDownCounter we can do: c = UpDownCounter(0,5) c.inc() print c.state() c.dec() print c.state() And this has the advantage that there is no impact on the other objects derived from the initial Counter class. Note that as well as adding methods you can also modify, or change entirely, the existing methods, that's called overriding a method and is probably left for later! I hope that makes sense, its about the simplest example I could come up with. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote States, getters-setters, direct access... I'm still in toilet-training here/ 8^D Can you provide some simple examples that illustrate exactly what and why there is any contention at all? One clear example I can think of that shows the views is this: Imagine you have a video game. You model it with a class. class VideoGame: pass But this video game will up your score if you hit this a particular button, which means that it needs to a) keep track of its score b) know what to do when the button is pushed class VideoGame: def __init__(self): self.score = 0 def buttonpush(self): self.score += 1 This is all fine and dandy, but the video game is pretty worthless unless it can show us what the score is. There are two ways to go about this. A) Give the video game a display which it updates, or B) Tear open the case of the video game and look at the actual gears that increment the score to read it. (imagine it's an old, old game - work with me here!) So, to print, you can... vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush() print vg.score#Tear open the case (hope you have a screwdriver) OR class VideoGame(): def __init__(self): self.score = 0 def updatedisp(): print self.score def buttonpush(): self.score += 1 self.updatedisp() vg = VideoGame() howmany = rand.randint(0,100) for i in range(howmany): vg.buttonpush()#Let the videogame display your score however it wishes The second way is preferable for many reasons... A) The game designer decides to change the display, you don't have to change any code that uses the class B) Clearly, tearing open a videogame is pretty low-level from an object perspective. This is what Alan is saying with OOP purism. Now. Alan's suggestion to have a state method is like... having a sticker on the side of the video game that constantly changes to show the internal state of the machine. (yeah yeah, stickers change, sure...) Anyway, This is very nice from a debugging standpoint, where you find out that the game does something incredibly weird, (like after 2**16 buttonpushes it jumps to negative numbers), so that you can watch exactly what happens inside the machine without tearing it apart. There are a few drawbacks though. As soon as you change the internal mechanism, the sticker is at a loss because it can't tell you the state anymore! So every time you change the internals, you have to change the sticker on the outside to reflect that change. This is what Kent is trying to say here about the lack of advantage to a state method. However, the advantage of pure OOP here is that if the videogame model is designed correctly, never would you have to change the actual display if you changed how the score was calculated. Well, I don't know if this whole email was of use, but it makes the crux of the argument make sense to me. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Kent Johnson [EMAIL PROTECTED] wrote The secondary reason is that a class author should be free to change the internal data of a class provided he doesn't change the message interface, but allowing direct access greatly increases the risk that a change will break some users code. Particularly if the change involves removing an attribute or converting it to a derived value. That is the usual argument for getters and setters in Java and C++ (at least). It makes sense for those languages but it doesn't hold water in Python where a simple attribute can be changed to a property with whatever underlying functionality you like and no change in client code. While that's true, it does move the onus onto the class maintainer to develop backwards compatible properties that may no longer have any releavance to the internal method code. For example a circle shape which moves from using a centre+radius system to one which uses a bounding box, or vice versa. (Although it could be argued that regardless of the implementation the radius/centre should be properties of the circle) But more dangerous is a database access class that stores the tablename and then changes database schema such that two names are needed, or vice versa, and direct access to that kind of attribute would be a very bad smell indeed! Why does the client need the tablename?! I think we are in general agreement, albeit with different levels of trust/toleration of the technique. Direct access is preferred to getter/setter methods but is in turn less desirable that higher level methods where they exist. The only contention seems to be whether a values() type mutilple-return method is worth anything over direct access. My personal taste is that if I need the entire official state of an object I'd like a method to give it me in one piece, but others obviously may feel differently. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 11, 2008 3:49 AM, Alan Gauld [EMAIL PROTECTED] wrote: I think we are in general agreement, albeit with different levels of trust/toleration of the technique. Direct access is preferred to getter/setter methods but is in turn less desirable that higher level methods where they exist. The only contention seems to be whether a values() type mutilple-return method is worth anything over direct access. My personal taste is that if I need the entire official state of an object I'd like a method to give it me in one piece, but others obviously may feel differently. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld States, getters-setters, direct access... I'm still in toilet-training here/ 8^D Can you provide some simple examples that illustrate exactly what and why there is any contention at all? TIA -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Sat, Feb 09, 2008 at 08:42:04PM -0500, Kent Johnson wrote: Alan Gauld wrote: def values(self): return (self.name, self.wealth, self.strenth) Or get rid of values() entirely and just refer to the attributes Nope, I don't like that as much since it encourages direct access. Maybe we just need to agree to disagree here. I don't see how returning a tuple is better encapsulation than direct access to named attributes. Here is something relevant to this argument, although I'm not sure that I agree with it: Getters and setters are evil. Evil, evil, I say! Python objects are not Java beans. Do not write getters and setters. This is what the 'property' built-in is for. And do not take that to mean that you should write getters and setters, and then wrap them in 'property'. That means that until you prove that you need anything more than a simple attribute access, don't write getters and setters. They are a waste of CPU time, but more important, they are a waste of programmer time. Not just for the people writing the code and tests, but for the people who have to read and understand them as well. In Java, you have to use getters and setters because using public fields gives you no opportunity to go back and change your mind later to using getters and setters. So in Java, you might as well get the chore out of the way up front. In Python, this is silly, because you can start with a normal attribute and change your mind at any time, without affecting any clients of the class. So, don't write getters and setters. extracted from: http://dirtsimple.org/2004/12/python-is-not-java.html Maybe I'm old school, but I still use getters and setters for access from outside the class and direct access from within methods in the class. - Dave [some good arguments snipped] -- Dave Kuhlman http://www.rexx.com/~dkuhlman ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Kent Johnson [EMAIL PROTECTED] wrote Alan doesn't like direct attribute access *or* getters and setters, IIUC. He wants all access to the attributes of a class instance to be through higher-level methods. I'd moderate that slightly. I really, really, don't like getters/setters. So, if you really need to get at an attribute then use direct access. However if a real responsibility of the class is to present it's overall state then I prefer to have a method to do that with state returned as a whole. For small numbers of attributes that could be a tuple or for longer sets of data as a dictionary. Over-use of direct access tends, in my experience, to lead to the temptation to move code that should be in the class (or a subclass) into client code. And it is avoidance of that temptation that is my main reason for providing a values() or state() type method, rather than using multiple attribute access. The secondary reason is that a class author should be free to change the internal data of a class provided he doesn't change the message interface, but allowing direct access greatly increases the risk that a change will break some users code. Particularly if the change involves removing an attribute or converting it to a derived value. Of course, as Kent pointed out if you add attributes then you have the question of whether to modify the state() method too, which also breaks client code - another reason state() methods should only return those attributes really needed by the clients!. They are less likely to change. I think it is a good goal and technique to look for higher-level methods, and to create classes that are amenable to same, but that on a practical level attribute access works and I don't avoid it on principle. I prefer it to getter/setter but try to avoid it if possible. Pragmatism means that sometimes its useful or even necessary, but I always question why I'm doing it and whether I should instead be adding a method or subclassing. And to close, the reason I made it an issue in this thread is that this is about a beginner learning good (P)OOP practice so I thought it would be good to highlight that direct access carries risk and is frowned on from a purist OOP perspective Hopefully this side discussion has done that :-) -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: Over-use of direct access tends, in my experience, to lead to the temptation to move code that should be in the class (or a subclass) into client code. And it is avoidance of that temptation that is my main reason for providing a values() or state() type method, rather than using multiple attribute access. I agree that it is easy to write code in a client, using attribute access, that really should be in the class as a method. I'm not sure how providing a value() method prevents that, other than making the client code more awkward. In either case the solution is to recognize the code smell (Feature Envy or Inappropriate Intimacy) and refactor to fix the problem. The secondary reason is that a class author should be free to change the internal data of a class provided he doesn't change the message interface, but allowing direct access greatly increases the risk that a change will break some users code. Particularly if the change involves removing an attribute or converting it to a derived value. That is the usual argument for getters and setters in Java and C++ (at least). It makes sense for those languages but it doesn't hold water in Python where a simple attribute can be changed to a property with whatever underlying functionality you like and no change in client code. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiger12506 [EMAIL PROTECTED] wrote Are some simple examples off the top of my head. It's not difficult to model real-life things with classes, but ... This is a good point, it is excellent practice for thinking about the responsibilities of objects ...it is much more difficult to model them in such a way that you interact with them normally. And this is the bit that does require experience and careful thought. But even thinking in the absract about doors, knobs,locks etc helps to get the brain attuned to the kind of decions that need to be made door, or the knob? Does the knob contain a Lock, or does the developer only need to know that it has one and whether it is locked or not?) And its important to remember that the answers will be problem dependant. There is no absolute right or wrong, just what works best for your problem. Of course that's why building reusable objects is so hard. Something apparently reusable will usually only be reusable within a single problem domain. And even then may need to be tweaked for the specific problem. It has been estimated that building reusable objects costs between 3-5 times as much as building a bespoke version (and commercially reusable objects cost up to 10 times as much!) Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 9, 2008 4:09 AM, Alan Gauld [EMAIL PROTECTED] wrote: Tiger12506 [EMAIL PROTECTED] wrote Are some simple examples off the top of my head. It's not difficult to model real-life things with classes, but ... This is a good point, it is excellent practice for thinking about the responsibilities of objects ...it is much more difficult to model them in such a way that you interact with them normally. And this is the bit that does require experience and careful thought. But even thinking in the absract about doors, knobs,locks etc helps to get the brain attuned to the kind of decions that need to be made I'm really getting a lot out of this discussion. In my tutorial (PPftAB2E) the second chapter deals with a Blackjack game. One thing I noticed (and remember, this is a Noob's viewpoint): The classes seemed to be designed from small to large, rather than from large to small. First, a card class was made that had card-object stuff in it (suits and ranks). Then a hand class was made that inherited the card class. Then, a deck class was made, that inherited from the hands class (that already had inherited from the card class). Is this the way you think about designing classes (small to large). I don't know the proper terminolgy for that yet. I'm almost ready to start working on another aspect of the adventure game. I've noticed in my tutorial that several small programs introduce various classes as the chapter proceeds, then at the end, it is all used to make the final program. That's fine for the book: no telling how long, or what he had to do to get it to work that way. But I'm just trying to figure out the design of the adventure game in small increments. If, in the end, I can use parts of these small programs to make the final program, great! But for now, I'm trying to keep it at a manageable size while I'm learning. There is a castle which has several levels and each level has rooms on it. The rooms have doors. The doors connect the rooms to each other. Each room can have either nothing in it, a treasure, or a monster. Each room has a description which describes 1) Is there a treasure in the room? (and if so, what is the amount), 2) Is there a monster in it (and if so, what is the Danger Level), 3) The room description, including where the doors are, (N,S,E,W,U,D). I'd like to try and design this small part so that the Explorer can move around the environment, from room to room, level to level. That's it. The Explorer will be able to see, but not pick-up treasure (keeping in mind that treasure can be picked-up in the final game). The Explorer will be warned about a monster in the room (keeping in mind that the monster can be fought in the final game). Design in small chucks. The Castle needs to be setup. Can the Travel Table from the procedural game be used? Setup requires that the floorplan, or map of the castle be used to define each room on a level, all the doors for the rooms, and treasure/terror. One array is used in the procedural program. Whoops! Sorry. I'm not supposed to think about it like that! If I use the small to large approach: A door is the smallest part of a room. Each room shares doors. Each floor has rooms. All the floors are in the Castle. But in this game, all the doors do is connect the rooms. They don't have knobs or locks. They don't open or close. (Although they MAY have that ability in some future game?). My thought is you can't possibly think of all the future things an object can do or be, but if the class is designed in a very abstract way, then it will be easier to add a new behavior or characteristic in the future, if needed? This is what I'm trying to learn with this adventure game exercise. So, I'm thinking that a door class isn't necessary? The next thing is a room. A room has doors that connect to other rooms, a description, and may contain a monster or treasure. This sounds like a candidate for a class? The castle has levels. Each level has rooms. Everything happens in the castle. The equivalent of the castle in the card game would be the deck of cards. But the deck of cards holds hands (rooms?) which are shuffled and dealt to people. It does something. What does the castle DO? It holds rooms, and monsters and treasure is shuffled and dealt to random rooms (for the Explorer to find). Not having much experience doing this, makes it harder than it should be! What is your thought process on this? door, or the knob? Does the knob contain a Lock, or does the developer only need to know that it has one and whether it is locked or not?) And its important to remember that the answers will be problem dependant. There is no absolute right or wrong, just what works best for your problem. Of course that's why building reusable objects is so hard. Something apparently reusable will usually only be reusable within a single problem domain. And even then may need to be tweaked for the specific problem. It has been estimated that
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote the second chapter deals with a Blackjack game. One thing I noticed (and remember, this is a Noob's viewpoint): The classes seemed to be designed from small to large, rather than from large to small. As I mentioned in an earlier mail it tends to oscillate in practice. You start off looking at the problem to identify the basic classes. Then you pick one or two and start designing those in detail and that identifies lower level classes. When you reach the point of being able to write some code you do so. The act of writing code brings up issues that get reflected back up the design - maybe even identifying new classes. Once you've written as much code as you can you go back up to the problem level, using your new found knowledge and design a bit more. Once you know enough to start coding go back into code mode again. This constant iteration between top level class discovery and low level class construction is what Grady Booch refers to in his book as Round Trip Gestalt Design and in practice is how most software other than the very biggest projects is built. I've noticed in my tutorial that several small programs introduce various classes as the chapter proceeds, then at the end, it is all used to make the final program. That's fine for the book: no telling how long, or what he had to do to get it to work that way. One of the problems of tutorials (my own included) is that you tend to focus on the code and never get round to explaining to the student how you worked out which classes to build in the first place! I tried to address that in the Games Framwork case syudy in the paper book version (try your local library) which deliberately sets out to create a class Framework step by step. But its quite hard to explain design techniques at the very early stages of programming. Thats why some of the design books I mentioed earlier are good (especially Booch) because they discuss the process of discovering classes and objects in the first place, and provide some basic heuristics to help. There is a castle which has several levels and each level has rooms on it. The rooms have doors. The doors connect the rooms to each other. Each room can have either nothing in it, a treasure, or a monster. Each room has a description which describes 1) Is there a treasure in the room? (and if so, what is the amount), 2) Is there a monster in it (and if so, what is the Danger Level), 3) The room description, including where the doors are, (N,S,E,W,U,D). I'd like to try and design this small part so that the Explorer can move around the environment, from room to room, level to level. That's it. The Explorer will be able to see, but not pick-up treasure (keeping in mind that treasure can be picked-up in the final game). The Explorer will be warned about a monster in the room (keeping in mind that the monster can be fought in the final game). Thats fine so you probably can start with a single room and your Explorer. Get the explorer to ask the room whats in it and then the Explorer can tell the Game what it has found. import room,explorer fred = Explorer('fred') room1 = Room(Dragon(),GoldRing(),Bread() room2 = Room(Serpent(),Bracelet(),Butter() fred.explore(room1) fred.describe() I am in a room with a dragon, a gold ring and a loaf od bread fred.explore(room2) fred.describe() I am in a room with a serpent, a bracelet and a pack of butter Once you have that working its a short step to make the castle contain a list of rooms with linkages between - possibly using a variant of your procedural table, but with Room objects rather than the raw data. The Room initialisation could read a data file to get the contents of each room... And the castle initialisation could read the data file to get the layout of the rooms - sounds like a job for the Python config file module maybe? And hppefully from the codec above you can start to think about what the expore method looks like inside? And maybe what method the room might need to support that? Design in small chucks. The Castle needs to be setup. Can the Travel Table from the procedural game be used? Setup requires that the floorplan, or map of the castle be used to define each room on a level, all the doors for the rooms, and treasure/terror. One array is used in the procedural program. Whoops! Sorry. I'm not supposed to think about it like that! No, thinking like that is fine when you are thinking about how the methods inside the classes work. So long as the castle stays concerned only with the layout of the rooms (how they are connected to each other) and the rooms look after the content within themselves. The Game class will then control the movement and action of the explorer. So if the user wants the explorer to go Siouth the Game can ask the Castle which room (if any) is Sourth of the current Room - and the explorer knows which room he is currently in so the Game can ask him that,
Re: [Tutor] designing POOP
On Feb 9, 2008 8:46 AM, Alan Gauld [EMAIL PROTECTED] wrote: bhaaluu [EMAIL PROTECTED] wrote Some more thoughts on designing here. You said I can use the procedural program as a program requirement because it defines I/O. Even though the OOP program will have the data and functions in classes, I'd like to have the finished program be identical to the procedural program as far as I/O goes. So the first little program's I/O looks like this: WHAT IS YOUR NAME, EXPLORER? _ - first prompt clrscr() ZORK, YOUR STRENGTH IS 100 YOU HAVE $ 75 IT IS TOO DARK TO SEE ANYTHING WHAT DO YOU WANT TO DO? _ - second prompt (main game) So I should be able to 'reuse' some of the code from the first little program, in the second little program where the castle is setup, and the player can move around the castle. IT IS TOO DARK TO SEE ANYTHING is replaced with the room description, as far as I/O goes, and I'd like for my second little sample program to follow suit. When you're designing a program, how do you go about dealing with text descriptions, like the descriptions for a room? Here is an example of a room description: THIS IS THE AUDIENCE CHAMBER THERE IS A WINDOW TO THE WEST. BY LOOKING TO THE RIGHT THROUGH IT YOU CAN SEE THE ENTRANCE TO THE CASTLE. DOORS LEAVE THIS ROOM TO THE NORTH, EAST AND SOUTH. In the procedural program, it is a function that prints the description: def room2(): print The player reads the description, and presses W. There is no west door. The program's output is: YOU CANNOT MOVE THROUGH SOLID STONE and back to the main prompt. Pressing S moves the player through the South door into another room, where the status of the player is displayed, and the description of the new room. The data.py file, with the room descriptions is the biggest file in the procedural program. I've been told that a data class with a lot of random data in it is a CodeSmell. Is a data class that has room descriptions in it, with a function for each room, considered a bad design? And, since the setup table and the function that decides which room description is closely related, couldn't they also be a part of that data class? Is a data class a CodeSmell when all the functions are related? Or, should I have a room class that can instantiate 19 room objects which simply accesses the room functions from the data.py file as it is? As a side note: Really, the adventure game isn't too much different from the Bank Account program in your tutorial:: there are several accounts in the adventure game which are credited and debited as the game progresses. Pick up treasure: credit my wealth account. Fight a monster: debit strength account. Move from room to room: debit strength account. Eat food: credit wealth account. Buy a weapon: debit wealth account. The real difference between the two is: moving about the castle and exploring in the adventure game. In the Bank Account, you are pretty much in one room. You enter the bank, and leave the bank after taking care of business. Note: I haven't tried your code snippet below yet, so please keep that in mind. I may have other thoughts after I try it. These are just some things I thought about while reading your reply. I don't have any comments below. -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] the second chapter deals with a Blackjack game. One thing I noticed (and remember, this is a Noob's viewpoint): The classes seemed to be designed from small to large, rather than from large to small. As I mentioned in an earlier mail it tends to oscillate in practice. You start off looking at the problem to identify the basic classes. Then you pick one or two and start designing those in detail and that identifies lower level classes. When you reach the point of being able to write some code you do so. The act of writing code brings up issues that get reflected back up the design - maybe even identifying new classes. Once you've written as much code as you can you go back up to the problem level, using your new found knowledge and design a bit more. Once you know enough to start coding go back into code mode again. This constant iteration between top level class discovery and low level class construction is what Grady Booch refers to in his book as Round Trip Gestalt Design and in practice is how most software other than the very biggest projects is built. I've noticed in my tutorial that several small programs introduce various classes as the chapter proceeds, then at the end, it is all used to make the final program. That's fine for the book: no telling how long, or what he had to do to get it to work that way. One of the problems of tutorials (my own included) is that you tend to
Re: [Tutor] designing POOP
bhaaluu wrote: When you're designing a program, how do you go about dealing with text descriptions, like the descriptions for a room? Here is an example of a room description: THIS IS THE AUDIENCE CHAMBER THERE IS A WINDOW TO THE WEST. BY LOOKING TO THE RIGHT THROUGH IT YOU CAN SEE THE ENTRANCE TO THE CASTLE. DOORS LEAVE THIS ROOM TO THE NORTH, EAST AND SOUTH. That would probably be an attribute of the Room class. The player reads the description, and presses W. There is no west door. The program's output is: YOU CANNOT MOVE THROUGH SOLID STONE and back to the main prompt. Pressing S moves the player through the South door into another room, where the status of the player is displayed, and the description of the new room. It might make sense for Room to have a move(direction) method that returns the resulting Room. Then room.move('W') would print the above message and return self. room.move('S') would return the room to the south. This requires that the rooms be linked together - each room knows the rooms that are adjacent to it. Another reasonable design is to have some kind of a Map object that holds the linkages between all the rooms, and a method move(from, direction) that takes both a Room and a direction. I don't know which of these would work better for your game. The data.py file, with the room descriptions is the biggest file in the procedural program. I've been told that a data class with a lot of random data in it is a CodeSmell. Is a data class that has room descriptions in it, with a function for each room, considered a bad design? A data file is fine. And, since the setup table and the function that decides which room description is closely related, couldn't they also be a part of that data class? Is a data class a CodeSmell when all the functions are related? I'm not sure I follow you. Are you talking about Room as a data class or some other class? What functions do you mean? A class with data and related functions is not a data class, it is good design. Or, should I have a room class that can instantiate 19 room objects which simply accesses the room functions from the data.py file as it is? Maybe you could give a short example of what you are doing. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
..., I'd like to have the finished program be identical to the procedural program as far as I/O goes. You could do it but it would be easier to change it a little because the original games prompts etc betray its internal structure. You can just get the objects to return their attributes and use string formatting to insert those in your prompts. But it might be better to have the objercts return the whole string including values. Of course you can do that easily with a default parameter in a method: class Explorer(object): fmtStr = My name is %s and I have wealth of $%s and strength of %s # other code here def describe(withText=False) values = (self.name, self.wealth, self.strenth) if not withText: return values else return fmtStr % values We can then call that as e = Explorer() e.describe(withText=True) # gets the long version or print You are an explorer whose name is %s, You have wealth of %s and strength of %s % e.describe() # uses tuple result Using this technique you could use exactly the same text as in the original or create a more OO variant where the objects all know how to describe themselves. Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote When you're designing a program, how do you go about dealing with text descriptions, like the descriptions for a room? Here is an example of a room description: THIS IS THE AUDIENCE CHAMBER THERE IS A WINDOW TO THE WEST. BY LOOKING TO THE RIGHT THROUGH IT YOU CAN SEE THE ENTRANCE TO THE CASTLE. DOORS LEAVE THIS ROOM TO THE NORTH, EAST AND SOUTH. You can use a class attribute as per my other email example. This attribute would contain %s markers to substitute the values as needed. And finally the actual text can be loaded from a data file by the init method. The player reads the description, and presses W. There is no west door. The program's output is: YOU CANNOT MOVE THROUGH SOLID STONE and back to the main prompt. Pressing S moves the player through the South door into another room, where the status of the player is displayed, and the description of the new room. OK, See my other porst but you could use the castle as a coordinator that determines which rooms are available from any other room. You can build that knowledge into the rooms - eg by passing the relationships in to the constructor but that gets hard to maintain, especially in 3D. So I prefer to have a coordinating object(the castle - or Kent suggested a Map) The data.py file, with the room descriptions is the biggest file in the procedural program. I've been told that a data class with a lot of random data in it is a CodeSmell. Is a data class that has room descriptions in it, with a function for each room, considered a bad design? The data isn't the problem its the functions and data being mixed in a class. Having a data file that classes use to set up common data(class attribnutes) is perfectly valid. And, since the setup table and the function that decides which room description is closely related, couldn't they also be a part of that data class? Is a data class a CodeSmell when all the functions are related? No a class with functions and the related data is exactly what you want. What you want to avoid is a classs that has data for two or more different object types. Or a class with only data. Or, should I have a room class that can instantiate 19 room objects which simply accesses the room functions from the data.py file as it is? The room objects don't use the functions in data.py rather those functions become the methods of the class and the data gets loaded by those methods into the instances. Remember, objects do it to themselves. Nothing outside the class should be changing the internal attributes. But it is OK for the class to load the data from outside - as in a config file. This is a good thing because it allows you to change the displayed messages without changing code. For example to support multiple languages... As a side note: Really, the adventure game isn't too much different from the Bank Account program in your tutorial:: there are several accounts in the adventure game which are credited and debited as the game progresses. Pick up treasure: credit my wealth account. Exactly so. And the ability to recognise that is a big step forward in recognising abstraction. Alan G ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: class Explorer(object): fmtStr = My name is %s and I have wealth of $%s and strength of %s # other code here def describe(withText=False) values = (self.name, self.wealth, self.strenth) if not withText: return values else return fmtStr % values Should be self.fmtStr or Explorer.fmtStr We can then call that as e = Explorer() e.describe(withText=True) # gets the long version or print You are an explorer whose name is %s, You have wealth of %s and strength of %s % e.describe() # uses tuple result Um, yuck. A function that returns either a string or a tuple depending on its parameter? How about class Explorer: ... def __str__(self): fmtStr = My name is %s and I have wealth of $%s and strength of %s return fmtStr % self.values() def values(self): return (self.name, self.wealth, self.strenth) Or get rid of values() entirely and just refer to the attributes directly - what if you want to print the values in a different order? Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Kent Johnson [EMAIL PROTECTED] wrote e = Explorer() e.describe(withText=True) # gets the long version or print You are an explorer whose name is %s, You have wealth of %s and strength of %s % e.describe() # uses tuple result Um, yuck. A function that returns either a string or a tuple depending on its parameter? How about Hmm, I don't have any problerm with that provided it's the same basic information thats returned in both formats. Using a flag to control format is quite common in report generators etc (either postscript or pdf or plain text etc) I would agree its not good if the actual data being returned was different. But in this case it's a caller selectable option so there should never be any confusion. class Explorer: ... def __str__(self): fmtStr = My name is %s and I have wealth of $%s and strength of %s return fmtStr % self.values() I thought about using the str method but decided against it since you couldn't easily get the string version for manipulation later - I thought - but of course you could just use the str() convertion: s = str(e) So yes that would be OK. def values(self): return (self.name, self.wealth, self.strenth) Or get rid of values() entirely and just refer to the attributes Nope, I don't like that as much since it encourages direct access. And although I don't object to that occasionally - and prefer it to writing getter methods - in the case where we are trying to generate a report I believe the object should support that directly by returning those values that represent it's state - which might include some that are dynamically calculated. - but mostly because the object (or its author) should decide what it wants the world to know about. directly - what if you want to print the values in a different order? returning a tuple means you can still access the individual elements via indexing if you don't like the order given. But you can (ie should) only access those attributes provided by the values() call. Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: def values(self): return (self.name, self.wealth, self.strenth) Or get rid of values() entirely and just refer to the attributes Nope, I don't like that as much since it encourages direct access. Maybe we just need to agree to disagree here. I don't see how returning a tuple is better encapsulation than direct access to named attributes. And what if an attribute is added? Do you add another value to the tuple, forcing every client to change? Start returning a value object with named attributes? :-) directly - what if you want to print the values in a different order? returning a tuple means you can still access the individual elements via indexing if you don't like the order given. But you can (ie should) only access those attributes provided by the values() call. So to print, say, strength, wealth and name, we can have values = explr.values() print values[2], values[1], values[0] or unpack the tuple and give them names again: strength, wealth, name = explr.values() print strength, wealth, name or just use the perfectly good names they already have: print explr.strength, explr.wealth, explr.name and of course unless you take extra steps to prevent it, direct attribute access is still available even with the values() method... Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote PyUnit: It really doesn't seem to be an absolute beginner technique. Unit tests and TDD is not a design technique per se. It is definitely not a technique for designing OOP programs its a programming technique that makes code more reliable (whether OOP or not). Where it does help in design is by focussing attention on how a class (or function) should behave from the consumers perspective. This is always a good thing. But TDD in itself will not help you identify classes or their interactions. It will help you build classes that are user friendly and work as expected. The noun/verb/adjective technique seems to be geared more towards beginners. I like the idea of that technique. It is completely intended for beginners. It is, in practice, a little too naive for production type use but it is a good starting point when you don't know where to go and don;t have lots of experience in the problem domain. What nouns/verbs does is identify candidate classes and operations. It says nothing about how those operations are to be coded or used. Once you know what classes you want to write TDD can help you build them better, but you have to identify them first! One thing I'm encouraged by: in Alan's tutorial, he says that I don't have to see the light to use POOP. Absolutely, you have been using string objects and file objects already. You can use classes to bundle data and methods together and use them in an object based approach without fully understanding OOP. But OOP does open up new avenues and possibilities and, particularly in larger programs, offers significant savings in effort and reuse. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: Unit tests and TDD is not a design technique per se. It is definitely not a technique for designing OOP programs its a programming technique that makes code more reliable (whether OOP or not). Where it does help in design is by focussing attention on how a class (or function) should behave from the consumers perspective. I agree that TDD is not a design technique, but it does strongly influence design by introducing testability as a design requirement. TDD strongly encourages loose coupling and reusability. - loose coupling because classes and functions that depend on many other classes/functions/modules are harder to test - reusability because of the loose coupling and because any code that has unit tests already has two clients - the production code and the tests. I like to say, no code is reusable until it has been reused. Although a bit of an overstatement, there is a lot of truth in it. It is very hard to anticipate how a bit of code might be reused without actual reuse. TDD provides an artificial second use which promotes reusability. TDD also promotes incremental development where the design evolves to meet current requirements. This is sometimes called Test-Driven Design: http://www.agiledata.org/essays/tdd.html http://www.salientblue.com/blog/?p=10 So TD development can be part of a process that includes design. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: class Explorer(object): player def __init__(self,name): initilaization method self.__name = name self.strength = 20 self.wealth = 60 def get_name(self): return self.__name There is no need for get_name(). Just refer to explr.name, the same as for strength and wealth. class Light(object): light switch def __init__(self,light): self.light = light def state(self): if self.light == 0: print ( IT IS TOO DARK TO SEE ANYTHING) else: print ( THE LIGHTS ARE ON, BUT NO ONE'S HOME) show_state() or print_state() might be a better name. If you call this method __str__() and just return the string instead of printing it, it will be called when you print switch def cs(): print \n*50 def main(): tally = 0 switch = Light(0) #instance cs() # clear screen name = raw_input( WHAT IS YOUR NAME, EXPLORER? ) explr = Explorer(name) while True: cs() # clear screen print ( %s, YOUR STRENGTH IS %d % (explr.get_name(), explr.strength)) print ( YOU HAVE $%d % explr.wealth) This could be Explorer.__str__(): def __str__(self): return %s, YOUR STRENGTH IS %d\n YOU HAVE $%d % (self.get_name(), self.strength, self.wealth) Then the prints become just print explr switch.state() print print answer = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) if answer.upper() == Q: break if answer.upper() == L: if switch.light == 1: switch.light = 0 else: switch.light = 1 explr.strength -= 5 explr.wealth -= 15 if explr.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(1) if explr.strength = 0: print print ( YOU DIED...) time.sleep(1) break This could be two Explorer methods: def change_wealth(self, incr): self.wealth += incr if self.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(1) Then call explr.change_wealth(-15) Strength is a little trickier because you need to break out of the loop. You could have def change_strength(self, incr): self.strength += incr if self.strength = 0: print print ( YOU DIED...) time.sleep(1) self.alive = False Then in Explorer.__init__() set self.alive = True and change the loop from while True: to while explr.alive: This would give you an Explorer class that actually does something useful. Kent else: print ( INVALID CHOICE) tally += 1 print print ( FINAL SCORE:) print (TALLY: %d % tally) print ( STRENGTH: %d % explr.strength) print ( WEALTH: $%d % explr.wealth) if __name__ == __main__: main() Happy Programming! ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 8, 2008 3:24 PM, Kent Johnson [EMAIL PROTECTED] wrote: and change the loop from while True: to while explr.alive: This would give you an Explorer class that actually does something useful. Kent It also cleaned up main(), and put everything in well defined packages at the top of the program. I can see do difference in game play. 8^D Here are your changes implemented, and working on my Linux system: #!/user/bin/python import time class Explorer(object): player def __init__(self,name): initilaization method self.name = name self.strength = 20 self.wealth = 60 self.alive = True def __str__(self): return %s, YOUR STRENGTH IS %d\n YOU HAVE $%d % (self.name, self.strength, self.wealth) def change_wealth(self, incr): self.wealth += incr if self.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(1) def change_strength(self, incr): self.strength += incr if self.strength = 0: print (\n\n YOU DIED...) time.sleep(1) self.alive = False class Light(object): light switch def __init__(self,light): self.light = light def __str__(self): if self.light == 0: return IT IS TOO DARK TO SEE ANYTHING else: return THE LIGHTS ARE ON, BUT NO ONE'S HOME def cs(): print \n*50 def main(): tally = 0 switch = Light(0) #instance cs() # clear screen name = raw_input( WHAT IS YOUR NAME, EXPLORER? ) explr = Explorer(name) while explr.alive: cs() # clear screen print explr print switch print print answer = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) if answer.upper() == Q: break if answer.upper() == L: if switch.light == 1: switch.light = 0 else: switch.light = 1 explr.change_wealth(-15) explr.change_strength(-5) else: print ( INVALID CHOICE) tally += 1 print print ( FINAL SCORE:) print (TALLY: %d % tally) print ( STRENGTH: %d % explr.strength) print ( WEALTH: $%d % explr.wealth) if __name__ == __main__: main() Thanks Kent! I like these small incremental changes with explanations. I especially like the way you took blocks of code from main() and made methods out of them. The actual code itself, hardly changed! Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 7, 2008 9:40 PM, Tiger12506 [EMAIL PROTECTED] wrote: There's a couple of errors in here that no one has addressed yet because the question was geared towards programming style... So now I will address them. Or undress them, I suppose. ;-) I didn't make much progress until I started thinking about the Explorer and Light classes as actual objects. I've tried to address what you undressed. 8^D Here is another version to undress: #!/user/bin/python import time class Explorer(object): player def __init__(self,name): initilaization method self.__name = name self.strength = 20 self.wealth = 60 def get_name(self): return self.__name class Light(object): light switch def __init__(self,light): self.light = light def state(self): if self.light == 0: print ( IT IS TOO DARK TO SEE ANYTHING) else: print ( THE LIGHTS ARE ON, BUT NO ONE'S HOME) def cs(): print \n*50 def main(): tally = 0 switch = Light(0) #instance cs() # clear screen name = raw_input( WHAT IS YOUR NAME, EXPLORER? ) explr = Explorer(name) while True: cs() # clear screen print ( %s, YOUR STRENGTH IS %d % (explr.get_name(), explr.strength)) print ( YOU HAVE $%d % explr.wealth) switch.state() print print answer = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) if answer.upper() == Q: break if answer.upper() == L: if switch.light == 1: switch.light = 0 else: switch.light = 1 explr.strength -= 5 explr.wealth -= 15 if explr.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(1) if explr.strength = 0: print print ( YOU DIED...) time.sleep(1) break else: print ( INVALID CHOICE) tally += 1 print print ( FINAL SCORE:) print (TALLY: %d % tally) print ( STRENGTH: %d % explr.strength) print ( WEALTH: $%d % explr.wealth) if __name__ == __main__: main() Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 8, 2008 4:46 PM, Kent Johnson [EMAIL PROTECTED] wrote: bhaaluu wrote: It also cleaned up main(), and put everything in well defined packages at the top of the program. Yes, good OOD puts things into cohesive, comprehensible packages. I can see do difference in game play. 8^D And that's a good thing, right? Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. -- Martin Fowler in Refactoring The refactoring you just did is called Extract Method: http://www.refactoring.com/catalog/extractMethod.html Kent This is something that one can only gain from experience? I really had to struggle to get the Light class to work at all. I have no idea how many times I started over. But I do feel that I am starting to learn some of this stuff. As simple as the adventure game is, I can see that it will provide lots of practice for me to design and code it in Python OOP. Thanks Kent! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: On Feb 8, 2008 4:46 PM, Kent Johnson [EMAIL PROTECTED] wrote: Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. -- Martin Fowler in Refactoring This is something that one can only gain from experience? Experience and study. I don't think there is much substitute for experience to see *why* OOP and refactoring and clean design are useful. There is nothing like growing a program to the point where you don't know how it works or how to change it to make you appreciate good design :-) Studying gives you good examples to follow and new techniques to try. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: It also cleaned up main(), and put everything in well defined packages at the top of the program. Yes, good OOD puts things into cohesive, comprehensible packages. I can see do difference in game play. 8^D And that's a good thing, right? Refactoring is the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure. -- Martin Fowler in Refactoring The refactoring you just did is called Extract Method: http://www.refactoring.com/catalog/extractMethod.html Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
This is something that one can only gain from experience? I really had to struggle to get the Light class to work at all. I have no idea how many times I started over. But I do feel that I am starting to learn some of this stuff. This surprises me... I guess it does take experience. What is the most basic thing you can describe about a light? Immediately I answer, You can turn it on or off. This suggests methods, turn_on(), turn_off(), and something to maintain the state of the light attribute - i.e. whether it is currently on or not. I suggest practice practice practice. You should be able to look at anything in your house and be able to design a basic class for it. Some that come to mind as I look around the room. I've often thought of redesigning my entire house in OOP. ;-) (Granted - these examples aren't entirely useful, but they provide examples of practice with methods and attributes.) class Pen: def __init__(self): self.level = 50 self.on = False def click(self): self.on = (not self.on) def isempty(self): return (self.level 0) def write(self): if self.isempty: return False if not self.on: return False self.level = self.level - 5 return True class Knob: def __init__(self, locked=False): self.locked = locked def turn(self): if self.locked: return False return True class Door: def __init__(self): self.knob = Knob() def lock(self): self.knob.locked = True def unlock(self): self.knob.locked = False def open(self): return self.knob.turn() Are some simple examples off the top of my head. It's not difficult to model real-life things with classes, but it is much more difficult to model them in such a way that you interact with them normally. (i.e. do you lock the door, or the knob? Does the knob contain a Lock, or does the developer only need to know that it has one and whether it is locked or not?) ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote There have been lots of comments about this already but I'm deliberately jumping in at this level because I want to pick up a few general points... class Explorer(object): player def __init__(self,name): initilaization method self.__name = name self.strength = 20 self.wealth = 60 def get_name(self): return self.__name Kent already pointed out this is not needed. But as a general rule consider what I said earlier about objects being based on behaviour. And that the data should be there to support the behaviour. So in this case ask: Why do I have a name, strength and wealth? What behaviour do these support? Behaviour is expressed as methods so I am expecting to see methods sof Explorer that use the attributes, otherwise the Explorer is just a data container like a list or dictionary. class Light(object): light switch def __init__(self,light): self.light = light def state(self): if self.light == 0: print ( IT IS TOO DARK TO SEE ANYTHING) else: print ( THE LIGHTS ARE ON, BUT NO ONE'S HOME) You have a method here that reports the state but doesn't a light switch usually do something? Like turn the light on or off? Usually by a toggle operation? So maybe a toggle method would be good: def toggle(self): self.light == not self.light # make it a boolean Also remembering the principle that UI and logic should be separated it might be good to pull the printing out of the class and just let the method returmn the string. And as Kent already suggested for Explorer that could be done with an __str__ method so all you need do in the consumer is: print switch def cs(): print \n*50 def main(): tally = 0 switch = Light(0) #instance cs() # clear screen name = raw_input( WHAT IS YOUR NAME, EXPLORER? ) explr = Explorer(name) while True: cs() # clear screen print ( %s, YOUR STRENGTH IS %d % (explr.get_name(), explr.strength)) print ( YOU HAVE $%d % explr.wealth) Kent has addressed this specifically but as a general rule remember the consumer should not have to get at the data attributes of an object. You should only need to send messages to the Explorer, in this case it's a status report - which we already said can be done via a __str__ method. switch.state() print print answer = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) if answer.upper() == Q: break if answer.upper() == L: if switch.light == 1: switch.light = 0 else: switch.light = 1 And here is the toggle method, except its in your program rather than in the object. Let the object do it to itself, do not try to mess with the data directly if answer.upper() == L: switch.toggle() explr.strength -= 5 explr.wealth -= 15 Now I'm not quite sure why you decrease these but again the Explorer should be doing it to himself - objects do it to themselves. If the Explorer always loses strengty and wealth after a turn then the method could be called newTurn() or somesuch. But I suspect there might be a more meaningful name we could use. if explr.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(1) if explr.strength = 0: print print ( YOU DIED...) time.sleep(1) break And all of this could be built into the explorer method above, maybe implemented as an exception? def newTiurn(self): self.wealth -= 15 self.strength -= 5 if self.wealth = 0: raise ExplorerBroke if self.strength = 0 raise ExplorerDied You control code then looks something like: if answer.upper() == L: switch.toggle() try: explr.newTurn() except ExplorerBroke e: print e.message except ExplorerDied e: print e.message Or with a bit more intelligence in the __str__ method if answer.upper() == L: switch.toggle() try: explr.newTurn() except ExplorerBroke,ExplorerDied: print explr Really the outside control code should be focused around the user interaction and senmding messages to the objects. It should not be pulling out data from inside the objects to do anything with it, that is the job of the objects. Occasionally we can break that rule if its just for printing or maybe to assign directly to another value. For example you could directly access switch.light if you needed to pass that into a method of explorer
Re: [Tutor] designing POOP
There is nothing like growing a program to the point where you don't know how it works or how to change it to make you appreciate good design Amen. I was recently fighting with an example of a multi-client, simple server that I wanted to translate into assembly. Not only was the code unreadable, but they had tried to apply a functional programming technique that failed miserably. Final result: Less # of lines, better readability, and slightly more algorithm efficient. Even with that change of language to something horrendously verbose. Key idea: Choose a design wisely. Understand that if a design does not enhance readability or code reusability, it's a bad design. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Kent Johnson [EMAIL PROTECTED] wrote Let me say that I don't mean any disrespect for Alan or his approach, I just have a different point of view. Heh, heh! I was waiting for someone to post a message like this. I'll respond by saying the noun/verb thing is not actually the method I would normally use (although when all else fails I do drop back to it as a starter technique). However I have found it to be a techhnique that woerks well for beginners who don't know how to get started. Partly because it is fairly mechanistic. But noun/verb does have some problems and often produces designs that have too many classes and that do not make best use of OOP idioms like polymorphism or abstraction. But for beginners and in small problems it is a good starter. Also I will say that converting a procedural program to OO 'just because' is not necessarily a good idea. Not every program is improved by OOP. In your case, it probably will be though. This is absolutely true. Too many people approach OOP as if it were some kind of holy grail that is inherently better than other styles - it isn't, its just another tool in the toolkit. I tend to work from small pieces to larger ones and let the design grow from the needs of the code, rather than from considerations of nouns and verbs in the spec. I agree at the micro level and in fact my discussion of explorers and monsters merging into a figher superclass hopefully illustrates how that micro level design/code cycle can generate new features of a design including new classes/objects. Many OO Design gurus have commented on the way that OO design tends to cycle between top down design - identifying core classes - and bottom up design - writing the lowest building blocks and using that to discover more about the higher level needs. OO design is a very organic process compared to procedural design which tends to bemuch more top down and heirarchical in nature. In my experience at least. accommodate it. Design a little, code a little, repeat... http://personalpages.tds.net/~kent37/stories/3.html Exactly so. The writings of Robert C Martin have taught me a lot about good design and agile development. They don't all apply to Python Martin is very good on Agile, I'm less impressed with his OO writing, largely because he does tend to see the world through the eyes of C++ and Java, both of which have a very singular view of OO which does not always work in other more dynamic OOP languages (Lisp, Smalltalk, Python, JavaScript etc) I don't use the command-line interpreter much, I do a lot more work in unit tests. In test-driven development (TDD), if you decide you want a Room class, the first thing you do is create a unit test for the class. For production programming I wholly endorse that approach, for exploring and inventing code structures (which is mainly what I use Python for, the results get converted to Java where we use TDD) I find the interpreter is very useful. To use TDD effectively you first need to know what you are trying to do. An example of bad use of TDD can be found in one of Robert Martins books where he tries to give an example of pair programming of a bowling game scorer. Unfortunately because of the haphazard design approach they wind up with code that is both bloated (it repeats an algorithm twice) and faulty (one of the algorithm implementations is broken). Unfortunately they don't detect the fault because the test data they used missed out all of the cases where the defect is exhibited... Note it wasn't the test that was broken it was the limited data set used. And that is one of the big limitations of TDD, it is only as effective as the test data. It is important to realize that there is no single way to design OOP programs. The noun/verb thing is a good way to get started and often effective when nothing else seems to be working. But there are plenty of other approaches out there and books by authors like Booch, Rumbaugh, Jacobsen, Schaer/Mellor, Coad/Yourdon, Wirfs-Brock and yes, Robert Martin are all worh reading to see the different approaches available. The Coad/Nicola OOP book is especially interesting because it contrasts the same problems in C++ and Smalltalk (which is conceptually close to python) and shows how the choice of language can have a big impact on detailed OOP design decisions. Once you get experienced in OPP you will not use the noun/verb te4chnique very often because your brain will start to think in terms of objects without need of intermediate tools. In fact when I went back to COBOL for the Y2K bug I found it hard initially to think procedurally because I'd been using OOP for so long by then. Nowadays I don;t write so much code I find I switch between both modes of design without really thinking too much about it. On small scale stuff I tend to go procedural but on big problems I tend to go OOP. Alan G. ___ Tutor maillist -
Re: [Tutor] designing POOP
On Feb 6, 2008 8:15 PM, Kent Johnson [EMAIL PROTECTED] wrote: Design a little, code a little, repeat... http://personalpages.tds.net/~kent37/stories/3.html You can discover many useful design techniques by applying DRY. More here: http://personalpages.tds.net/~kent37/stories/00012.html It has a chapter that explains the code smells and points out ways to fix them. An abbreviated version is available here: http://wiki.java.net/bin/view/People/SmellsToRefactorings The writings of Robert C Martin have taught me a lot about good design and agile development. A lot of his work is available on-line: http://objectmentor.com/resources/publishedArticles.html http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf might be a good starting point. http://objectmentor.com/resources/articles/xpepisode.htm attempts to give the flavor of agile, test-driven development. I don't use the command-line interpreter much, I do a lot more work in unit tests. I have written a little more about this here: http://personalpages.tds.net/~kent37/stories/7.html HTH, Kent Thank you Kent! I am open to all suggestions as to where to get started learning how to design with the Python Object-Oriented Paradigm. I'm doing a lot of reading, some coding (in my 'testing' directory), and a lot of thinking about what I'm trying to do. This is a learning situation. Since I'm a Hobbyist programmer, I don't have a 'class' deadline to meet (and believe me, I'm happy about that!). I do feel that learning how to do this will enhance the enjoyment of my Hobby for years to come. I do know that it will open a lot of doors for me that are currently closed, especially when it comes to creating games with Python/PyGame, and so forth. Plus, it is quite possible that this discussion will benefit others who are also just beginning. Happy Happy Joy Joy. -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld wrote: Kent Johnson [EMAIL PROTECTED] wrote The writings of Robert C Martin have taught me a lot about good design and agile development. They don't all apply to Python Martin is very good on Agile, I'm less impressed with his OO writing, largely because he does tend to see the world through the eyes of C++ and Java, both of which have a very singular view of OO which does not always work in other more dynamic OOP languages (Lisp, Smalltalk, Python, JavaScript etc) I found his writing on principles of OO design very helpful when I was a C++ programmer. I admit I have not revisited them from the point-of-view of a Python programmer. I'm sure some of the techniques are not needed - the pervasive use of interfaces, in particular - but the underlying principles should still apply. Taking a closer look, I think these still have something to offer: The Liskov Substitution Principle http://objectmentor.com/resources/articles/lsp.pdf Inheritance vs. Delegation (Template Method and Strategy patterns) http://objectmentor.com/resources/articles/inheritanceVsDelegation.pdf The Craftsman series might be of interest. One thing to keep in mind is that when C++ and Java use interfaces, Python uses duck typing. C++ and Java use classes to encapsulate functions (e.g. in Strategy) but Python can use functions directly. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Sorry, my bad - this was my me, but I forgot to hit Reply All. My me? I think I meant to type my message. -- www.fsrtechnologies.com ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: Best practice? Use class attributes when you actually want a shared attribute, for example for constants with class scope, or as defaults when instance attributes may not be assigned. Class attributes can be redefined by subclasses which makes them useful as a way to configure a class. Don't use them strictly as documentation. Write a docstring instead. My $.02 Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Also beware the difference between reassigning and extending: class F: a = 3 b = [] def __init__(self, a, b): self.a = a self.b.append(b) def show(self): print self.a, self.b f1=F(1,2) f2=F(3,4) f1.show() # 1 [2, 4] f2.show() # 3 [2, 4] -- Bob Gailer 919-636-4239 Chapel Hill, NC ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
I was asked: quote Here's a situation I often encounter, and I was wondering what the best practice is. I've generally initialized my classes' attributes this same way: class TestClass1(object): please give me a better name def __init__(self): please document me self.name = self.answer = self.strength = 20 self.wealth = 45 self.light = 0 self.tally = 0 but it could also be done like so: class TestClass1(object): please give me a better name name = answer = strength = 20 wealth = 45 light = 0 tally = 0 def __init__(self,name=Zed): please document me self.name = name ...etc. I realize that the two are NOT equivalent if you're using the class as a static class, rather than instantiating it (e.g. using a static class called Global while weaning oneself from global variables...) However, I'm asking about this present case: the class under discussion will always be instantiated. It seems to me that declaring the attributes in the class body makes the class more amenable to introspection, but are there downsides I'm not seeing? What's the best practice? /quote I've tried both ways and can't see any difference between the two as far as input/output is concerned. Best practice? -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: The TDD method is the method used in my tutorial: Python Programming for the Absolute Beginner 2E. Michael Dawson. 2006. Dawson uses a very simple Tamagotchi example called Critter Caretaker to introduce the mechanics of POOP. However, perhaps he is using the TDD method of design? I don't think Dawson uses TDD. AFAIK he doesn't talk about unit-testing at all, which is the fundamental practice of TDD. For an example of unit tests in Python, see http://docs.python.org/lib/minimal-example.html here is a first little testing snippet from the testing directory, using the TDD method. I'm confident that if I am using the terminology incorrectly, someone will point out the error of my ways. I think you are using the terminology incorrectly. I would call this an example of experimental programming, maybe. A classic example of TDD in Java is here: http://junit.sourceforge.net/doc/testinfected/testing.htm class TestClass1(object): please give me a better name def __init__(self): please document me self.name = self.answer = self.strength = 20 self.wealth = 45 self.light = 0 self.tally = 0 This is a good example of a data class - a class that is just a container for data. That is a code smell. It seems to contain unrelated values - name and strength are attributes of the player, light is an attribute of the environment. So it should probably be more than one class, or, since the entire program is in one loop, these could just be local variables of main(). def main(): tc1 = TestClass1() # instance tc1.__init__() # invoke method The __init__() method is called implicitly by calling TestClass1(). Generally the only time you explicitly call __init__() is when calling the method of a base class. Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 7, 2008 4:58 PM, Eric Brunson [EMAIL PROTECTED] wrote: bhaaluu wrote: What is the equivalent of JUnit in Python? The article says that JUnit is used for unit tests, or you can write your own. Since I don't have a clue, writing my own is probably out the question. Also I'm not familiar with Java, and am just learning Python OOP, so I'm not getting much out of that one. Sorry. Absolute Beginner here. http://www.google.com/search?q=python+unit+test Cleverly called unittest, though sometimes referred to by its original project name PyUnit. :-) Cool! http://docs.python.org/lib/module-unittest.html The Python unit testing framework, sometimes referred to as ``PyUnit,'' is a Python language version of JUnit, by Kent Beck and Erich Gamma. JUnit is, in turn, a Java version of Kent's Smalltalk testing framework. Each is the de facto standard unit testing framework for its respective language. Who would have thunk it? I'll Google and see if I can find a nice PyUnit tutorial. So, is my first try dong a unit test a total bit-bucket case? No way to make a test case out of it? That would be a good example (for me). 8^D -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Greetings, I've read both Kent's and Alan's approaches to designing a POOP, and am intrigued with the possibilities of the noun/verb/adjective technique, but am also sympathetic to the TDD method as well because it is how I've always programmed. I have noted Alan's comments on the limitations of TDD, as well as the limitations of the noun/verb/adjective method of design. The TDD method is the method used in my tutorial: Python Programming for the Absolute Beginner 2E. Michael Dawson. 2006. Dawson uses a very simple Tamagotchi example called Critter Caretaker to introduce the mechanics of POOP. However, perhaps he is using the TDD method of design? I'm still experimenting with the noun/verb/adjective design technique, but I was also itching to get started on something as well, so here is a first little testing snippet from the testing directory, using the TDD method. I'm confident that if I am using the terminology incorrectly, someone will point out the error of my ways. The Tutors are always saying they really can't help unless they see some code, so this is a simple adventure game that involves switching a light on and off. The gameplay isn't all that great, but it is a start. 8^D #!/user/bin/python From the testing laboratory of: b h a a l u u at g m a i l dot c o m 2008-02-07 import time CS = \n*50 class TestClass1(object): please give me a better name def __init__(self): please document me self.name = self.answer = self.strength = 20 self.wealth = 45 self.light = 0 self.tally = 0 def main(): tc1 = TestClass1() # instance tc1.__init__() # invoke method print CS N1 = tc1.name N1 = raw_input( WHAT IS YOUR NAME, EXPLORER? ) # main game loop while True: print CS print ( %s, YOUR STRENGTH IS %d) % (N1, tc1.strength) print ( YOU HAVE $%d) % tc1.wealth if tc1.light == 0: print ( IT IS TOO DARK TO SEE ANYTHING) else: print ( THE LIGHT'S ON, BUT NO ONE'S HOME) print print A = tc1.answer A = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) # main game prompt if A.upper() == Q: break if A.upper() == L: light = raw_input( LIGHT? [0|1]: ) # turn the light on and off if light == 0 and tc1.light == 0: print ( THE LIGHT IS OFF) time.sleep(2) if tc1.wealth = 0: print print ( YOU HAVE NO MONEY) time.sleep(2) else: tc1.light = int(light) tc1.wealth -= 15 else: print ( INVALID CHOICE) time.sleep(2) tc1.tally += 1 tc1.strength -= 5 if tc1.strength = 0: print ( YOU DIED) time.sleep(2) break print print ( Final Score:) print (Tally: %d) % tc1.tally print ( Wealth: $%d) % tc1.wealth print ( Strength: %d) % tc1.strength if __name__ == __main__: main() On Feb 7, 2008 4:15 AM, Alan Gauld [EMAIL PROTECTED] wrote: Kent Johnson [EMAIL PROTECTED] wrote Let me say that I don't mean any disrespect for Alan or his approach, I just have a different point of view. Heh, heh! I was waiting for someone to post a message like this. I'll respond by saying the noun/verb thing is not actually the method I would normally use (although when all else fails I do drop back to it as a starter technique). However I have found it to be a techhnique that woerks well for beginners who don't know how to get started. Partly because it is fairly mechanistic. But noun/verb does have some problems and often produces designs that have too many classes and that do not make best use of OOP idioms like polymorphism or abstraction. But for beginners and in small problems it is a good starter. Also I will say that converting a procedural program to OO 'just because' is not necessarily a good idea. Not every program is improved by OOP. In your case, it probably will be though. This is absolutely true. Too many people approach OOP as if it were some kind of holy grail that is inherently better than other styles - it isn't, its just another tool in the toolkit. I tend to work from small pieces to larger ones and let the design grow from the needs of the code, rather than from considerations of nouns and verbs in the spec. I agree at the micro level and in fact my discussion of explorers and monsters merging into a figher superclass hopefully illustrates how that micro level design/code cycle can generate new features of a design including new classes/objects. Many OO Design gurus have commented on the way that OO design tends to cycle between top down design - identifying core classes - and bottom up design - writing the lowest building blocks and using that to discover more about the higher level needs. OO
Re: [Tutor] designing POOP
On Feb 7, 2008 4:07 PM, Kent Johnson [EMAIL PROTECTED] wrote: bhaaluu wrote: The TDD method is the method used in my tutorial: Python Programming for the Absolute Beginner 2E. Michael Dawson. 2006. Dawson uses a very simple Tamagotchi example called Critter Caretaker to introduce the mechanics of POOP. However, perhaps he is using the TDD method of design? I don't think Dawson uses TDD. AFAIK he doesn't talk about unit-testing at all, which is the fundamental practice of TDD. For an example of unit tests in Python, see http://docs.python.org/lib/minimal-example.html here is a first little testing snippet from the testing directory, using the TDD method. I'm confident that if I am using the terminology incorrectly, someone will point out the error of my ways. I think you are using the terminology incorrectly. I would call this an example of experimental programming, maybe. A classic example of TDD in Java is here: http://junit.sourceforge.net/doc/testinfected/testing.htm What is the equivalent of JUnit in Python? The article says that JUnit is used for unit tests, or you can write your own. Since I don't have a clue, writing my own is probably out the question. Also I'm not familiar with Java, and am just learning Python OOP, so I'm not getting much out of that one. Sorry. Absolute Beginner here. class TestClass1(object): please give me a better name def __init__(self): please document me self.name = self.answer = self.strength = 20 self.wealth = 45 self.light = 0 self.tally = 0 This is a good example of a data class - a class that is just a container for data. That is a code smell. It seems to contain unrelated values - name and strength are attributes of the player, light is an attribute of the environment. So it should probably be more than one class, or, since the entire program is in one loop, these could just be local variables of main(). Well, most of these were local variables in main() in the procedural version of this program. So DataClass() is what I should name such a class. I was wondering about that. These variables were all initialized in the procedural program before the loop started. Also, the Castle was setup as part of the initialization, but I'm not dealing with that here. I'm just trying to learn how to design here. I figured I'd put the Castle setup in it's own class because it is an object (using the model as a real-world object method). I don't think I can worry about whether the CodeSmells at this point. I'm thinking I need to design something that works, then be able to refactor it to eliminate as many CodeSmells as I can. But! Noted: a DataClass is a CodeSmell. def main(): tc1 = TestClass1() # instance tc1.__init__() # invoke method The __init__() method is called implicitly by calling TestClass1(). Generally the only time you explicitly call __init__() is when calling the method of a base class. I can fix that right now! Back to the laboratory! 8^D Kent Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: What is the equivalent of JUnit in Python? The article says that JUnit is used for unit tests, or you can write your own. Since I don't have a clue, writing my own is probably out the question. Also I'm not familiar with Java, and am just learning Python OOP, so I'm not getting much out of that one. Sorry. Absolute Beginner here. http://www.google.com/search?q=python+unit+test Cleverly called unittest, though sometimes referred to by its original project name PyUnit. :-) ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: What is the equivalent of JUnit in Python? The unittest module is based on JUnit. http://docs.python.org/lib/module-unittest.html Here is a simple introduction to the capabilities of unittest. It doesn't do much to motivate the examples though: http://www.oreillynet.com/onlamp/blog/2007/09/pymotw_unittest.html A longer intro: http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-1-unittest.html An alternative to unittest is doctest. They both get the job done, which one to use is mostly a matter of preference and the complexity of the tests. http://docs.python.org/lib/module-doctest.html Wikipedia has a short introduction to doctest and a link to Tim Peter's c.l.py posting introducing the module: http://en.wikipedia.org/wiki/Doctest http://groups.google.com/group/comp.lang.python/msg/1c57cfb7b3772763 Another intro: http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-2-doctest.html There are many other testing tools that are not in the standard library. Nose and py.test are popular alternatives to unittest and doctest. http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-3-pytest-tool.html Here is a good list of testing articles: http://www.pycheesecake.org/wiki/AgileTestingArticlesAndTutorials Here is a pretty comprehensive list of tools: http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote What is the equivalent of JUnit in Python? I think the nearest equivalent is writing my own is probably out the question. Also I'm not familiar with Java, and am just learning Python OOP, so I'm not getting much out of that one. Sorry. Absolute Beginner here. Note that Unit testing is orthogonal to OOP. You can use TDD and unit tests(and should!) when doing procedural programming just as well. Well, most of these were local variables in main() in the procedural version of this program. So DataClass() is what I should name such a class. I was wondering about that. While you can use classes that way it leads to a style of programming called object based rather than object oriented. It uses objects but the underlying design is still procedural. Thats why its better to focus on the behaviour of the objects and add the data attributes needed to support that behaviour. Remember we communicate with objects by sending them messages asking them to *do* stuff not to get data out of them, or at least we should do. Objects do it to themselves: The Law of demeter. Ask What does this object do? What data does it need to achieve that? Castle setup in it's own class because it is an object (using the model as a real-world object method). Yes, each object should initialise its own data. (Albeit maybe based on values passed into the constructor.) HTH, Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Alan Gauld [EMAIL PROTECTED] wrote What is the equivalent of JUnit in Python? I think the nearest equivalent is Oops, I was going top say PyUnit then remembered the name had changed but forgot to check out the latest incarnation. Fortyunately others have done the work for me. Personally I like the Nose framework that comes with TurboGears but even hand written unit tests are no big deal in Python - just use asserts and other invariant checks and tests etc liberally Alan G. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 7, 2008 6:47 PM, Alan Gauld [EMAIL PROTECTED] wrote: Alan Gauld [EMAIL PROTECTED] wrote What is the equivalent of JUnit in Python? I think the nearest equivalent is Oops, I was going top say PyUnit then remembered the name had changed but forgot to check out the latest incarnation. Fortyunately others have done the work for me. Personally I like the Nose framework that comes with TurboGears but even hand written unit tests are no big deal in Python - just use asserts and other invariant checks and tests etc liberally Alan G. PyUnit: It really doesn't seem to be an absolute beginner technique. The noun/verb/adjective technique seems to be geared more towards beginners. I like the idea of that technique. Perhaps the unit test approach is more for Intermediate learners, or learners who already have a background in OOP of some form or another (like Java). I'm just starting out, so I'm looking at everything that is thrown at me, but quite frankly, it is really easy for me to see something that is over my head at this point. If it's over my head, I'll just stall, like I have in the past, and then I'll have to start this thread over again later. sigh 8^D I guess you can tell it's been a long day for me. I've done some reading, some coding, some experimenting... all in a day's play for a Hobbyist Programmer. 8^D I'll take another look at PyUnit tomorrow morning when I'm fresh. One thing I'm encouraged by: in Alan's tutorial, he says that I don't have to see the light to use POOP. But if I can learn some basic design POOP techniques from all this, then I'll be happy. After all, I'm a beginner... you can't get any more basic than that! Happy Happy Joy Joy. -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
There's a couple of errors in here that no one has addressed yet because the question was geared towards programming style... So now I will address them. Or undress them, I suppose. ;-) #!/user/bin/python From the testing laboratory of: b h a a l u u at g m a i l dot c o m 2008-02-07 import time CS = \n*50 This is okay, but it is a little more intuitive to make this def clrscr(): print \n*50 so that you can say clrscr() because clearing the screen is an action, not a thing that you would normally think of printing. The point of python is to make programming easier for humans. You defeat it's greatest power by not using it in a style that takes advantage of it's ability to mimic the real world. actions usually indicate functions. (This is definitely a style thing. I'm not trying to start an argument) class TestClass1(object): please give me a better name def __init__(self): please document me self.name = self.answer = self.strength = 20 self.wealth = 45 self.light = 0 self.tally = 0 As mentioned before, data in class should be related to one real (or abstract) object, not just a container for random data. def main(): tc1 = TestClass1() # instance tc1.__init__() # invoke method print CS N1 = tc1.name N1 = raw_input( WHAT IS YOUR NAME, EXPLORER? ) This is pointless. When you assign the value of tc1.name (which is ) you immediately overwrite it when you say N1 = raw_input(...) What you are trying to accomplish without grokking assignment is this. tc1.name = raw_input(What is your name, explorer?) # main game loop while True: print CS print ( %s, YOUR STRENGTH IS %d) % (N1, tc1.strength) Earlier you set N1, but not tc1.name. Either use one or the other. print ( YOU HAVE $%d) % tc1.wealth if tc1.light == 0: Can be if tc1.light: print(The light's on, but no one's home) else: print(It is too dark to see anything) print ( IT IS TOO DARK TO SEE ANYTHING) else: print ( THE LIGHT'S ON, BUT NO ONE'S HOME) print print A = tc1.answer Again, the same problem with tc1.name. Why are you bothering with A? Please realize that you can assign directly tc1.answer = raw_input(...) and just use the one variable. This is not C, but Python. A = raw_input( WHAT DO YOU WANT TO DO? [Q|L]: ) # main game prompt if A.upper() == Q: break if A.upper() == L: light = raw_input( LIGHT? [0|1]: ) # turn the light on and off if light == 0 and tc1.light == 0: What?!? What is the deal? Do you have two different lights? No... then using two different light variables does not make sense. Also, the variable 'light' will never be == 0 unless you hit enter without entering anything because raw_input returns a string. 0 != 0 print ( THE LIGHT IS OFF) I see. You have two seperate variables so that you can determine whether the light was off previously. In which case, I suggest you change the variable to a more intuitive name, such as 'chosen' or something. To test whether the light was on before or not, you should have a method of the class islighton() because you are performing an action. Checking to see whether the light is on. If this doesn't make sense to you, consider that often attributes of a class are not directly accessed. There are even special things called properties that define get and set methods of classes... Um, disregard that. Too much info. :-) time.sleep(2) if tc1.wealth = 0: You have put this wealth check after the changing of the light. So it is possible that someone can change the light after they already have no money. print print ( YOU HAVE NO MONEY) time.sleep(2) else: tc1.light = int(light) Good. You just didn't think of int() in the if check. btw, you aren't going to tell anyone when they turn the light on? tc1.wealth -= 15 else: print ( INVALID CHOICE) time.sleep(2) tc1.tally += 1 tc1.strength -= 5 if tc1.strength = 0: print ( YOU DIED) time.sleep(2) break print print ( Final Score:) print (Tally: %d) % tc1.tally print ( Wealth: $%d) % tc1.wealth print ( Strength: %d) % tc1.strength if __name__ == __main__: main() ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Tiago Saboga [EMAIL PROTECTED] wrote sub types of an abstract superclass. Do NOT use data attributes for this, always base inheritance heirarchies on behaviour. Could you please elaborate on this last sentence? I don't understand what you mean, and I feel I may be on this track. Inheritance heirarchies are the basis of polymorphism in OOP. Polymorphism is all about methods not data. Therefore to create useful inheritance heirarchies the key is to find groups of objects that share the same behaviour (ie method set) even if the internal data (the attributres) are different. The classic example of polymorphism is shapes. Now if you look at the data attributres of a set of shapes: square, circle, triangle etc they look quite different. (radius v lenxbreadth, height, angles etc) So from a data perspective they are not good inheritance candidates. But idf you look at their behaviours - draw, calculate area, move, intersect etc they are all shared, thus we can create an abstract superclass with those behaviours. Each subclass can provide its own internal data and implementt the methods using that data but the external interface of all shapes is identical and therefore polymorphiasm can be used. By contrast if you take some objects that have the same data but different methods and try to create a superclass you will simply wind up with a very big class that aggregates all the methods of all the objects but cannot be used in a polymorphic way because only a subaset of the methods actually apply to any given instance. Thus always base inheriotance on common mbehaviour not on common data. I hope that makes it clearer. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 5, 2008 3:02 PM, Alan Gauld [EMAIL PROTECTED] wrote: One of the earliest ways of doing this has now fallen sonewhat out of favour but in practie I find it works quite well for beginners is: Describe the problem in plain English text(or whatever you language is!). Underline the nouns and separate into proper and common nouns. Common nouns are likely classes (although be careful to check for synonyms - the same class described by different nouns) while proper nouns are likely to be instances of classes (which classes may or may not be in your list of common nouns) Identify the common noun (class) that applies and add to your list. This sounds like a good suggestion! I've already started, and have a rough draft. I still need to knock the rough edges off the description. How detailed do you make your description? Do you write an overview that isn't very detailed, or do you describe every detail you can think of? (My rough draft is quite detailed because I have just finished writing the procedural program, and have all the details in my head.) Actually, writing a description of the problem in Plain English is part of designing any computer program (according to some old programming texts I have). This is why beginning computer programmers should stay awake in English class, and pay attention to grammar! Now go through and identify the verbs and adjectives in the text. Assign each to a noun. Verns are potential methods of the classes and adjectives are potential attributes. Noted: potential The end result is a candidate set of classes with potential methods and attributes. Now try linking them together to identify relationships. Don't be surprised if not all classes are related to others - you will usuially identify more classes than you need and some classes will be demoted to attributes of other more significant classes. And a few attributes may get promoted to classes in their own right. I had a 'testing' directory when I wrote the procedural version of the program. I tested snippets of code to see if they would work, before putting them in the main program. I can see that a similar 'testing' directory will be well used when designing this POOP version. 8^D Once you have your candidate classes pick a few that look like they will be core to the problem and try to work through some scenarios focussing on the interactions between the objects. At this point its often good to think of the objects in physical terms - as if you were building a mechanical model of the problem rather than a software version. What kinds of signals or messagews would you send to each object and how would each object interact with those around it This is why I chose the Text Adventure Game as a learning program. It is full of objects that can be thought of in physical terms! I'm not quite clear how they will message each other (yet), but that will probably become clearer as I work through this. Don't at this stage worry too much about inheritance. Focus on function. If you find that several classes have the same or similar methods then consider if they are sub types of an abstract superclass. Do NOT use data attributes for this, always base inheritance heirarchies on behaviour. Noted. Worth a try. It will miss many OOP tricks but as a starter methodology it is how millions of OOP programmers began. As you gain experience you will identify common abstract patterns. Once that starts then go and read the design patterns book by Gamma et al. This is exactly the kind of thing I was looking for I'm sure I'll have more questions as I go along. Thats how I'd do it, I'm sure others will suggest other approaches. -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld Thank you Alan! Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Wed, Feb 06, 2008 at 08:58:09AM -, Alan Gauld wrote: Thus always base inheriotance on common mbehaviour not on common data. I hope that makes it clearer. Thanks Alan, it's clear now. And now I know that this is not one of the mistakes I am making ;) Tiago Saboga. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 5, 2008 3:02 PM, Alan Gauld [EMAIL PROTECTED] wrote: Describe the problem in plain English text(or whatever you language is!). -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld Here is my description, in plain English. Text Adventure Game Requirements: 1. The Explorer enters her name at a prompt. 2. Other things are initialized at this point. 3. The layout of the Castle is defined. 4. Treasure is placed in rooms in the Castle. A. Treasure is distributed randomly to four rooms. B. Treasure is placed in two specific rooms. 5. Four Monsters are randomly distributed to four rooms in the Castle. A. No monsters should be placed at Entrance or Exit. B. Each monster has a name. C. Each monster has a Ferocity Factor / Danger Level. 6. She has 100 strength and $75 wealth to start with. A. Strength is decremented 5 for each prompt entry. 1. If strength equals zero: a. She dies. b. Final score displayed. c. Game over. B. Strength can be incremented by consuming food. C. Wealth can be used to buy things in QuarterMaster's Store. D. Wealth can be incremented by finding and picking-up treasure. 7. She does not have food, weapons, armor, magic, or light. 8. She starts at the Entrance to the Castle (Room 6). 9. She cannot see anything without a light. 10. She enters commands at the prompt in order to: A. Move in six directions [N,S,E,W,U,D]: 1. Move in indicated direction. 2. Informed she cannot move in indicated direction. 3. Her strength is decremented 5 each move. 4. The tally of moves is incremented 1 each move. B. Access the Provisions Inventory menu [I]: 1. She must have some wealth to access the PI menu. 2. She can purchase items from the menu: a. Light is 0 or 1. b. Weapons: Axe / Sword is 0 or 1. c. Food units. 1. She is told how many units of food she has. 2. She is asked how many units of food she wants to buy. d. Magic amulet. e. Armor. 3. Wealth is decremented after each purchase. a. She is informed when she has no money, and exited from the store. b. She loses everything except strength and food, if she tries to spend more wealth than she has. C. She can pick-up treasure [P]. 1. She cannot pick-up treasure if she cannot see it (she needs light). 2. The treasure will remain in the room if not picked-up. D. She can run from a monster [R]. 1. She may be asked where she wants to flee to (direction). 2. She may be told she must stand and fight (random decision). E. She can fight a monster. 1. Wearing armor increases her chance of success. 2. If she has a weapon, she must fight with it. 3. If she has two weapons, she is asked which one she wants to use. 4. If she has no weapon(s), she must fight bare-handed. a. The Explorer or the monster may attack first (random decision). b. The Explorer or the monster may wound the other (random decision). c. The Explorer or the monster may defeat the other. 1. Strength is decremented from the Explorer during the fight. 2. Ferocity Factor is decremented from the monster during the fight. 11. She can consume food [C]. A. She must have food to consume 1. She is told how many units of food she has. 2. She is asked how many units of food she wants to eat. 12. She can use the Magic Amulet [M]. A. She must have the Magic Amulet in her possession. B. The Magic Amulet will move her to a random room in the Castle. 1. It should not move her to the Entrance or Exit. 13. The game ends when she exits the Castle (finds Room 11). A. Exit message is displayed. B. Final Score is displayed. 1. Final score depends on several factors: a. Strength, wealth, tally, food, number of monsters killed. Now the hard part: grammar. Happy Programming! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote Here is my description, in plain English. Text Adventure Game Requirements: 1. The Explorer enters her name at a prompt. 2. Other things are initialized at this point. 3. The layout of the Castle is defined. 4. Treasure is placed in rooms in the Castle. Actually thats not really plain English its a very structured English. In fact it approaches procedural pseudo code! Its possibly a little too detailed too. I'd go for a more free-form paragraph or two(at most) something like: -- I want to build a text adventure game based around an explorer moving around a castle with multiple rooms,. In each rooms there could be various items of treasure or monsters. To win the game the explorer has to collect as much treasure as possible and defeat as many monsters as possible. Treasure is worth points and the expolorer starts off with a given amount of strength and points. .. Because its a text game the interface will consist of a series of input prompts with responses and printed status messages. The game is over when. --- That should be shorter and less likely to predispose your thinking to a particular approach - such as when the initialisation takes place, or how many rooms or premature consideration of the command structures etc. These things should emerge as you create the object definitions and interactions. The initial aim is only to find the half dozen to a dozen key classes top get started. Other classes will emerge as you progress, and some of the original candidates may merge into others or be discarded. And don't forget that there could well be a game class/object to control the overall flow of the game and coordinate the actions of the other objects. For example the prompt/response/display mechanism might be part of the game class (and they might be classes too!). This would maximise reuse of the compnent objects within a different game framework ( a GUI fort instance) later. HTH, -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
Thank you Alan. This helps tremendously! I had gone to your OOP tutorial and read it over (again) and the closest thing I could find on that page was the Bank Account example that had a list of things a bank account might be expected to do. So away I went, making a list. The problems with that approach surfaced as soon as I started trying to identify the nouns (potential classes and instances), adjectives (potential attributes) and verbs (potential methods). I'm making mistakes, but at least that shows that I'm trying. If nothing else, I now know what doesn't work. 8^D Actually, I'm not expecting to get this done today. It may take awhile. From my past experience, that is how the design process goes. But if I can learn how to do this, I'm pretty sure it will save a lot of time when I work on future projects. Back to the drawing board! -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] On Feb 6, 2008 12:06 PM, Alan Gauld [EMAIL PROTECTED] wrote: bhaaluu [EMAIL PROTECTED] wrote Here is my description, in plain English. Text Adventure Game Requirements: 1. The Explorer enters her name at a prompt. 2. Other things are initialized at this point. 3. The layout of the Castle is defined. 4. Treasure is placed in rooms in the Castle. Actually thats not really plain English its a very structured English. In fact it approaches procedural pseudo code! Its possibly a little too detailed too. I'd go for a more free-form paragraph or two(at most) something like: -- I want to build a text adventure game based around an explorer moving around a castle with multiple rooms,. In each rooms there could be various items of treasure or monsters. To win the game the explorer has to collect as much treasure as possible and defeat as many monsters as possible. Treasure is worth points and the expolorer starts off with a given amount of strength and points. .. Because its a text game the interface will consist of a series of input prompts with responses and printed status messages. The game is over when. --- That should be shorter and less likely to predispose your thinking to a particular approach - such as when the initialisation takes place, or how many rooms or premature consideration of the command structures etc. These things should emerge as you create the object definitions and interactions. The initial aim is only to find the half dozen to a dozen key classes top get started. Other classes will emerge as you progress, and some of the original candidates may merge into others or be discarded. And don't forget that there could well be a game class/object to control the overall flow of the game and coordinate the actions of the other objects. For example the prompt/response/display mechanism might be part of the game class (and they might be classes too!). This would maximise reuse of the compnent objects within a different game framework ( a GUI fort instance) later. HTH, -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 6, 2008 12:06 PM, Alan Gauld [EMAIL PROTECTED] wrote: bhaaluu [EMAIL PROTECTED] wrote Here is my description, in plain English. Text Adventure Game Requirements: 1. The Explorer enters her name at a prompt. 2. Other things are initialized at this point. 3. The layout of the Castle is defined. 4. Treasure is placed in rooms in the Castle. Actually thats not really plain English its a very structured English. In fact it approaches procedural pseudo code! Its possibly a little too detailed too. My first try didn't work. I'm going to try again. I'm intrigued with the idea that the nouns, verbs, and adjectives can indicate possible classes, instances, methods, and attributes. While I'm familiar with the objects in this TAG example, I'd like to have a way to approach something that I'm not as familiar with. I like the idea of this technique. It seems like it should work with just about anything that can be modelled as an object. I have a tendancy to think about things as actual objects (but probably not OOP objects -- more like real objects, like a vase). I also like techniques. I know this much: Explorer: has strength wealth, can carry weapons food, can wear armor, can pick-up treasure, can fight monsters, can wound monsters, can defeat monsters, can move from room to room. Monster: can be anywhere, has Ferocity Factor / Danger Level, can fight Explorer, can wound Explorer, can defeat Explorer. Treasure: can be picked-up, can be in any room in Castle (except entrance and exit). Castle: contains interconnected rooms, has three levels. Rooms: room has door(s), door(s) connect to other rooms, room has description, can contain treasure, can contain monster. The trick is to take all that stuff, and figure out what the classes are, the instances, the methods, and the attributes. So it seems I need to write something descriptive about exploring the above. Subject, verb, adjective object. I must start somewhere! 8^D The above is much smaller than my previous pseudocode attempt. I'd go for a more free-form paragraph or two(at most) something like: -- I want to build a text adventure game based around an explorer moving around a castle with multiple rooms,. In each rooms there could be various items of treasure or monsters. To win the game the explorer has to collect as much treasure as possible and defeat as many monsters as possible. Treasure is worth points and the expolorer starts off with a given amount of strength and points. .. Because its a text game the interface will consist of a series of input prompts with responses and printed status messages. The game is over when. --- That should be shorter and less likely to predispose your thinking to a particular approach - such as when the initialisation takes place, or how many rooms or premature consideration of the command structures etc. These things should emerge as you create the object definitions and interactions. The initial aim is only to find the half dozen to a dozen key classes top get started. Other classes will emerge as you progress, and some of the original candidates may merge into others or be discarded. And don't forget that there could well be a game class/object to control the overall flow of the game and coordinate the actions of the other objects. For example the prompt/response/display mechanism might be part of the game class (and they might be classes too!). This would maximise reuse of the compnent objects within a different game framework ( a GUI fort instance) later. HTH, -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor Happy Happy Joy Joy -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu [EMAIL PROTECTED] wrote Let me preface this message by saying that I've never written a TAG before - either procedurally nor using OOP. so I don't know if the following approach is a good way to go or not. However it's where I feel things moving... I have a tendancy to think about things as actual objects (but probably not OOP objects -- more like real objects, like a vase). But thats the right way to go. The whole point of OOP is that you are trying to simulate the real world objects. Thats why people who haven't been trained in classical programming techniqiues usually find OOP much easier to pick up than experienced programmers do. Its logically more sensible to say move a table in a direction for a distance than to change the x,y coordinates explicitly! Explorer: has strength wealth, can carry weapons food, can wear armor, can pick-up treasure, can fight monsters, can wound monsters, can defeat monsters, can move from room to room. A good start so Explorer looks like a class with two scalar attributes: strength and wealth. Also a number of lists of objects - weapons, food, treasure and maybe armor. Looks like we might have a set of methods to pickUp(object) and to wear(armor) and maybe some test methods hasWeapon(weapon), isWearing(armor) etc. Also we have some methods around fighting, BUT... We are interested in what we can do TO the objerect not what it does to other objects (at least at this point). So rather than fighting a monster maybe the monster can be fought - ie the fight method is a method of monster? Except Monster: can be anywhere, has Ferocity Factor / Danger Level, can fight Explorer, can wound Explorer, can defeat Explorer. It looks like the same applies to monsters and Explorers. So maybe both Monster and Explorer are subclasses of a Fighter because they share the same methods. Now we can have a battle between two fighter objects - and this could allow the game to be extended to allow monsters to fight monsters and explorers to fight explorers, almost for free! class Fighter(object): def fight(self, fighter) def attack(self, weapon) def repulse(self, weapon) def isKilled(self) def currentStrength(self) Notice that one of the things that seems to come out of this is that maybe the strength attribute and the list of weapons belongs in the fighter class? Or maybe not if monsters don't have weapons - a design decision... Now we can make a stab at how the fight metjod might work: def fight(self, fighter): weapon = self chooseWeapon() fighter.attack(weapon) if fighter.isKilled(): self.strength += fighter.value And from this we could maybe do the attack method too: def attack(self,weapon): if self.canRepulse(weapon): self.repulse(weapon) else: self.strength -= weapon.value if self.strength 0: self.die() And this reveals some new attributes and methods we can add, and also probably some ideas for how to write the repulse method too... And by constantly repeating this cycle of invent a bit, write a bit, test a lot we gradually build up the individual classes. Remember the prompt is your friend for testing these things. Create a few instances of fighters and weapons and get them to fight each other using the prompt. When you stop being sure of where to go, go back to your text description and look for more clues about other objects that might help. As I say, I don't actually know if the above aproach will really work for a TAG but it looks worth a try. But one of the beauties of OOP is that each object is a mini program that can be played with and experimented with at the prompt so you find out what works and what doesn't very quickly. HTH, -- Alan Gauld Author of the Learn to Program web site http://www.freenetpages.co.uk/hp/alan.gauld ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: How do you design POOP? What are the guidelines you keep in mind to design good POOP? Can an absolute beginner learn to design POOP? I have mostly stayed out of this thread for lack of time and because Alan is doing a great job, but I think I will chime in a bit because this is an area where Alan and I have very different styles. Let me say that I don't mean any disrespect for Alan or his approach, I just have a different point of view. Also I will say that converting a procedural program to OO 'just because' is not necessarily a good idea. Not every program is improved by OOP. In your case, it probably will be though. I tend to work from small pieces to larger ones and let the design grow from the needs of the code, rather than from considerations of nouns and verbs in the spec. I think for me the primary drivers are data structure and functionality. For example, maybe I need a way to represent a room. I might start with a simple list or tuple and write some code that works with rooms. Soon I get tired of having to use subscripts all the time so I make a simple container class Room to hold the data. Then I will find bits of functionality - functions - that work with the room data; they become methods of the Room class. One piece at a time the code grows. Each new piece of functionality imposes new requirements on the design and the design may change to accommodate it. Design a little, code a little, repeat... http://personalpages.tds.net/~kent37/stories/3.html Once and Only Once - aka Don't Repeat Yourself - is one of the best principles of design. Whenever you are tempted to copy/paste code or data, ask yourself how you could change the design to avoid the copying. You can discover many useful design techniques by applying DRY. More here: http://personalpages.tds.net/~kent37/stories/00012.html Sensitivity to code smells is another good way to discover when your design needs to change. Martin Fowler's book Refactoring popularized this term. It has a chapter that explains the code smells and points out ways to fix them. An abbreviated version is available here: http://wiki.java.net/bin/view/People/SmellsToRefactorings The writings of Robert C Martin have taught me a lot about good design and agile development. They don't all apply to Python - many design patterns that make sense in C++ or Java are not needed in Python - but the principles still hold. A lot of his work is available on-line: http://objectmentor.com/resources/publishedArticles.html http://objectmentor.com/resources/articles/Principles_and_Patterns.pdf might be a good starting point. http://objectmentor.com/resources/articles/xpepisode.htm attempts to give the flavor of agile, test-driven development. I don't use the command-line interpreter much, I do a lot more work in unit tests. In test-driven development (TDD), if you decide you want a Room class, the first thing you do is create a unit test for the class. The test will fail, because the class doesn't exist, so you next write the class and make the test pass. Then add another (failing) test for the next bit of functionality, then implement it and make the test pass. Continue as needed. I have written a little more about this here: http://personalpages.tds.net/~kent37/stories/7.html HTH, Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 5, 2008 5:46 AM, bhaaluu [EMAIL PROTECTED] wrote: What I'm interested in is the thought processes and/or guidelines that Tutors employ when they sit down to design a POOP. Whenever I have a few free minutes and a desire to contemplate the infinite (Hah!), I surf over to the C2 wiki. I don't know the official name of the thing, I don't even know which page (if any) is supposed to be the home page. Rather, I surf around it the same way I did the dictionary when I was a kid - just let one link lead to another. Officially it's about refactoring - which basically means tuning-up a suboptimal design, with the implicit assumption that all designs are suboptimal and could be improved. But it's also a great place to see a bunch of very smart programmers opine on exactly what a good design is in the first place. The principles of OnceAndOnlyOnce and Don'tRepeatYourself, for instance, speak directly to the questions you're asking. I must say that I find the visual design, and the editing style, incredibly infuriating. Not every contributor signs his/her submission, so it's not always clear where one ends and another begins. Did I mention it's ugly? But it's fascinating stuff, and I feel it's made me a better programmer. Most of the programming examples are in Java {ick!}, some are in Smalltalk; I think I've seen some Lisp; I have yet to see an example in Python. But the code is all pretty readable (which is, after all, one of the principles they're trying to get across.) The Code Smells page is as good a starting place as any: http://c2.com/xp/CodeSmell.html Enjoy! (And by the way - if you find any paragraphs particularly hard to follow {I certainly have!}, don't kill yourself. Read on a bit further down the page. Generally another contributor will have restated the same argument in more accessible terms - remember that great programmers are not necessarily great essayists, and vice versa.) -- www.fsrtechnologies.com -- www.fsrtechnologies.com ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Feb 5, 2008 1:13 PM, Marc Tompkins [EMAIL PROTECTED] wrote: On Feb 5, 2008 5:46 AM, bhaaluu [EMAIL PROTECTED] wrote: What I'm interested in is the thought processes and/or guidelines that Tutors employ when they sit down to design a POOP. The Code Smells page is as good a starting place as any: http://c2.com/xp/CodeSmell.html -- www.fsrtechnologies.com This page looks good: http://c2.com/cgi/wiki?PrinciplesOfObjectOrientedDesign 8^D -- b h a a l u u at g m a i l dot c o m You assist an evil system most effectively by obeying its orders and decrees. An evil system never deserves such allegiance. Allegiance to it means partaking of the evil. A good person will resist an evil system with his or her whole soul. [Mahatma Gandhi] ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
bhaaluu wrote: POOP: Python Object Oriented Programming/Programmer/Program(s) POOP = borderline offensive and definitely annoying. Maybe you don't know that poop is a synonym for excrement? Is that what you are trying to learn? Now I am interested in learning how to DESIGN an object-oriented version of the game in Python. All my Python tutorials show me the mechanics of how to MAKE classes. What I'm interested in is the thought processes and/or guidelines that Tutors employ when they sit down to design a POOP. From the archives: http://thread.gmane.org/gmane.comp.python.tutor/29876 http://thread.gmane.org/gmane.comp.python.tutor/39443/focus=39489 http://thread.gmane.org/gmane.comp.python.org.baypiggies/2857/focus=43197 Also: http://personalpages.tds.net/~kent37/stories/00014.html Kent ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor
Re: [Tutor] designing POOP
On Tue, Feb 05, 2008 at 08:02:19PM -, Alan Gauld wrote: bhaaluu [EMAIL PROTECTED] wrote Now I am interested in learning how to DESIGN an object-oriented version The question was very interesting, and so where the answers. Don't at this stage worry too much about inheritance. Focus on function. If you find that several classes have the same or similar methods then consider if they are sub types of an abstract superclass. Do NOT use data attributes for this, always base inheritance heirarchies on behaviour. Could you please elaborate on this last sentence? I don't understand what you mean, and I feel I may be on this track. Thanks, Tiago Saboga. ___ Tutor maillist - Tutor@python.org http://mail.python.org/mailman/listinfo/tutor