Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #70550 > unrolled thread

Moving to an OOP model from an classically imperitive one

Started bytim.thelion@gmail.com
First post2014-04-23 13:57 -0700
Last post2014-04-23 22:01 -0400
Articles 15 — 10 participants

Back to article view | Back to comp.lang.python


Contents

  Moving to an OOP model from an classically imperitive one tim.thelion@gmail.com - 2014-04-23 13:57 -0700
    Re: Moving to an OOP model from an classically imperitive one Mark Lawrence <breamoreboy@yahoo.co.uk> - 2014-04-23 22:15 +0100
    Re: Moving to an OOP model from an classically imperitive one Ian Kelly <ian.g.kelly@gmail.com> - 2014-04-23 15:23 -0600
      Re: Moving to an OOP model from an classically imperitive one Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-04-24 12:26 +1200
    Re: Moving to an OOP model from an classically imperitive one Ethan Furman <ethan@stoneleaf.us> - 2014-04-23 14:42 -0700
      Re: Moving to an OOP model from an classically imperitive one tim.thelion@gmail.com - 2014-04-24 00:32 -0700
    Re: Moving to an OOP model from an classically imperitive one MRAB <python@mrabarnett.plus.com> - 2014-04-24 00:08 +0100
      Re: Moving to an OOP model from an classically imperitive one tim.thelion@gmail.com - 2014-04-24 00:21 -0700
        Re: Moving to an OOP model from an classically imperitive one Chris Angelico <rosuav@gmail.com> - 2014-04-24 17:36 +1000
        Re: Moving to an OOP model from an classically imperitive one Steven D'Aprano <steve@pearwood.info> - 2014-04-24 09:08 +0000
    Re: Moving to an OOP model from an classically imperitive one Chris Angelico <rosuav@gmail.com> - 2014-04-24 09:12 +1000
    Re: Moving to an OOP model from an classically imperitive one Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2014-04-24 12:21 +1200
      Re: Moving to an OOP model from an classically imperitive one tim.thelion@gmail.com - 2014-04-24 09:53 -0700
        Re: Moving to an OOP model from an classically imperitive one Amirouche Boubekki <amirouche.boubekki@gmail.com> - 2014-04-25 19:21 +0200
    Re:Moving to an OOP model from an classically imperitive one Dave Angel <davea@davea.name> - 2014-04-23 22:01 -0400

#70550 — Moving to an OOP model from an classically imperitive one

Fromtim.thelion@gmail.com
Date2014-04-23 13:57 -0700
SubjectMoving to an OOP model from an classically imperitive one
Message-ID<80a82415-fc67-4ccf-8827-27a0ba5459b7@googlegroups.com>
Hello,

I am currently writting a program called subuser(subuser.org), which is written as classically imperative code.  Subuser is, essentially, a package manager.  It installs and updates programs from repositories.

I have a set of source files https://github.com/subuser-security/subuser/tree/master/logic/subuserCommands/subuserlib which have functions in them.  Each function does something to a program, it identifies the program by the programs name.  For example, I have an installProgram function defined as such:

def installProgram(programName, useCache):

Now I've run into a flaw in this model.  There are certain situations where a "programName" is not a unique identifier. It is possible for two repositories to each have a program with the same name.  Obviously, I could go through my code and replace all use of the string "programName" with a tuple of (programName, repository).  Or I could define a new class with two attributes: programName and repository, and pass such a simple object arround, or pass a dictionary.  However, I think this would be better solved by moving fully to an OOP model.  That is, I would have a SubuserProgram class which had methods such as "install", "describe", "isInstalled"...

There is one problem though.  Currently, I have these functions logically organized into source files, each between 40 and 170 LOC.  I fear that if I were to put all of these functions into one class, than I would have a single, very large source file.  I don't like working with large source files for practicall reasons.  If I am to define the class SubuserProgram in the file SubuserProgram.py, I do not want all <https://github.com/subuser-security/subuser/blob/master/logic/subuserCommands/subuserlib/run.py#L162> of run.py to be moved into that file as well.

I thought about keeping each method in a separate file, much as I do now, something like:

###################
#FileA.py
###################
def a(self):
  blah

###################
#FileB.py
###################
def b(self):
  blah

###################
#Class.py
###################
import FileA, FileB
class C:
  a=FileA.a
  b=FileB.b

This works, but I find that it is hard to read.  When I come across FileA, and I see "self" it just seems very confusing.  I suffer a bout of "who-am-i"ism.

I asked on IRC and it was sugested that I use multiple classes, however I see no logical way to separate a SubuserProgram object into multiple classes.

So I thought I would seek your advice.

Tim

[toc] | [next] | [standalone]


#70551

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2014-04-23 22:15 +0100
Message-ID<mailman.9469.1398287725.18130.python-list@python.org>
In reply to#70550
On 23/04/2014 21:57, tim.thelion@gmail.com wrote:
> Hello,
>
> I am currently writting a program called subuser(subuser.org), which is written as classically imperative code.  Subuser is, essentially, a package manager.  It installs and updates programs from repositories.
>
> I have a set of source files https://github.com/subuser-security/subuser/tree/master/logic/subuserCommands/subuserlib which have functions in them.  Each function does something to a program, it identifies the program by the programs name.  For example, I have an installProgram function defined as such:
>
> def installProgram(programName, useCache):
>
> Now I've run into a flaw in this model.  There are certain situations where a "programName" is not a unique identifier. It is possible for two repositories to each have a program with the same name.  Obviously, I could go through my code and replace all use of the string "programName" with a tuple of (programName, repository).  Or I could define a new class with two attributes: programName and repository, and pass such a simple object arround, or pass a dictionary.  However, I think this would be better solved by moving fully to an OOP model.  That is, I would have a SubuserProgram class which had methods such as "install", "describe", "isInstalled"...
>
> There is one problem though.  Currently, I have these functions logically organized into source files, each between 40 and 170 LOC.  I fear that if I were to put all of these functions into one class, than I would have a single, very large source file.  I don't like working with large source files for practicall reasons.  If I am to define the class SubuserProgram in the file SubuserProgram.py, I do not want all <https://github.com/subuser-security/subuser/blob/master/logic/subuserCommands/subuserlib/run.py#L162> of run.py to be moved into that file as well.
>
> I thought about keeping each method in a separate file, much as I do now, something like:
>
> ###################
> #FileA.py
> ###################
> def a(self):
>    blah
>
> ###################
> #FileB.py
> ###################
> def b(self):
>    blah
>
> ###################
> #Class.py
> ###################
> import FileA, FileB
> class C:
>    a=FileA.a
>    b=FileB.b
>
> This works, but I find that it is hard to read.  When I come across FileA, and I see "self" it just seems very confusing.  I suffer a bout of "who-am-i"ism.
>
> I asked on IRC and it was sugested that I use multiple classes, however I see no logical way to separate a SubuserProgram object into multiple classes.
>
> So I thought I would seek your advice.
>
> Tim
>

You're writing Python, not Java, so put your code into one file and stop 
messing about.

-- 
My fellow Pythonistas, ask not what our language can do for you, ask 
what you can do for our language.

Mark Lawrence

---
This email is free from viruses and malware because avast! Antivirus protection is active.
http://www.avast.com

[toc] | [prev] | [next] | [standalone]


#70552

FromIan Kelly <ian.g.kelly@gmail.com>
Date2014-04-23 15:23 -0600
Message-ID<mailman.9470.1398288213.18130.python-list@python.org>
In reply to#70550

[Multipart message — attachments visible in raw view] — view raw

On Apr 23, 2014 5:01 PM, <tim.thelion@gmail.com> wrote:
> I asked on IRC and it was sugested that I use multiple classes, however I
see no logical way to separate a SubuserProgram object into multiple
classes.

You say you already have the methods logically separated into files. How
about adding one abstract class per file, and then letting SubuserProgram
inherit from each of those individual classes?

As another alternative that you haven't mentioned yet, you could create a
decorator to be applied to each method, which will inject it into the class
at the time it is defined. The explicitness of the decorator solves your
confusion problem of "why does this function use self". It creates a couple
of new problems though: 1) reading the class won't tell you what methods it
contains; and 2) making sure the class is fully constructed before it is
used becomes tricky.

[toc] | [prev] | [next] | [standalone]


#70561

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2014-04-24 12:26 +1200
Message-ID<brr428FdllqU1@mid.individual.net>
In reply to#70552
Ian Kelly wrote:

> How 
> about adding one abstract class per file, and then letting 
> SubuserProgram inherit from each of those individual classes?

I'd recommend against that kind of thing, because it makes
the code hard to follow. With module-level functions, you can
tell where any given function is coming from by looking at the
imports (as long as you haven't used 'import *', which is a
bad idea for this very reason).

But if you're looking at a method call on a class that
inherits from half a dozen base classes, it's hard to tell
which class it's implemented in.

In other words, massively multiple inheritance is the OO
equivalent of 'import *'.

The same goes for any scheme for injecting methods into a
class after defining it, only more so, because the reader
won't be expecting weird things like that.

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#70553

FromEthan Furman <ethan@stoneleaf.us>
Date2014-04-23 14:42 -0700
Message-ID<mailman.9471.1398293527.18130.python-list@python.org>
In reply to#70550
On 04/23/2014 01:57 PM, tim.thelion@gmail.com wrote:
>
> There is one problem though.  Currently, I have these functions logically
>  organized into source files, each between 40 and 170 LOC.  I fear that if
> I were to put all of these functions into one class, than I would have a
>  single, very large source file.  I don't like working with large source
>  files for practicall reasons.

I'm curious what these practical reasons are.  One my smallest source files has 870 lines in it, my largest nearly 9000.

If the problem is your editor, you should seriously consider switching.

--
~Ethan~

[toc] | [prev] | [next] | [standalone]


#70568

Fromtim.thelion@gmail.com
Date2014-04-24 00:32 -0700
Message-ID<3220d8af-5961-410b-9e79-93a69c029672@googlegroups.com>
In reply to#70553
> I'm curious what these practical reasons are.  One my smallest source files has 870 lines in it, my largest nearly 9000.
> 
> 
> 
> If the problem is your editor, you should seriously consider switching.
> 

I think that the main reasons for doing so are as follows:

git status provides much more usefull output when the source files are separate.  If all your code is in one file, than git status tells you nothing about what has changed, yet git diff will provide you with overly verbose output.

The seccond reason is that when refactoring code, it is much easier to manage a todo list when one knows which files have been processed already/what needs to be processed.  This is especially true if the refactor will take several days or be done by several people.

Tim

[toc] | [prev] | [next] | [standalone]


#70554

FromMRAB <python@mrabarnett.plus.com>
Date2014-04-24 00:08 +0100
Message-ID<mailman.9472.1398294517.18130.python-list@python.org>
In reply to#70550
On 2014-04-23 21:57, tim.thelion@gmail.com wrote:
> Hello,
>
> I am currently writting a program called subuser(subuser.org), which
> is written as classically imperative code.  Subuser is, essentially,
> a package manager.  It installs and updates programs from
> repositories.
>
> I have a set of source files
> https://github.com/subuser-security/subuser/tree/master/logic/subuserCommands/subuserlib
> which have functions in them.  Each function does something to a
> program, it identifies the program by the programs name.  For
> example, I have an installProgram function defined as such:
>
> def installProgram(programName, useCache):
>
> Now I've run into a flaw in this model.  There are certain situations
> where a "programName" is not a unique identifier. It is possible for
> two repositories to each have a program with the same name.
> Obviously, I could go through my code and replace all use of the
> string "programName" with a tuple of (programName, repository).  Or I
> could define a new class with two attributes: programName and
> repository, and pass such a simple object arround, or pass a
> dictionary.  However, I think this would be better solved by moving
> fully to an OOP model.  That is, I would have a SubuserProgram class
> which had methods such as "install", "describe", "isInstalled"...
>
[snip]
Could you make the program name unique just by combining it with the
repository name in a single string?

[toc] | [prev] | [next] | [standalone]


#70567

Fromtim.thelion@gmail.com
Date2014-04-24 00:21 -0700
Message-ID<6bf23ea5-e534-486e-adc9-675fe97fa414@googlegroups.com>
In reply to#70554
> [snip]
> 
> Could you make the program name unique just by combining it with the
> 
> repository name in a single string?

In my case I cannot.  But there is a larger reason why I wouldn't do this:  It would mean adding a special character that could not be included in the repository name, that is, if I were to create a "unique-program-name" string which was of the format repo+"-"+programName then the repo name could not have the "-" symbol in it.

Tim

[toc] | [prev] | [next] | [standalone]


#70569

FromChris Angelico <rosuav@gmail.com>
Date2014-04-24 17:36 +1000
Message-ID<mailman.9480.1398324998.18130.python-list@python.org>
In reply to#70567
On Thu, Apr 24, 2014 at 5:21 PM,  <tim.thelion@gmail.com> wrote:
>> [snip]
>>
>> Could you make the program name unique just by combining it with the
>>
>> repository name in a single string?
>
> In my case I cannot.  But there is a larger reason why I wouldn't do this:  It would mean adding a special character that could not be included in the repository name, that is, if I were to create a "unique-program-name" string which was of the format repo+"-"+programName then the repo name could not have the "-" symbol in it.
>

Can you, then, simply substitute a tuple for the string? Instead of
comparing program name strings, compare tuples of (repo, program_name)
- it should work just fine.

ChrisA

[toc] | [prev] | [next] | [standalone]


#70571

FromSteven D'Aprano <steve@pearwood.info>
Date2014-04-24 09:08 +0000
Message-ID<5358d486$0$11109$c3e8da3@news.astraweb.com>
In reply to#70567
On Thu, 24 Apr 2014 00:21:18 -0700, tim.thelion wrote:

>> [snip]
>> 
>> Could you make the program name unique just by combining it with the
>> 
>> repository name in a single string?
> 
> In my case I cannot.  But there is a larger reason why I wouldn't do
> this:  It would mean adding a special character that could not be
> included in the repository name, 

Do you support \n or \r or \0 in repo names? If not, then there you go, 
three special characters to choose from.

But I suspect that a tuple of (repo_name, program_name) will be better.



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#70555

FromChris Angelico <rosuav@gmail.com>
Date2014-04-24 09:12 +1000
Message-ID<mailman.9473.1398294747.18130.python-list@python.org>
In reply to#70550
On Thu, Apr 24, 2014 at 7:42 AM, Ethan Furman <ethan@stoneleaf.us> wrote:
> On 04/23/2014 01:57 PM, tim.thelion@gmail.com wrote:
>>
>>
>> There is one problem though.  Currently, I have these functions logically
>>  organized into source files, each between 40 and 170 LOC.  I fear that if
>> I were to put all of these functions into one class, than I would have a
>>  single, very large source file.  I don't like working with large source
>>  files for practicall reasons.
>
>
> I'm curious what these practical reasons are.  One my smallest source files
> has 870 lines in it, my largest nearly 9000.
>
> If the problem is your editor, you should seriously consider switching.

It's probably not the case here, but one good reason for splitting a
file into pieces is to allow separate people or systems to update
different parts. Lots of Linux programs support either
/etc/foobar.conf or /etc/foobar.conf.d/ where the former is one file
and the latter is a directory of separate files, generally deemed to
be concatenated to the main config file. (Example:
/etc/apt/sources.list and /etc/apt/sources.list.d/ - the main config
for your Debian repositories, the directory for additional ones for
VirtualBox or PostgreSQL.) It's easier to allow someone to completely
overwrite a file than to try to merge changes.

But that's not often the case with source code.

ChrisA

[toc] | [prev] | [next] | [standalone]


#70560

FromGregory Ewing <greg.ewing@canterbury.ac.nz>
Date2014-04-24 12:21 +1200
Message-ID<brr3nkFdjl5U1@mid.individual.net>
In reply to#70550
tim.thelion@gmail.com wrote:
> I think this would be better solved
> by moving fully to an OOP model.  That is, I would have a SubuserProgram
> class which had methods such as "install", "describe", "isInstalled"...

This wouldn't necessarily be better. Don't be taken in by the
"everything is better as a class" kind of dogma that seems to
prevail in some circles.

If all you do is take a bunch of module-level functions and
put them into a single class, you haven't really changed anything.
It's still the same design, you've just arranged the source
differently.

There are a couple of good reasons for turning a function into
a method. One is if it embodies implementation details that you
want to keep separated from the rest of the program. But if
*all* of your code is inside the class, there isn't any "rest
of the program" to keep it separate from.

Another is if you want to be able to override it in subclasses.
If there were different kinds of SubuserProgram that needed to
be installed in different ways, for example, it would make
sense to structure this as a collection of classes with an
install() method. But even then, you don't have to put all
the installation code in the classes -- the methods could just
be stubs that call out to different module-level functions if
you wanted.

A reasonable compromise might be to keep the *data* assocated
with a SubuserProgram in a class, maybe together with a few
methods that are tightly coupled to it, but have the major
pieces of functionality such as install() implemented by
separate functions that operate *on* the class, rather than
being inside it.

> Currently, I have these functions logically
> organized into source files, each between 40 and 170 LOC.

That's quite small as these things typically go. You can afford
to make them somewhat larger; I tend to find that files start to
get unwieldy around 1000 lines or so.

-- 
Greg

[toc] | [prev] | [next] | [standalone]


#70576

Fromtim.thelion@gmail.com
Date2014-04-24 09:53 -0700
Message-ID<89bbe51e-2f07-4d80-844d-2e252733cace@googlegroups.com>
In reply to#70560
> A reasonable compromise might be to keep the *data* assocated
> 
> with a SubuserProgram in a class, maybe together with a few
> 
> methods that are tightly coupled to it, but have the major
> 
> pieces of functionality such as install() implemented by
> 
> separate functions that operate *on* the class, rather than
> 
> being inside it.
> 

I think this is sound advice.  I'm still not sure what I'll come up with.

One of the other reasons why an OOP model might be right for me is that of caching.  I currently load a lot of attributes regarding programs from disk, and I do so multiple times, I could either pass those attributes around, OR, using a class, I could store those attributes in the object after loading them just once.  I have no experience with OOP except in the domain of GUIs(where it seems inescapable, all major toolkits use OOP), so I'm not yet sure how this will turn out.

Tim

[toc] | [prev] | [next] | [standalone]


#70604

FromAmirouche Boubekki <amirouche.boubekki@gmail.com>
Date2014-04-25 19:21 +0200
Message-ID<mailman.9500.1398446509.18130.python-list@python.org>
In reply to#70576

[Multipart message — attachments visible in raw view] — view raw

Héllo,

I have no definitive answer regarding the OOP/functional mismatch.

2014-04-24 18:53 GMT+02:00 <tim.thelion@gmail.com>:

> > A reasonable compromise might be to keep the *data* assocated
> >
> > with a SubuserProgram in a class, maybe together with a few
> >
> > methods that are tightly coupled to it, but have the major
> >
> > pieces of functionality such as install() implemented by
> >
> > separate functions that operate *on* the class, rather than
> >
> > being inside it.
> >
>
> I think this is sound advice.  I'm still not sure what I'll come up with.
>
> One of the other reasons why an OOP model might be right for me is that of
> caching.  I currently load a lot of attributes regarding programs from
> disk, and I do so multiple times, I could either pass those attributes
> around, OR, using a class, I could store those attributes in the object
> after loading them just once.


You could also use a generator with a somekind of memoization/cache.


> I have no experience with OOP except in the domain of GUIs (where it seems
> inescapable, all major toolkits use OOP)


I have some experience in GUIs with Python in a proprietary framework.

I have a bias for OOP and Python in particular. I started exploring Scheme
through Guile and other languages more or less. I am asking myself the
question "what is the interest of functional programming or so called".
Scheme doesn't enforce functional code or immutability. It's actually "more
open" somewhat because of the macro system among other things. Outside any
performance considerations or implementations details like GIL. Scheme and
(all?) *LISP don't use the infix notation*. probably because you can work
around it but IMO not fully. The infix notations allows to write things
like: people.move_to(paris). It's easy to read, as «Subject Verb
Complement»... Class based OOP is prefered because of that, in a lot of
situations. IMO, if OOP won, it's because of readability, and in particular
Class based OOP. JavaScript OOP is useless in asynchronous context, see
http://repl.it/Rrf/2. Maybe you can work around this feature with
JavaScript descriptors easly, I did not try that.

so I'm not yet sure how this will turn out.
>

I skimmed through the code, but it's very superficial reading, like I
installed pycharm to ask for help...:

- CamelCase is usually for class names. That said, sometime variable
holding classes are called my_object_class or my_object_factory
- I think permissions.py would be easier to read with a class... or a
function that initialize the dictionary as intented and just use dict
methods onward.
- To I read code, I have a systematic method I call
gunshot/destructive/production rules/function inlining/develop (as the dual
of factorize).

I started with subuser.py, I got: http://dpaste.com/1797075/

def getSubuserCommands():
  """ Returns a list of commands that may be called by the user. """

  def isPathToSubuserCommand(path):
      directory, executableName = os.path.split(path)
      return executableName.startswith("subuser-")

  externalCommandPaths = queryPATH(isPathToSubuserCommand)

  externalCommands = []
  subuserPrefixLength=len("subuser-")

  for externalCommandPath in externalCommandPaths:
    commandDir, executableName = os.path.split(externalCommandPath)
    commandName = executableName[subuserPrefixLength:]
    externalCommands.append(commandName)

  external_subuser_commands = list(set(externalCommands))

  return list(set(
os.listdir(paths.getSubuserCommandsDir())).difference(nonCommands)) +
external_subuser_commands


It's kind of easier to read.

Gremlin is a DSL that allows to navigate a graph. That's exactly what
happens here (and all the
time<http://en.wikipedia.org/wiki/Transderivational_search> long
now<http://en.wikipedia.org/wiki/Kundalini_syndrome#The_Physio-Kundalini_Syndrome_Index>
).wrapped_ <http://en.wikipedia.org/wiki/Net.art>in(tesseract<http://en.wikipedia.org/wiki/Tesseract_%28disambiguation%29>).
I'd like to write the above as:

>>> subuser.commands = (subuser.path.directories +
subuser.user.path.directories).filter(is_command).distinct().memoize()

I think it's possible in Ruby.

I'm quite interested by the subject. Elm language (see
reactconf<http://reactconf.com/>)
and your graphical
IDE<http://thobbs.cz/works/2013/graphical-elm/Intro.html>is very
interesting, do you know about Domain
Specific Modeling Forum <http://www.dsmforum.org/>? I started to put some
thinking grouped together. Also I started proto-py to gather code ideas,
but it's still offline. My plan is to mimick subuser to see, what happens.

Can be of interest Scala @ Systems @
Twitter<https://news.ycombinator.com/item?id=7618969>

Nice project by the way, with a better "see also" section that I could do :)

[toc] | [prev] | [next] | [standalone]


#70565

FromDave Angel <davea@davea.name>
Date2014-04-23 22:01 -0400
Message-ID<mailman.9479.1398304549.18130.python-list@python.org>
In reply to#70550
tim.thelion@gmail.com Wrote in message:
>

I don't really understand your problem or your examples,  but
 others apparently do. So I'll just make a few comments.
 


> 
> There is one problem though.  Currently, I have these functions logically organized into source files, each between 40 and 170 LOC.  I fear that if I were to put all of these functions into one class, than I would have a single, very large source file.  I don't like working with large source files for practicall reasons.

Definitely limit your source file size. 10k lines is probably a
 good limit.

>  If I am to define the class SubuserProgram in the file SubuserProgram.py, 

That's a big mistake right there.  Never let the module name match
 the class name.  If you really only happen to have a single class
 in the file, then just use lower case for the filename.
 


-- 
DaveA

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web