By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
439,944 Members | 1,819 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 439,944 IT Pros & Developers. It's quick & easy.

Assigning to self

P: n/a

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


Jul 18 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
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
Jul 18 '05 #2

P: n/a
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
Jul 18 '05 #3

P: n/a
"Frans Englich" <fr***********@telia.com> wrote in message
news:ma**************************************@pyth on.org...

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


Jul 18 '05 #4

P: n/a
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

Jul 18 '05 #5

P: n/a
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

Jul 18 '05 #6

P: n/a
On Monday 17 January 2005 20:03, John Roth wrote:
"Frans Englich" <fr***********@telia.com> 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

Jul 18 '05 #7

P: n/a
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

Jul 18 '05 #8

P: n/a
Frans Englich wrote:
On Monday 17 January 2005 20:03, John Roth wrote:
"Frans Englich" <fr***********@telia.com> 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

Jul 18 '05 #9

P: n/a
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" <fr***********@telia.com> 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

Jul 18 '05 #10

P: n/a

"Frans Englich" <fr***********@telia.com> wrote in message
news:ma**************************************@pyth on.org...
On Monday 17 January 2005 20:03, John Roth wrote:
"Frans Englich" <fr***********@telia.com> 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?


I don't know of any generic methods that will work in all
cases _and_ are easy to apply. There are really two issues:
testing and abuse of the pattern.

There really are some places where you want a single instance
of something that is globally visible. Things that leap immediately
to mind include the connection to a data base and a logger
facility.

However, in a lot of cases, you find singletons used as an
"object oriented" substitute for a global variable, which stinks
just as badly as a global would. Since Python is a multi-paradigm
language, just put in a global at the module level. It's clearer.
Otherwise redesign.

There are several ways of getting around the testing
difficulty. One is the "toolbox" pattern that appears in a
number of places. The idea there is to have a single
object that proxies all of the singletons so that they
can be replace by testing versions at initialization time.

A neater and more modern method is to use an IOC
(Inversion of Control) container, or at least the pattern
involved. All IOC containers I'm aware of support
singletons and make testing them almost trivially
easy.

A third way is to simply take advantage of Python's
dynamic nature and have your tests stuff the testing
instance into the class object before the first call. This
is an ad-hoc variation on the IOC principle.

HTH

John Roth


Cheers,

Frans


Jul 18 '05 #11

P: n/a
In <ma**************************************@python.o rg>, Frans Englich
wrote:
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?


As already mentioned it's similar to a global variable. If I need a
"Singleton" I just put it as global into a module. Either initialize it
at module level or define a function with the content of your __init__().

Ciao,
Marc 'BlackJack' Rintsch
Jul 18 '05 #12

P: n/a
Marc 'BlackJack' Rintsch wrote:
Frans Englich wrote:
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?


As already mentioned it's similar to a global variable. If I need a
"Singleton" I just put it as global into a module. Either initialize it
at module level or define a function with the content of your __init__().


If one is determined to both use a Singleton and avoid having a plain
module-global variable, one could (ab)use function default parameters:

class __Foo:
"I am a singleton!"
pass

def Foo(foo_obj = __Foo()):
assert isinstance(foo_obj, __Foo
return foo_obj

Of course, this suffers from the weakness that one might pass an
object as an argument to the factory function and thus temporarily
override the Singleton-ness of __Foo... but a determined programmer
will work around any sort of protection scheme anyhow. ;)

In general, ISTM that if one wants a Singleton, it's best to create it
via a factory function (even if that function then masquerades as a
class). This gives you pretty good control over the circumstances in
which your Singleton will be created and/or retrieved, and it also
makes it trivial to replace the Singleton with some other pattern
(such as, e.g., a Flyweight or Borg object) should the need to
refactor arise.

Jeff Shannon
Technician/Programmer
Credit International
Jul 18 '05 #13

P: n/a
top
Jeff Shannon wrote:
class __Foo:
"I am a singleton!"
pass

def Foo(foo_obj = __Foo()):
assert isinstance(foo_obj, __Foo
return foo_obj

this is a bit simpler, I think, and takes advantage from Python's free
name-rebinding.

class Singleton(object):
def __call__(self):
return self
Singleton = Singleton()

And, now, every time you say obj = Singleton(), you're getting the same
instance. Of course, this corrupt the __call__ method of the class, and
isn't inheritance-safe at all, but if you want only one or two classes
like this, it isn't very much work to implement it. Also, it's free of
weird metaclasses, __new__s, or __dict__ hacks, I think.
Just putting my two-cents into this,
--
- Alexandre

Jul 18 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.