Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Assigning to self

Reply
Thread Tools

Assigning to self

 
 
Frans Englich
Guest
Posts: n/a
 
      01-17-2005

Hello,

I am having trouble with throwing class instances around. Perhaps I'm
approaching my goals with the wrong solution, but here's nevertheless a
stripped down example which demonstrates my scenario:

#------------------------------------------------------------------------------------------

class foo:
tests = {}
def __init__( self, id ):

try:
me = self.__class__.tests[ id ]

except KeyError:
print "Did not exist, initializing myself.."
self.attr = "exists"
self.__class__.tests[ id ] = self

else:
print "Already exists! Re-using existing instance"
self = me

print "Me", self.attr + "!" # line 18

def yo(self):
return self.attr # line 21

def main():

a = foo( "test" )
print "ATTR:", a.yo()

b = foo( "test" )
print "ATTR:", b.yo()

if __name__ == "__main__":
main()

#------------------------------------------------------------------------------------------

This is the output:

Did not exist, initializing myself..
Me exists!
ATTR: exists
Already exists! Re-using existing instance
Me exists!
ATTR:
Traceback (most recent call last):
File "cpClass.py", line 32, in ?
main()
File "cpClass.py", line 29, in main
print "ATTR:", b.yo()
File "cpClass.py", line 21, in yo
return self.attr # line 21
AttributeError: foo instance has no attribute 'attr'
#------------------------------------------------------------------------------------------

What the code attempts to do is implementing a, to the API user, transparent
memory-saver by ensuring that no more than one instance of the class foo
exists for a particular id. E.g, the user can simply "create" an instance and
if one not already exists, it is created.

First of all; am I approaching the goal with the right solution?

The way I do fails, obviously. The line 'self = me'(scary..) doesn't really
work for the attribute attr; the attribute exists on line 21, but it fails
when yo() tries to access it. What have failed? Is it a namespace scope
issue? Do 'self = me' do what I think it should?


Cheers,

Frans




 
Reply With Quote
 
 
 
 
Peter Otten
Guest
Posts: n/a
 
      01-17-2005
Frans Englich wrote:

> What the code attempts to do is implementing a, to the API user,
> transparent memory-saver by ensuring that no more than one instance of the
> class foo exists for a particular id. E.g, the user can simply "create" an
> instance and if one not already exists, it is created.


By the time __init__() is called, a new Foo instance has already been
created. Therefore you need to implement Foo.__new__(). E. g.:

>>> class Foo(object):

.... cache = {}
.... def __new__(cls, id):
.... try:
.... return cls.cache[id]
.... except KeyError:
.... pass
.... cls.cache[id] = result = object.__new__(cls, id)
.... return result
.... def __init__(self, id):
.... self.id = id
.... def __repr__(self):
.... return "Foo(id=%r)" % self.id
....
>>> foos = map(Foo, "abca")
>>> foos

[Foo(id='a'), Foo(id='b'), Foo(id='c'), Foo(id='a')]
>>> foos[0] is foos[-1]

True
>>> Foo.cache

{'a': Foo(id='a'), 'c': Foo(id='c'), 'b': Foo(id='b')}

Note that putting the instances into the cache prevents them from being
garbage collected -- you may even end up with higher memory usage.
Use a weakref.WeakValueDictionary instead of the normal dict to fix that.

Peter


 
Reply With Quote
 
 
 
 
Reinhold Birkenfeld
Guest
Posts: n/a
 
      01-17-2005
Frans Englich wrote:
> Hello,
>
> I am having trouble with throwing class instances around. Perhaps I'm
> approaching my goals with the wrong solution, but here's nevertheless a
> stripped down example which demonstrates my scenario:
>
> #------------------------------------------------------------------------------------------
>
> class foo:
> tests = {}
> def __init__( self, id ):
>
> try:
> me = self.__class__.tests[ id ]
>
> except KeyError:
> print "Did not exist, initializing myself.."
> self.attr = "exists"
> self.__class__.tests[ id ] = self
>
> else:
> print "Already exists! Re-using existing instance"
> self = me
>
> print "Me", self.attr + "!" # line 18
>
> def yo(self):
> return self.attr # line 21


As 'self' is a method parameter, changing it only affects the current
function. When __init__ is called, the instance is already created, so
you can't change it.

What you are looking for is a class factory (is this term correct?),
here is a sample implementation (using 2.4 decorators):

class foo:
tests = {}
@classmethod
def get_test(cls, id):
if cls.tests.has_key(id):
return cls.tests[id]
else:
inst = cls()
inst.attr = "exists"
cls.tests[id] = inst
return inst

def yo(self):
return self.attr

Here you define get_test as a classmethod, that is, it does not receive
the instance as first argument, but the class. It can be called from the
class (foo.get_test) or an instance (foo().get_test).

An alternative might be to override __new__, but I'm sure someone other
will suggest this.

Reinhold
 
Reply With Quote
 
John Roth
Guest
Posts: n/a
 
      01-17-2005
"Frans Englich" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed)...
>
> Hello,
>

[...]

>
> What the code attempts to do is implementing a, to the API user,
> transparent
> memory-saver by ensuring that no more than one instance of the class foo
> exists for a particular id. E.g, the user can simply "create" an instance
> and
> if one not already exists, it is created.


In other words, you're trying to create a singleton. In general,
singletons are frowned on these days for a number of reasons,
not least because of the difficulty of testing them.

> First of all; am I approaching the goal with the right solution?


No. In all Python releases since 2.2, the correct way of doing this is to
use the __new__() method. Unfortunately, the only place it is documented
is here:

http://www.python.org/2.2.3/descrintro.html

and here:

http://users.rcn.com/python/download/Descriptor.htm

The first reference contains an example of how to do
a singleton: simply search on the word Singleton.

John Roth

> Cheers,
>
> Frans
>
>
>
>


 
Reply With Quote
 
Frans Englich
Guest
Posts: n/a
 
      01-17-2005
On Monday 17 January 2005 19:02, Peter Otten wrote:
> Frans Englich wrote:
> > What the code attempts to do is implementing a, to the API user,
> > transparent memory-saver by ensuring that no more than one instance of
> > the class foo exists for a particular id. E.g, the user can simply
> > "create" an instance and if one not already exists, it is created.

>
> By the time __init__() is called, a new Foo instance has already been
>
> created. Therefore you need to implement Foo.__new__(). E. g.:
> >>> class Foo(object):

>
> ... cache = {}
> ... def __new__(cls, id):
> ... try:
> ... return cls.cache[id]
> ... except KeyError:
> ... pass
> ... cls.cache[id] = result = object.__new__(cls, id)
> ... return result
> ... def __init__(self, id):
> ... self.id = id
> ... def __repr__(self):
> ... return "Foo(id=%r)" % self.id
> ...


I'm not sure, but I think this code misses one thing: that __init__ is called
each time __new__ returns it, as per the docs Peter posted.


Cheers,

Frans

 
Reply With Quote
 
Frans Englich
Guest
Posts: n/a
 
      01-17-2005
On Monday 17 January 2005 20:55, Frans Englich wrote:
> On Monday 17 January 2005 19:02, Peter Otten wrote:
> > Frans Englich wrote:
> > > What the code attempts to do is implementing a, to the API user,
> > > transparent memory-saver by ensuring that no more than one instance of
> > > the class foo exists for a particular id. E.g, the user can simply
> > > "create" an instance and if one not already exists, it is created.

> >
> > By the time __init__() is called, a new Foo instance has already been
> >
> > created. Therefore you need to implement Foo.__new__(). E. g.:
> > >>> class Foo(object):

> >
> > ... cache = {}
> > ... def __new__(cls, id):
> > ... try:
> > ... return cls.cache[id]
> > ... except KeyError:
> > ... pass
> > ... cls.cache[id] = result = object.__new__(cls, id)
> > ... return result
> > ... def __init__(self, id):
> > ... self.id = id
> > ... def __repr__(self):
> > ... return "Foo(id=%r)" % self.id
> > ...

>
> I'm not sure, but I think this code misses one thing: that __init__ is
> called each time __new__ returns it, as per the docs Peter posted.


Ahem, John I ment

The second typo today..


Cheers,

Frans

 
Reply With Quote
 
Frans Englich
Guest
Posts: n/a
 
      01-17-2005
On Monday 17 January 2005 20:03, John Roth wrote:
> "Frans Englich" <(E-Mail Removed)> wrote in message


<snip>

> In other words, you're trying to create a singleton. In general,
> singletons are frowned on these days for a number of reasons,
> not least because of the difficulty of testing them.


Then I have some vague, general questions which perhaps someone can reason
from: what is then the preferred methods for solving problems which requires
Singletons? Is it only frowned upon in Python code?


Cheers,

Frans

 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      01-17-2005
Frans Englich wrote:

>> > >>> class Foo(object):
>> >
>> > ... cache = {}
>> > ... def __new__(cls, id):
>> > ... try:
>> > ... return cls.cache[id]
>> > ... except KeyError:
>> > ... pass
>> > ... cls.cache[id] = result = object.__new__(cls, id)
>> > ... return result
>> > ... def __init__(self, id):
>> > ... self.id = id
>> > ... def __repr__(self):
>> > ... return "Foo(id=%r)" % self.id
>> > ...

>>
>> I'm not sure, but I think this code misses one thing: that __init__ is
>> called each time __new__ returns it, as per the docs Peter posted.

>
> Ahem, John I ment


You are right -- just put the initialization into the __new__() method,
then.

Peter

 
Reply With Quote
 
Peter Otten
Guest
Posts: n/a
 
      01-17-2005
Frans Englich wrote:

> On Monday 17 January 2005 20:03, John Roth wrote:
>> "Frans Englich" <(E-Mail Removed)> wrote in message

>
> <snip>
>
>> In other words, you're trying to create a singleton. In general,
>> singletons are frowned on these days for a number of reasons,
>> not least because of the difficulty of testing them.

>
> Then I have some vague, general questions which perhaps someone can reason
> from: what is then the preferred methods for solving problems which
> requires Singletons? Is it only frowned upon in Python code?


Sorry, no answer here, but do you really want a singleton?

Singleton: "Ensure a class only has one instance, and provide a global point
of access to it"

whereas

Flyweight: "Use sharing to support large numbers of fine-grained objects
efficiently"

as per "Design Patterns" by Gamma et al.

Peter

 
Reply With Quote
 
Frans Englich
Guest
Posts: n/a
 
      01-17-2005
On Monday 17 January 2005 21:24, Peter Otten wrote:
> Frans Englich wrote:
> > On Monday 17 January 2005 20:03, John Roth wrote:
> >> "Frans Englich" <(E-Mail Removed)> wrote in message

> >
> > <snip>
> >
> >> In other words, you're trying to create a singleton. In general,
> >> singletons are frowned on these days for a number of reasons,
> >> not least because of the difficulty of testing them.

> >
> > Then I have some vague, general questions which perhaps someone can
> > reason from: what is then the preferred methods for solving problems
> > which requires Singletons? Is it only frowned upon in Python code?

>
> Sorry, no answer here, but do you really want a singleton?
>
> Singleton: "Ensure a class only has one instance, and provide a global
> point of access to it"
>
> whereas
>
> Flyweight: "Use sharing to support large numbers of fine-grained objects
> efficiently"
>
> as per "Design Patterns" by Gamma et al.


Hehe Singleton sounds like what I want, but OTOH I do not know what
Flyweight is, except for sounding interesting. Darn, I really must save for
that Design Patterns by GOF.


Cheers,

Frans

 
Reply With Quote
 
 
 
Reply

Thread Tools

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

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


Similar Threads
Thread Thread Starter Forum Replies Last Post
Changing self: if self is a tree how to set to a different self Bart Kastermans Python 6 07-13-2008 11:19 AM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) falcon Python 0 07-31-2005 05:41 PM
Re: __autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 2 07-12-2005 03:20 AM
Proposal: reducing self.x=x; self.y=y; self.z=z boilerplate code Ralf W. Grosse-Kunstleve Python 16 07-11-2005 09:28 PM
__autoinit__ (Was: Proposal: reducing self.x=x; self.y=y;self.z=z boilerplate code) Ralf W. Grosse-Kunstleve Python 18 07-11-2005 04:01 PM



Advertisments