Go Back   Velocity Reviews > Newsgroups > Python
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

Reply

Python - Circular Class Logic

 
Thread Tools Search this Thread
Old 03-15-2007, 12:35 AM   #1
Default Circular Class Logic


I have a set of classes that describe Files, Folders, etc., that I use
often in my scripts for moving files around, getting a files
extension, converting paths, changing permissions, etc It's very
similar to Jason Orendorff's 'Path' library, and is very useful to
me. The base class 'Data.py' stores all the basic attributes of any
piece of data on disk, and it is then subclassed to represent files
and folders with the attributes specific to that type of object.

I recently made a new class 'Disk.py' that is a subclass of
'Folder.py', to describe all of the attributes of any local or network
disks attached to the computer. I subclassed it from Folder, because
it really is a folder, it's just at the root of a drive. I'm
realizing that these 'Disk' objects are pretty useful, and I came up
with the idea to put a 'Disks' instance as a shared class variable
(singleton?) within the base class ('Data') The idea being that any
instance of a File, or Folder object would contain the list of Disk
objects attached to the system, and could use them accordingly. Also
important is that I would only need to gather the disk info once for
any given running application and all the instances could use it
(origianlly I was getting the disk info for each File/Folder object)

After an hour of banging my head from getting "AttributeError:
'module' object has no attribute 'Disks'" errors, I finally realized
that I'm trying to include an instance in the base class that is a
subclass of itself. Short of making 'Disk' no longer a subclass of
Folder, is there any other way to include a subclassed instance in the
base class of that object? (this is very hard to put in to words)

~Sean



half.italian@gmail.com
  Reply With Quote
Old 03-15-2007, 12:58 AM   #2
Ben Finney
 
Posts: n/a
Default Re: Circular Class Logic
writes:

> Short of making 'Disk' no longer a subclass of Folder, is there any
> other way to include a subclassed instance in the base class of that
> object? (this is very hard to put in to words)


It's a little difficult to visualise what you're describing, but IIUC
your problem is of this form:

===== foo.py =====
import bar

class Foo(bar.Bar):
pass
=====

===== bar.py =====
import baz

class Bar(baz.Baz):
pass
=====

===== baz.py =====
import foo

class Baz(foo.Foo):
pass
=====

That is, each of the classes want to inherit from the others.

The usual solution in these cases is to find the common required
functionality and factor that out to a separate class that is then the
superclass of two of the existing classes, breaking the circle.

===== wibble.py =====
# no dependencies

class Wibble(object):
pass
=====

===== foo.py =====
import wibble
import bar

class Foo(wibble.Wibble, bar.Bar):
pass
=====

===== baz.py =====
import wibble

class Baz(wibble.Wibble):
pass
=====

Note that Baz no longer subclasses foo.Foo, and both Foo and Baz get
the common functionality they share from wibble.Wibble.

--
\ "Buy not what you want, but what you need; what you do not need |
`\ is expensive at a penny." -- Cato, 234-149 BC, Relique |
_o__) |
Ben Finney



Ben Finney
  Reply With Quote
Old 03-15-2007, 01:19 AM   #3
half.italian@gmail.com
 
Posts: n/a
Default Re: Circular Class Logic
>
> That is, each of the classes want to inherit from the others.


That's not exactly what I'm doing, but your comment still might help.
I actually want to include an instance of a subclass in it's
superclass like this:

===== foo.py =====
import Baz

class Foo:
baz = Baz.Baz()

def __init__(self):
pass
=====

===== bar.py =====
import Foo

class Bar(Foo.Foo):
pass
=====

===== baz.py =====
import Bar

class Baz(Bar.Bar):
pass
=====

> The usual solution in these cases is to find the common required
> functionality and factor that out to a separate class that is then the
> superclass of two of the existing classes, breaking the circle.
>
> ===== wibble.py =====
> # no dependencies
>
> class Wibble(object):
> pass
> =====
>
> ===== foo.py =====
> import wibble
> import bar
>
> class Foo(wibble.Wibble, bar.Bar):
> pass
> =====
>
> ===== baz.py =====
> import wibble
>
> class Baz(wibble.Wibble):
> pass
> =====
>
> Note that Baz no longer subclasses foo.Foo, and both Foo and Baz get
> the common functionality they share from wibble.Wibble.


I have to think about that for a bit and see if it makes sense to
factor anything out. Thanks for the idea. Would that be the best
solution considering the above description?

~Sean
>
> --
> \ "Buy not what you want, but what you need; what you do not need |
> `\ is expensive at a penny." -- Cato, 234-149 BC, Relique |
> _o__) |
> Ben Finney





half.italian@gmail.com
  Reply With Quote
Old 03-15-2007, 05:38 AM   #4
Gabriel Genellina
 
Posts: n/a
Default Re: Circular Class Logic
<half.italian <at> gmail.com> writes:

> That's not exactly what I'm doing, but your comment still might help.
> I actually want to include an instance of a subclass in it's
> superclass like this:


Move the initialization to another function.

>
> ===== foo.py =====
> # import Baz

Remove the line above
>
> class Foo:
> # baz = Baz.Baz()

Remove the line above
>
> def __init__(self):
> pass
> =====


and add this below:
def initFoo():
import baz
Foo.baz = baz.Baz()
initFoo()

No changes in bar.py, baz.py
Instead of initFoo, you could use a custom metaclass. Or a class decorator (if
and when they become available...)
The code above is an effective way of doing what you want. But I'd think about
the actual need of doing such things - are you sure it's a good design?

--
Gabriel Genellina



Gabriel Genellina
  Reply With Quote
Old 03-15-2007, 12:01 PM   #5
half.italian@gmail.com
 
Posts: n/a
Default Re: Circular Class Logic
> Remove the line above
> and add this below:
> def initFoo():
> import baz
> Foo.baz = baz.Baz()
> initFoo()


I got it to work, but I had to add a check to see if the class
variable had been set..

def initBaz():
import Baz
Foo.baz = Baz.Baz()

class Foo:
baz = None
def __init__(self):
if Foo.baz == None:
Foo.baz = True
initBaz()

What exactly is being accomplished by having the init function outside
of the class? If there is no check, wouldn't it just execute every
time an object is instantiated anyway?

> Instead of initFoo, you could use a custom metaclass. Or a class decorator (if
> and when they become available...)


I haven't tried either of those yet. The names scare me. Sounds
like this might be a good time to explore them.

> The code above is an effective way of doing what you want. But I'd think about
> the actual need of doing such things - are you sure it's a good design?
>


I thought it was a good design, but now I'm not so sure. I'm
untrained, so often I dont know the right way to do things. As I
build this into the libraries, I'll keep an eye on how the code is
developing and go from there. Thanks for the help!

~Sean



half.italian@gmail.com
  Reply With Quote
Old 03-15-2007, 12:48 PM   #6
Paul McGuire
 
Posts: n/a
Default Re: Circular Class Logic
On Mar 15, 7:01 am, half.ital...@gmail.com wrote:
> > Remove the line above
> > and add this below:
> > def initFoo():
> > import baz
> > Foo.baz = baz.Baz()
> > initFoo()

>
> I got it to work, but I had to add a check to see if the class
> variable had been set..
>
> def initBaz():
> import Baz
> Foo.baz = Baz.Baz()
>
> class Foo:
> baz = None
> def __init__(self):
> if Foo.baz == None:
> Foo.baz = True
> initBaz()
>
> What exactly is being accomplished by having the init function outside
> of the class? If there is no check, wouldn't it just execute every
> time an object is instantiated anyway?
>
> > Instead of initFoo, you could use a custom metaclass. Or a class decorator (if
> > and when they become available...)

>
> I haven't tried either of those yet. The names scare me. Sounds
> like this might be a good time to explore them.
>
> > The code above is an effective way of doing what you want. But I'd think about
> > the actual need of doing such things - are you sure it's a good design?

>
> I thought it was a good design, but now I'm not so sure. I'm
> untrained, so often I dont know the right way to do things. As I
> build this into the libraries, I'll keep an eye on how the code is
> developing and go from there. Thanks for the help!
>
> ~Sean


Just initialize Folder at module level - see below.
-- Paul

class Folder(object):
def __init__(self,path):
self.path = path
pass

def __repr__(self):
return self.__class__.__name__+"("+self.path+")"

class Disk(Folder):
def __init__(self,driveLetter):
super(Disk,self).__init__(driveLetter+":/")

# hokey function to test if a drive letter points to a drive, I'm
# sure there's a better way
import os,string
def isDisk(d):
try:
os.stat(d + ":/")
return True
except:
return False

# instead of calling some initFolder() method, just include this
statement
# at module level in the module that declares both classes
Folder.allDisks = map(Disk,[d for d in string.uppercase if isDisk(d)])

# now can reference allDisks through Folder instances
f = Folder("C:/temp")
print f.allDisks


prints:
[Disk(C:/), Disk(D:/), Disk(E:/)]




Paul McGuire
  Reply With Quote
Old 03-15-2007, 06:55 PM   #7
half.italian@gmail.com
 
Posts: n/a
Default Re: Circular Class Logic
> Just initialize Folder at module level - see below.
> -- Paul
>
> class Disk(Folder):
> def __init__(self,driveLetter):
> super(Disk,self).__init__(driveLetter+":/")


What is going on there? Is it just explicitly calling the super's
init function? How is that really different from this:

class Disk(Folder):
def __init__(self,driveLetter):
Folder.Folder.__init__(self.path) # ??? Being that Folder is the
superclass?

I'd like to be able to use the shared Disk objects in any class that
is a subclass of Data. Will the above method still make the Disk
objects available in File.py? Also, what if the classes are in
different modules.

I'll try to experiment with it this afternoon. I'm using more
information than just the drive letter. What if the user wants to
find out the unc path to the share given the drive letter, or copy a
file to the local disk that is not a system disk that has the most
available space on it, or wants to mount or unmount a network drive.

pause...

I'm trying to justify why the Folders/Files really need the drive info
beyond just the paths and I'm having a hard time. I even just tried
to give an example of how it would be used, and couldn't. It seems to
make sense on a gut level, but maybe it's just as usefull on it's
own. There's definitely justification for having Disks be a subclass
of Folder, but not necessarily for there to be an instance of it
available within the classes. All that kind of work will be external
to the class.

I think I'll backtrace and keep it separate. Thanks for letting me
think it through.

~Sean



half.italian@gmail.com
  Reply With Quote
Old 03-15-2007, 07:25 PM   #8
Paul McGuire
 
Posts: n/a
Default Re: Circular Class Logic
On Mar 15, 1:55 pm, half.ital...@gmail.com wrote:
> > class Disk(Folder):
> > def __init__(self,driveLetter):
> > super(Disk,self).__init__(driveLetter+":/")

>
> What is going on there? Is it just explicitly calling the super's
> init function?


What is going on is that Disk is being initialized with a single
character, such as 'D', and then calling the superclass with 'D:/',
the root folder on D. You're the one who said that Disk was a
subclass of Folder (sorry, you called it "Data"), so I tried to come
up with an example in which this made some kind of sense.

> How is that really different from this:
>
> class Disk(Folder):
> def __init__(self,driveLetter):
> Folder.Folder.__init__(self.path) # ??? Being that Folder is the
> superclass?
>

Where did self.path come from? Even though Folder is the superclass,
self.path doesn't exist until the Folder.__init__ method gets called.
This ain't C++ you know. And as I said above, we are taking a single
character drive letter, and calling the superclass init with the root
directory of that drive, so these are .

> I'd like to be able to use the shared Disk objects in any class that
> is a subclass of Data. Will the above method still make the Disk
> objects available in File.py? Also, what if the classes are in
> different modules.
>
> I'll try to experiment with it this afternoon. I'm using more
> information than just the drive letter. What if the user wants to
> find out the unc path to the share given the drive letter, or copy a
> file to the local disk that is not a system disk that has the most
> available space on it, or wants to mount or unmount a network drive.
>

Knock yourself out. I just hacked together these Folder/Disk classes
by way of a half-baked-but-working example. My point is that to
initialize a class level variable on class Foo, all that is needed is
to assign it in the defining module, that is:

class Foo:
pass

Foo.fooClassVar = "a class level variable"

Now any Foo or sub-Foo can access fooClassVar. The type of
fooClassVar can be anything you want, whether it is a Foo, subclass of
Foo or whatever, as long as it has been defined by the time you assign
fooClassVar.

-- Paul



Paul McGuire
  Reply With Quote
Old 03-15-2007, 08:14 PM   #9
Gabriel Genellina
 
Posts: n/a
Default Re: Circular Class Logic
En Thu, 15 Mar 2007 09:01:07 -0300, <> escribió:

> I got it to work, but I had to add a check to see if the class
> variable had been set..
> class Foo:
> baz = None
> def __init__(self):
> if Foo.baz == None:
> Foo.baz = True
> initBaz()


This is a different approach. You are using instance initialization
(Foo.__init__) to finish class initialization. Foo.__init__ will be called
each time you create a Foo instance; that's why you had to check if
Foo.baz is None.
(BTW, Foo.baz=True is unneeded).
The only problem I can see is that the Foo class is not completely
initialized until its first instance is created; this may not be a problem
in your case.

> What exactly is being accomplished by having the init function outside
> of the class? If there is no check, wouldn't it just execute every
> time an object is instantiated anyway?


What I intended was different:

==========
C:\TEMP>type foo.py
class Foo:
baz = None

def __init__(self):
pass

def initFoo():
import baz
Foo.baz = baz.Baz()
initFoo()

C:\TEMP>type bar.py
import foo

class Bar(foo.Foo):
pass

C:\TEMP>type baz.py
import bar

class Baz(bar.Bar):
pass

C:\TEMP>type test.py
import foo,bar,baz

print foo.Foo.baz
f = foo.Foo()
print f.baz
b = bar.Bar()
print b.baz
print baz.Baz.baz

C:\TEMP>python test.py
<baz.Baz instance at 0x00AD7B20>
<baz.Baz instance at 0x00AD7B20>
<baz.Baz instance at 0x00AD7B20>
<baz.Baz instance at 0x00AD7B20>
==========

initFoo is only executed when Foo is imported the first time. Note that
you can't do that if

> I thought it was a good design, but now I'm not so sure. I'm
> untrained, so often I dont know the right way to do things. As I
> build this into the libraries, I'll keep an eye on how the code is
> developing and go from there. Thanks for the help!


Usually Python code is quite concise and straightforward; when I find
myself writing things too convoluted, I know it's time to
refactor/redesign. (Anyway some things remain not as simple as I'd like
)
Perhaps you later find the need for a different/better way.

--
Gabriel Genellina



Gabriel Genellina
  Reply With Quote
Old 03-16-2007, 02:02 AM   #10
half.italian@gmail.com
 
Posts: n/a
Default Re: Circular Class Logic
> > How is that really different from this:
>
> > class Disk(Folder):
> > def __init__(self,driveLetter):
> > Folder.Folder.__init__(self.path) # ??? Being that Folder is the
> > superclass?

>
> Where did self.path come from? Even though Folder is the superclass,
> self.path doesn't exist until the Folder.__init__ method gets called.
> This ain't C++ you know.


My bad. I should have said:

class Disk(Folder):
def __init__(self,driveLetter):
Folder.Folder.__init__(self, driveLetter + ":/")

> Knock yourself out. I just hacked together these Folder/Disk classes
> by way of a half-baked-but-working example. My point is that to
> initialize a class level variable on class Foo, all that is needed is
> to assign it in the defining module, that is:
>
> class Foo:
> pass
>
> Foo.fooClassVar = "a class level variable"


> Now any Foo or sub-Foo can access fooClassVar. The type of
> fooClassVar can be anything you want, whether it is a Foo, subclass of
> Foo or whatever, as long as it has been defined by the time you assign
> fooClassVar.


That was the first thing I tried, but because the libs were importing
each other, etc, it got hung up with wierd "This module doesn't exist"
errors, when it clearly did.

~Sean





half.italian@gmail.com
  Reply With Quote
Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
loading java class from .war file jayeth Software 0 04-09-2009 07:06 PM
Eclipse how to add external class with different pkg name jan2321 General Help Related Topics 0 11-06-2008 10:04 AM
70-536, 3 questions blade MCTS 11 03-23-2008 03:47 PM
2007/11/29 Boris 7 new programs, Logic Studio 8 for Mac, MicrosoftVisual Studio 2008 Professional Edition, Microsoft Windows Vista UltimateNov-2007.Win32/64, other new programs ola@mail.gr DVD Video 0 11-29-2007 06:15 AM
Storing class with session (ASP.Net) bqmassey Software 0 09-22-2006 05:37 PM




SEO by vBSEO 3.3.2 ©2009, Crawlability, Inc.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46