From: Tim Arnold on 6 Apr 2010 09:52 Hi, I have a few classes that manipulate documents. One is really a process that I use a class for just to bundle a bunch of functions together (and to keep my call signatures the same for each of my manipulator classes). So my question is whether it's bad practice to set things up so each method operates on self.document or should I pass document around from one function to the next? pseudo code: class ManipulatorA(object): def process(self, document): document = self.do_one_thing(document) document = self.do_another_thing(document) # bunch of similar lines return document or class ManipulatorA(object): def process(self, document): self.document = document self.do_one_thing() # operates on self.document self.do_another_thing() # bunch of similar lines return self.document I ask because I've been told that the first case is easier to understand. I never thought of it before, so I'd appreciate any comments. thanks, --Tim
From: Bruno Desthuilliers on 6 Apr 2010 10:57 Tim Arnold a �crit : > Hi, > I have a few classes that manipulate documents. One is really a > process that I use a class for just to bundle a bunch of functions > together (and to keep my call signatures the same for each of my > manipulator classes). > > So my question is whether it's bad practice to set things up so each > method operates on self.document or should I pass document around from > one function to the next? As far as I'm concerned, I strongly prefer passing the document around. Makes thing clear, avoids useless preconditions (is self.document set ???) and race conditions (if two threads have to share the Manipulator instance), makes the code easier to understand / maintain / refactor IMHO. Also remember that modules are objects too, so - depending on parts of your code we don't see here - you may even maintain your API without having to use a "class as module". My 2 cents
From: Jean-Michel Pichavant on 6 Apr 2010 11:19 Tim Arnold wrote: > Hi, > I have a few classes that manipulate documents. One is really a > process that I use a class for just to bundle a bunch of functions > together (and to keep my call signatures the same for each of my > manipulator classes). > > So my question is whether it's bad practice to set things up so each > method operates on self.document or should I pass document around from > one function to the next? > pseudo code: > > class ManipulatorA(object): > def process(self, document): > document = self.do_one_thing(document) > document = self.do_another_thing(document) > # bunch of similar lines > return document > > or > > class ManipulatorA(object): > def process(self, document): > self.document = document > self.do_one_thing() # operates on self.document > self.do_another_thing() > # bunch of similar lines > return self.document > > I ask because I've been told that the first case is easier to > understand. I never thought of it before, so I'd appreciate any > comments. > thanks, > --Tim > Usually, when using classes as namespace, functions are declared as static (or as classmethod if required). e.g. class Foo: @classmethod def process(cls, document): print 'process of' cls.foo(document) @staticmethod def foo(document): print document In [5]: Foo.process('my document') process of my document There is no more question about self, 'cause there is no more self. You don't need to create any instance of Foo neither. JM
From: Lie Ryan on 6 Apr 2010 14:42 On 04/06/10 23:52, Tim Arnold wrote: > Hi, > I have a few classes that manipulate documents. One is really a > process that I use a class for just to bundle a bunch of functions > together (and to keep my call signatures the same for each of my > manipulator classes). > > So my question is whether it's bad practice to set things up so each > method operates on self.document or should I pass document around from > one function to the next? > pseudo code: > > class ManipulatorA(object): > def process(self, document): > document = self.do_one_thing(document) > document = self.do_another_thing(document) > # bunch of similar lines > return document > > or > > class ManipulatorA(object): > def process(self, document): > self.document = document > self.do_one_thing() # operates on self.document > self.do_another_thing() > # bunch of similar lines > return self.document Since in function in python is a first-class object, you can instead do something like: def process(document): # note: document should encapsulate its own logic document.do_one_thing() document.do_another_thing() And when you need some complex logic, you can easily elevate your function to a class: class Appender(object): def __init__(self, text): self.text = text def __call__(self, document): mtext = self.manipulate(document, text) document.append(mtext) and I think for your purpose, the mixin pattern could cleanly separate manipulation and document while still obeying object-oriented pattern that document is self-sufficient: # language with only single-inheritance can only dream to do this class Appendable(object): def append(self, text): self.text += text class Savable(object): def save(self, fileobj): fileobj.write(self.text) class Openable(object): def open(self, fileobj): self.text = fileobj.read() class Document(Appendable, Savable, Openable): def __init__(self): self.text = ''
From: Bruno Desthuilliers on 7 Apr 2010 04:34
Lie Ryan a �crit : (snip) > Since in function in python is a first-class object, you can instead do > something like: > > def process(document): > # note: document should encapsulate its own logic > document.do_one_thing() Obvious case of encapsulation abuse here. Should a file object encapsulate all the csv parsing logic ? (and the html parsing, xml parsing, image manipulation etc...) ? Should a "model" object encapsulate the presentation logic ? I could go on for hours here... > > and I think for your purpose, the mixin pattern could cleanly separate > manipulation and document while still obeying object-oriented pattern > that document is self-sufficient: > > # language with only single-inheritance can only dream to do this > > class Appendable(object): > def append(self, text): > self.text += text > class Savable(object): > def save(self, fileobj): > fileobj.write(self.text) > class Openable(object): > def open(self, fileobj): > self.text = fileobj.read() > class Document(Appendable, Savable, Openable): > def __init__(self): > self.text = '' Anyone having enough experience with Zope2 knows why this sucks big time. |