'Once' properties.

0 views
Skip to first unread message

menomnon

unread,
Oct 5, 2009, 10:56:29 PM10/5/09
to
Does python have a ‘once’ (per class) feature?

‘Once’, as I’ve know it is in Eiffel. May be in Java don’t.

The first time you instantiate a given class into an object it
constructs, say, a dictionary containing static information. In my
case static is information that may change once a week at the most and
there’s no need to be refreshing this data during a single running of
the program (currently maybe 30 minutes).

So you instantiate the same class into a second object, but instead of
going to the databases again and recreating the same dictionary a
second time, you get a pointer or reference to the one already created
in the first object – copies into the second object that is. And the
dictionary, no matter how many instances of the object you make, is
always the same one from the first object.

So, as we put it, once per class and not object.

Saves on both time and space.

Chris Rebert

unread,
Oct 5, 2009, 11:04:21 PM10/5/09
to menomnon, pytho...@python.org
On Mon, Oct 5, 2009 at 7:56 PM, menomnon <pa...@well.com> wrote:
> Does python have a ‘once’ (per class) feature?

In Python, `class` is an executable statement, so you can put whatever
code you want in the class body (along with your method definitions)
and it will be run exactly once, at the time the class is defined
(that is, when the `class` statement is encountered by the
interpreter). In this way, you could create class variables containing
such static information.

Cheers,
Chris
--
http://blog.rebertia.com

Carl Banks

unread,
Oct 6, 2009, 2:07:36 AM10/6/09
to

Sounds like Borg Pattern:

http://code.activestate.com/recipes/66531/


Carl Banks

Carl Banks

unread,
Oct 6, 2009, 2:12:46 AM10/6/09
to


BTW, for your problem you'd probably want to add some kind of
conditional initialization code:


class Borg(object):
_shared_state = { 'initialized' : False }

def __init__(self):
self.__dict__ = self._shared_state
if self.initialized:
return
# perform initialization here
self.initialized = True


Carl Banks

Scott David Daniels

unread,
Oct 6, 2009, 2:50:12 AM10/6/09
to
menomnon wrote:
> Does python have a �once� (per class) feature?
>
> �Once�, as I�ve know it is in Eiffel. May be in Java don�t.

>
> The first time you instantiate a given class into an object it
> constructs, say, a dictionary containing static information. In my
> case static is information that may change once a week at the most and
> there�s no need to be refreshing this data during a single running of

> the program (currently maybe 30 minutes).
>
> So you instantiate the same class into a second object, but instead of
> going to the databases again and recreating the same dictionary a
> second time, you get a pointer or reference to the one already created
> in the first object � copies into the second object that is. And the

> dictionary, no matter how many instances of the object you make, is
> always the same one from the first object.
>
> So, as we put it, once per class and not object.
>
> Saves on both time and space.
Look into metaclasses:

class MyType(type):
def __new__(class_, name, bases, dct):
result = type.__new__(class_, name, bases, dct)
result._init_class()
return result

class ClassBase(object):
__metaclass__ = MyType

@classmethod
def _init_class(class_):
print 'initializing class'


class Initialized(ClassBase):
@classmethod
def _init_class(class_):
class_.a, class_.b = 1, 2
super(Initialized, class_)._init_class()

print Initialized.a, Initialized.b

--Scott David Daniels
Scott....@Acm.Org

Scott David Daniels

unread,
Oct 6, 2009, 10:25:41 AM10/6/09
to
Scott David Daniels wrote:
> ...
> Look into metaclasses:
...

> class Initialized(ClassBase):
> @classmethod
> def _init_class(class_):
> class_.a, class_.b = 1, 2
> super(Initialized, class_)._init_class()

Mea culpa: Here super is _not_ a good idea, and I had tried that
and recoded, but cut and pasted the wrong code. I just noticed
that I had done so this morning.

class Initialized(ClassBase):
@classmethod
def _init_class(class_):
class_.a, class_.b = 1, 2

ClassBase._init_class()

print Initialized.a, Initialized.b

Much better. There is probably a way to get to the MRO, but for now,
this should do.

--Scott David Daniels
Scott....@Acm.Org

Ben Finney

unread,
Oct 6, 2009, 7:09:51 PM10/6/09
to
Scott David Daniels <Scott....@Acm.Org> writes:

> Scott David Daniels wrote:
> > class Initialized(ClassBase):
> > @classmethod
> > def _init_class(class_):
> > class_.a, class_.b = 1, 2
> > super(Initialized, class_)._init_class()
>
> Mea culpa: Here super is _not_ a good idea,

[…]

Why is ‘super’ not a good idea here?

> class Initialized(ClassBase):
> @classmethod
> def _init_class(class_):
> class_.a, class_.b = 1, 2
> ClassBase._init_class()

What makes this implementation better than the one using ‘super’?

--
\ “I was once walking through the forest alone and a tree fell |
`\ right in front of me, and I didn't hear it.” —Steven Wright |
_o__) |
Ben Finney

Jean-Michel Pichavant

unread,
Oct 7, 2009, 6:14:40 AM10/7/09
to Ben Finney, Python List
Ben Finney wrote:
> Scott David Daniels <Scott....@Acm.Org> writes:
>
>
>> Scott David Daniels wrote:
>>
>>> class Initialized(ClassBase):
>>> @classmethod
>>> def _init_class(class_):
>>> class_.a, class_.b = 1, 2
>>> super(Initialized, class_)._init_class()
>>>
>> Mea culpa: Here super is _not_ a good idea,
>>
> […]
>
> Why is ‘super’ not a good idea here?
>
>
>> class Initialized(ClassBase):
>> @classmethod
>> def _init_class(class_):
>> class_.a, class_.b = 1, 2
>> ClassBase._init_class()
>>
>
> What makes this implementation better than the one using ‘super’?
>
>
a possible answer:
- explicit >> implicit

I'm not sure this is the correct one though :)

JM

alex23

unread,
Oct 7, 2009, 8:01:16 AM10/7/09
to
Jean-Michel Pichavant <jeanmic...@sequans.com> wrote:
> a possible answer:
> - explicit >> implicit
>
> I'm not sure this is the correct one though :)

To me, the explicit reference to the base class violates DRY. It also
means you need to manually change all such references should the base
class ever change, something that using super() avoids.

Jean-Michel Pichavant

unread,
Oct 7, 2009, 10:11:48 AM10/7/09
to alex23, pytho...@python.org
I found the correct answer
(http://www.artima.com/weblogs/viewpost.jsp?thread=236275)

" super is perhaps the trickiest Python construct: this series aims to
unveil its secrets"

"Having established that super cannot return the mythical superclass, we
may ask ourselves what the hell it is returning ;) The truth is that
super returns proxy objects.Informally speaking, a proxy is an object
with the ability to dispatch to methods of other objects via delegation.
Technically, super is a class overriding the __getattribute__ method.
Instances of super are proxy objects providing access to the methods in
the MRO."


Jean-Michel

Scott David Daniels

unread,
Oct 7, 2009, 11:17:25 AM10/7/09
to
Ben Finney wrote:
> Scott David Daniels wrote: ...

>>> class Initialized(ClassBase):


>>> @classmethod
>>> def _init_class(class_):
>>> class_.a, class_.b = 1, 2
>>> super(Initialized, class_)._init_class()
>> Mea culpa: Here super is _not_ a good idea,
> […]
> Why is ‘super’ not a good idea here?
>> class Initialized(ClassBase):
>> @classmethod
>> def _init_class(class_):
>> class_.a, class_.b = 1, 2
>> ClassBase._init_class()
> What makes this implementation better than the one using ‘super’?
>

Well, it doesn't end with an error message :-)

The reason for the error message is that super is built for instance
methods, not class methods. You'd need a class method style super
to get to "the next superclass in the __mro__ with an '_init_class'
method." Personally I don't see the need.
You could of course do it like this:

class MyOtherType(type):


def __new__(class_, name, bases, dct):
result = type.__new__(class_, name, bases, dct)

result()._init_class()
return result

class OtherClassBase(object):
__metaclass__ = MyOtherType

def _init_class(self):
print 'initializing class'

class Initialized(OtherClassBase):
def _init_class(self):
self.__class__.a, self.__class__.b = 1, 2
super(Initialized, self)._init_class()

This code is a problem because the point of this exercise is to do
initialization _before_ building an instance (think of building tables
used in __init__).

Before you decide that super should simply check if the second arg to
super is a subclass of the first arg, and operate differently in that
case (as my first code naively did), realize there is a problem. I saw
the problem in trying the code, and simply tacked in the proper parent
call and ran off to work.

Think about the fact that classes are now objects as well; a class
itself has a class (type or in these classes MyType or MyOtherType)
with its own needs for super, and the combination would be a mess.
I'm certain you'd get inadvertent switches across the two subtype
hierarchies, but that belief may just be my fear of the inevitable
testing and debugging issues such an implementation would require.

--Scott David Daniels
Scott....@Acm.Org

alex23

unread,
Oct 7, 2009, 7:02:32 PM10/7/09
to
Jean-Michel Pichavant <jeanmic...@sequans.com> wrote:

> alex23 wrote:
> > To me, the explicit reference to the base class violates DRY. It also
> > means you need to manually change all such references should the base
> > class ever change, something that using super() avoids.
>
> I found the correct answer
> (http://www.artima.com/weblogs/viewpost.jsp?thread=236275)

I'm not entirely sure how an opinion + explanation of the underlying
mechanics is more or less "correct" than a development principle...

Jean-Michel Pichavant

unread,
Oct 8, 2009, 9:28:37 AM10/8/09
to alex23, pytho...@python.org
The correctness applies to my answer, not the super mechanism. The super
mechanism is correct and properly documented since python 2.6, so anyone
is free to use it.
I'm just trying to give arguments in favor of using the explicit base
class name instead of super.

And in my opinion, explicit names are (slightly) better because there's
no underlying explanation required when using the base class name
instead of super.

JM

Reply all
Reply to author
Forward
0 new messages