Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #70550 > unrolled thread
| Started by | tim.thelion@gmail.com |
|---|---|
| First post | 2014-04-23 13:57 -0700 |
| Last post | 2014-04-23 22:01 -0400 |
| Articles | 15 — 10 participants |
Back to article view | Back to comp.lang.python
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
| From | tim.thelion@gmail.com |
|---|---|
| Date | 2014-04-23 13:57 -0700 |
| Subject | Moving 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]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2014-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]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2014-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]
| From | Ethan Furman <ethan@stoneleaf.us> |
|---|---|
| Date | 2014-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]
| From | tim.thelion@gmail.com |
|---|---|
| Date | 2014-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]
| From | MRAB <python@mrabarnett.plus.com> |
|---|---|
| Date | 2014-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]
| From | tim.thelion@gmail.com |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2014-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]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2014-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]
| From | tim.thelion@gmail.com |
|---|---|
| Date | 2014-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]
| From | Amirouche Boubekki <amirouche.boubekki@gmail.com> |
|---|---|
| Date | 2014-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]
| From | Dave Angel <davea@davea.name> |
|---|---|
| Date | 2014-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