Path: csiph.com!newsfeed.hal-mli.net!feeder3.hal-mli.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!newsfeed.xs4all.nl!newsfeed3a.news.xs4all.nl!xs4all!newsgate.cistron.nl!newsgate.news.xs4all.nl!post.news.xs4all.nl!not-for-mail Return-Path: X-Original-To: python-list@python.org Delivered-To: python-list@mail.python.org X-Spam-Status: OK 0.001 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'python,': 0.02; 'represents': 0.05; 'subject:Python': 0.06; 'class,': 0.07; 'debug': 0.07; 'modified': 0.07; 'variables': 0.07; 'anymore.': 0.09; 'function,': 0.09; 'logic': 0.09; 'meaningful': 0.09; 'namespace': 0.09; 'seemed': 0.09; 'cc:addr:python-list': 0.11; 'python': 0.11; 'def': 0.12; 'mostly': 0.14; 'programs.': 0.14; 'books': 0.15; '"global"': 0.16; '4-5': 0.16; 'ack': 0.16; 'disciplined': 0.16; 'function(s)': 0.16; 'practices.': 0.16; 'basically': 0.19; 'practices,': 0.19; 'later': 0.20; 'code,': 0.22; 'coding': 0.22; 'cc:addr:python.org': 0.22; 'this?': 0.23; 'instead.': 0.24; 'question': 0.24; 'cc:2**0': 0.24; 'sort': 0.25; "i've": 0.25; 'class.': 0.26; 'define': 0.26; 'this:': 0.26; 'updating': 0.26; 'second': 0.26; 'least': 0.26; 'header:In-Reply- To:1': 0.27; 'function': 0.29; 'related': 0.29; 'bigger': 0.30; 'message-id:@mail.gmail.com': 0.30; 'along': 0.30; "i'm": 0.30; 'code': 0.31; 'lines': 0.31; 'that.': 0.31; 'fighting': 0.31; 'object.': 0.31; 'question:': 0.31; 'class': 0.32; 'stuff': 0.32; 'quite': 0.32; 'call.': 0.33; 'cases': 0.33; 'maybe': 0.34; 'problem': 0.35; 'something': 0.35; 'case,': 0.35; 'hundreds': 0.35; 'objects': 0.35; 'but': 0.35; 'received:google.com': 0.35; 'google': 0.35; 'there': 0.35; 'really': 0.36; 'interact': 0.36; 'leads': 0.36; 'object,': 0.36; 'returning': 0.36; 'method': 0.36; 'subject:?': 0.36; 'should': 0.36; 'so,': 0.37; 'two': 0.37; 'project': 0.37; 'step': 0.37; 'architecture': 0.38; 'sometimes': 0.38; 'whatever': 0.38; 'does': 0.39; 'flow': 0.39; 'structure': 0.39; 'sure': 0.39; 'called': 0.40; 'how': 0.40; 'even': 0.60; 'is.': 0.60; 'problems.': 0.60; 'new': 0.61; "you're": 0.61; 'first': 0.61; 'you.': 0.62; 'information': 0.63; 'name': 0.63; 'more': 0.64; 'different': 0.65; 'to:addr:gmail.com': 0.65; 'within': 0.65; 'approaches': 0.68; 'therefore': 0.72; 'hoping': 0.75; 'yourself': 0.78; '20,000': 0.84; 'ram,': 0.84; 'regard.': 0.84; 'navigate': 0.91 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type:content-transfer-encoding; bh=JqH+8kYhat/eCGz3hGGDjtybHKFScLrrequqy72JyMk=; b=FChvov3JyGbj5tfvrCz61pe9rqFiMOa2itsprzJ5Sv/ebTLKmb2cVnQHTgLmvS0yGi i3EDZON7lj8ZOINmBSe1ZVSvpQz1hiLiX+F7M/sN5cQ+GQFvHiRKYx8AbTCMoietYXaT OcM/U1nb19SejsFtFM8MpJqqX3YjQmv9gC4VFysSYlNipBYqS3NElnqvTMSNHXuEiyqv zuLyOc4FjL3o5DoDT2SX4R/bW38U++qXvf7HZ6Y8JKOb2ZXAfAGJCz1W5PPcYCXSxsio feOoMSzsKVRNwEyruXN7ZlmnTL3iu9Mc7Q6Fft+5ya6t73uyjaAqGmzRB1AnNwE9ycXs WSYw== MIME-Version: 1.0 X-Received: by 10.58.187.98 with SMTP id fr2mr1466004vec.38.1390338236329; Tue, 21 Jan 2014 13:03:56 -0800 (PST) In-Reply-To: <346d0a59-0d8a-447e-a8a6-1198119002a9@googlegroups.com> References: <346d0a59-0d8a-447e-a8a6-1198119002a9@googlegroups.com> Date: Tue, 21 Jan 2014 21:03:56 +0000 Subject: Re: how to avoid spaghetti in Python? From: andrea crotti To: CM Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Cc: python-list X-BeenThere: python-list@python.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: General discussion list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Newsgroups: comp.lang.python Message-ID: Lines: 82 NNTP-Posting-Host: 2001:888:2000:d::a6 X-Trace: 1390338719 news.xs4all.nl 2889 [2001:888:2000:d::a6]:48362 X-Complaints-To: abuse@xs4all.nl Xref: csiph.com comp.lang.python:64455 2014/1/21 CM : > I've been learning and using Python for a number of years now but never r= eally go particularly disciplined about all good coding practices. I've de= finitely learned *some*, but I'm hoping this year to take a good step up in= terms of refactoring, maintainability, and mostly just "de-spaghettizing" = my approach to writing Python programs. > It's not really a problem of Python, you just want to learn more about OO principles and good design practices, and about that there are hundreds of good books to read! > > A few specific questions in this area... > > 1) One of my main "spaghetti problems" is something I don't know what to = ever call. Basically it is that I sometimes have a "chain" of functions or= objects that get called in some order and these functions may live in diff= erent modules and the flow of information may jump around quite a bit, some= times through 4-5 different parts of the code, and along the way variables = get modified (and those variables might be child objects of the whole class= , or they may just be objects that exist only within functions' namespaces,= or both). This is hard to debug and maintain. What would people recommen= d to manage this? A system of notes? A way to simplify the flow? And wha= t is this problem called (if something other than just spaghetti code) so I= can Google more about it? > Just define clearly objects and methods and how they interact with each other in a logic way, and you won't have this problem anymore. > 2) A related question: Often I find there are two ways to update the val= ue of an object, and I don't know what's best in which circumstances... To = begin to explain, let's say the code is within a class that represents a Fr= ame object in a GUI, like wxPython. Now let's say ALL the code is within t= his wxFrame class object. So, any object that is named with "self." prepen= ded, like self.panel, or self.current_customer, or self.current_date, will = be a child object of that frame class, and therefore is sort of "global" to= the whole frame's namespace and can therefore be accessed from within any = function in the class. So let's say I have a function called self.GetCurren= tCustomer(). To actually get the name of the current customer into RAM, it= goes into the database and uses some rule to get the current customer. NO= W, the question is, which of these should I do? This: > > def GetCurrentCustomer(self): > self.current_customer =3D #do some database stuff here.... > > Or this: > > def GetCurrentCustomer(self): > current_customer =3D #do some database stuff here.... > return current_customer > > And what difference does it make? In the first case, I am just updating = the "global" object of the current_customer, so that any function can then = use it. In the second case, I am only returning the current_customer to wh= atever function(s) call this GetCurrentCustomer() function. > GetCurrentCustomer should be really get_current_customer if you don't want people screaming at you. And about the question it depends, is the database stuff going to be expens= ive? Do you need to have always a new value? And by the way if you're never actually using "self" in a method maybe it should be a function, or at least a classmethod instead. > My hunch is the first way leads to spaghetti problems. But I want to und= erstand what the best practices are in this regard. I have found in some ca= ses the first method seemed handy, but I'm not sure what the best way of th= inking about this is. > > 3) Generally, what are other tools or approaches you would use to organiz= e well a good-sized project so to avoid fighting yourself later when you do= n't understand your own code and the flow of information through it? By go= od sized, say about 20,000 lines of Python code, or something like that. > Good architecture and some meaningful directory structure is good enough, to navigate Emacs + ack and I'm already very productive even with bigger projects than that.