Postpone creation of attributes until needed

Steven D'Aprano steve at REMOVE.THIS.cybersource.com.au
Mon Jun 11 07:56:58 EDT 2007


On Mon, 11 Jun 2007 03:58:16 -0700, Frank Millman wrote:

>> By using slots, you're telling Python not to reserve space for a __dict__,
>> which means that your class cannot create attributes on the fly.
>>
> 
> I understand that. In fact I was already using slots, as I was
> concerned about the number of 'column' instances that could be created
> in any one program, and wanted to minimise the footprint. 

Unless you have thousands and thousands of instances, __slots__ is almost
certainly not the answer. __slots__ is an optimization to minimize the
size of each instance. The fact that it prevents the creation of new
attributes is a side-effect.


> I have since
> read some of caveats regarding slots, but I am not doing anything out
> of the ordinary so I feel comfortable with them so far.
> 
>> > I use __slots__ to catch any invalid attributes, otherwise I would get
>> > a 'maximum recursion depth exceeded' error.
>>
>> That's the wrong solution to that problem. To avoid that problem,
>> __getattr__ should write directly to self.__dict__.
>>
> 
> Are you saying that instead of
> 
>     self.z = self.x * self.y
>     return getattr(self.name)
> 
> I should have
> 
>     self.__dict__['z'] = self.x * self.y
>     return self.__dict__[name]
> 
> I tried that, but I get AttributeError: 'A' object has no attribute
> '__dict__'.

Of course you do, because you are using __slots__ and so there is no
__dict__ attribute.

I really think you need to lose the __slots__. I don't see that it really
gives you any advantage.



> Aslo, how does this solve the problem that 'name' may not be one of
> the attributes that my 'compute' method sets up. Or are you saying
> that, if I fixed the previous problem, it would just raise
> AttributeError anyway, which is what I would want to happen.

You haven't told us what the 'compute' method is.

Or if you have, I missed it.


>> > Is this ok, or is there a better way?
>>
>> At the interactive Python prompt:
>>
>> help(property)
>>
> 
> See my reply to Phil - I would use property if there was only one
> attribute, but there are several.

Writing "several" properties isn't that big a chore, especially if they
have any common code that can be factored out.

Another approach might be to create a factory-function that creates the
properties for you, so you just need to call it like this:

class MyClass(object):
    x = property_maker(database1, tableX, 'x', other_args)
    y = property_maker(database2, tableY, 'y', other_args)
    # blah blah blah

def property_maker(database, table, name, args):
    def getx(self):
        return getattr(database[table], name)  # or whatever...
    def setx(self, value):
        setattr(database[table], name, value)
    return property(getx, setx, None, "Some doc string")



-- 
Steven.




More information about the Python-list mailing list