473,383 Members | 1,874 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,383 software developers and data experts.

Computing class variable on demand?

We all know that using __getattr__() we can compute an instance
variable on demand, for example:

class Foo:
def __getattr__ (self, name):
if name == 'bar':
self.bar = 'apple'
return self.bar
else:
raise AttributeError()

Then we can

f = Foo()
s1 = f.bar
s2 = f.bar # this uses the "cached" result

My question is can we do the same with class variables? I can't find a
class-equivalent __getattr__ for this purpose. The key is to allow the
use of the following statement

Foo.bar # bar is a class variable of Foo computed on demand
without unnecessary fudge. Thanks.

Jul 18 '05 #1
4 1922
fortepianissimo wrote:
We all know that using __getattr__() we can compute an instance
variable on demand, for example:

class Foo:
def __getattr__ (self, name):
if name == 'bar':
self.bar = 'apple'
return self.bar
else:
raise AttributeError()

Then we can

f = Foo()
s1 = f.bar
s2 = f.bar # this uses the "cached" result

My question is can we do the same with class variables?


You can do this using a metaclass, e.g.:

py> class FooType(type):
.... def __getattr__(self, name):
.... if name == 'bar':
.... self.bar = 'apple'
.... return self.bar
.... else:
.... raise AttributeError('no attribute named %r' % name)
....
py> class Foo(object):
.... __metaclass__ = FooType
....
py> Foo.bar
'apple'

However, you probably don't want to. What's your use case?

Steve
Jul 18 '05 #2
fortepianissimo wrote:
Thank you so much about this useful tip! I learned the new decorator
feature of 2.4 simply because of your post.

Unfortunately I don't have luxury right now to run Python 2.4 (for what
I'm doing anyways). You mentioned the way to do decorator in 2.3. Still
I have a question here. Here is Scott David Daniels's code for lazy
initialization:

class Lazy (object):
def __init__ (self, calculate_function):
self._calculate = calculate_function

def __get__ (self, obj, _=None):
if obj is None:
return self
value = self._calculate(obj)
setattr(obj, self._calculate.func_name, value)
return value

The problem I run into using this for *instance* variables is: the
setattr() call won't work with a class with __slots__ defined - it
simply produces error that the attribute we want to modify is
read-only. Is there a workaround of this problem?


Sounds like you're declaring the class variables in your __slots__ too.
Is this true? I don't think that's necessary -- __slots__ is only for
used for instances. So, for example, this code should work okay:

py> class Foo(object):
.... __slots__ = ['baz']
.... class __metaclass__(type):
.... def bar(self):
.... print 'slow initialization'
.... return 'apple'
.... bar = LazyAttribute(bar)
.... def __init__(self, baz):
.... self.baz = baz
....
py> f = Foo(1)
py> f.baz
1
py> f.bar
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
AttributeError: 'Foo' object has no attribute 'bar'
py> f.__class__.bar
slow initialization
'apple'
py> Foo.bar
'apple'

Note that if you want to reference the class variable, you have to
specficially go through the class, instead of counting on the instance
lookup as classes without __slots__ can. But as long as you don't
declare 'bar' as a slot, you should still be able to access Foo.bar.

Note that you probably don't want to have 'bar' as both a class variable
and an instance variable -- then the instance variable will just hide
the class variable...

HTH,

Steve
Jul 18 '05 #3
Thanks Steve - actually my question was simpler than that. I just
wanted to use Daniels' recipe of lazy initialization on objects with
__slots__:

class Lazy(object):
def __init__(self, calculate_function):
self._calculate = calculate_function

def __get__(self, obj, _=None):
if obj is None:
return self
value = self._calculate(obj)
setattr(obj, self._calculate.func_name, value)
return value
class SomeClass(object):

__slots__ = 'someprop'

@Lazy
def someprop(self):
print 'Actually calculating value'
return 13
o = SomeClass()
print o.someprop
print o.someprop

Running the code above will produce:

Actually calculating value
Traceback (most recent call last):
File "Lazy.py", line 26, in ?
print o.someprop
File "Lazy.py", line 11, in __get__
setattr(obj, self._calculate.func_name, value)
AttributeError: 'SomeClass' object attribute 'someprop' is read-only
Removing the __slots__ statement, everything would run normally.

Is there any workaround?

Jul 18 '05 #4
fortepianissimo wrote:
Thanks Steve - actually my question was simpler than that. I just
wanted to use Daniels' recipe of lazy initialization on objects with
__slots__:

class Lazy(object):
def __init__(self, calculate_function):
self._calculate = calculate_function

def __get__(self, obj, _=None):
if obj is None:
return self
value = self._calculate(obj)
setattr(obj, self._calculate.func_name, value)
return value
class SomeClass(object):

__slots__ = 'someprop'

@Lazy
def someprop(self):
print 'Actually calculating value'
return 13
o = SomeClass()
print o.someprop
print o.someprop

Running the code above will produce:

Actually calculating value
Traceback (most recent call last):
File "Lazy.py", line 26, in ?
print o.someprop
File "Lazy.py", line 11, in __get__
setattr(obj, self._calculate.func_name, value)
AttributeError: 'SomeClass' object attribute 'someprop' is read-only
Removing the __slots__ statement, everything would run normally.

Is there any workaround?

Hmm... Well, there's a thread on a similar topic:

http://mail.python.org/pipermail/pyt...ay/035575.html

The summary is basically that '__slots__' creates descriptors for all
the names in the __slots__ iterable. If you define a function (or a
Lazy object) at the class level with the same name as a slot, it
replaces the descriptor for that slot name. So then when setattr gets
called, it can't find the descriptor anymore, so it can't write the value...

One workaround would be to have Lazy store the values instead of setting
the attribute on the instance -- something like:

py> class Lazy(object):
.... def __init__(self, calculate_function):
.... self._calculate = calculate_function
.... self._values = {}
.... def __get__(self, obj, _=None):
.... if obj is None:
.... return self
.... obj_id = id(obj)
.... if obj_id not in self._values:
.... self._values[obj_id] = self._calculate(obj)
.... return self._values[obj_id]
....
py>
py> class SomeClass(object):
.... __slots__ = []
.... @Lazy
.... def someprop(self):
.... print 'Actually calculating value'
.... return 13
....
py> o = SomeClass()
py> o.someprop
Actually calculating value
13
py> o.someprop
13

Basically Lazy just stores a mapping from object ids to calculated
values. Not as pretty as the original solution, but if you have to have
__slots__ defined[1], I guess this might work.

Note that I don't need to declare any slots since the someprop
descriptor is a class-level attribute, not an instance-level one...

Steve

[1] Are you sure you have to use __slots__? Unless you're creating a
very large number of these objects, you probably won't notice the
difference in memory consumption...
Jul 18 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Chua Wen Ching | last post by:
Hi there, I had applied this security permissions in my class library based on fxcop standards. Before namespace: using System.Runtime.InteropServices; using System.Security.Permissions;
9
by: Carl | last post by:
Hi, I have a class in .Net which I instantiate in my code behind on one of my aspx pages. When I am finished with the instance, what is teh best method of taking it out of memory. Should I...
1
by: Mythran | last post by:
I have the following setup: BLL Project Category.vb AssemblyInfo.vb Schema Project Category.xsd AssemblyInfo.vb
9
by: Crirus | last post by:
I have ~200 players on a server... They share the same 512x512 tiles map... Each player have an explored area and a visible area... visible area is given by players's current units and...
16
by: Basil Fawlty | last post by:
Hi everyone, I have an assignment, to create a simple VB program that computes the volume of a cylinder. The Form is pretty simple, it has a label and text box for base radius, another for height...
1
by: stephane | last post by:
I have a problem which must be in this : print" <script type='text/javascript'> document.location.replace('http://127.0.0.1/add_task.php?req_id={$maxValue}&tk_request_name={$req_name}');...
42
by: John Smith | last post by:
In a C program I need to do exponentiation where the base is negative and the exponent is a fraction. In standard C this would be something like t = pow(-11.5, .333), but with this combination of...
13
by: Xah Lee | last post by:
Today, a motherfucker Christophe Rhodes (aka Xof in irc://chat.freenode.net/lisp ) kicked banned me. Here's the few relevant excerpt. (full, unedited excerpt will be published if there is a public...
14
by: Aaron Watters | last post by:
So, in between skiing runs I noticed a Business Week cover story on "cloud computing". The article had lots of interesting information in it like about how somebody's mom used to be an airline...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.