Postpone creation of attributes until needed

Frank Millman frank at chagford.com
Mon Jun 11 12:58:16 CEST 2007


On Jun 11, 12:21 pm, Steven D'Aprano
<s... at REMOVE.THIS.cybersource.com.au> wrote:
> On Mon, 11 Jun 2007 02:24:51 -0700, Frank Millman wrote:
> > Hi all
>
> > I have a small problem. I have come up with a solution, but I don't
> > know if it is a) safe, and b) optimal.
>
> > I have a class with a number of attributes, but for various reasons I
> > cannot assign values to all the attributes at __init__ time, as the
> > values depend on attributes of other linked classes which may not have
> > been created yet. I can be sure that by the time any values are
> > requested, all the other classes have been created, so it is then
> > possible to compute the missing values.
>
> Unless you're doing something like creating classes in one thread while
> another thread initiates your instance, I don't understand how this is
> possible.
>

I was hoping not to have to explain this, as it gets a bit complicated
(yes, I have read The Zen of Python ;-), but I will try.

I have a class that represents a database table, and another class
that represents a database column. When the application 'opens' a
table, I create an instance for the table and separate instances for
each column.

If there are foreign keys, I used to automatically open the foreign
table with its columns, and build cross-references between the foreign
key column on the first table and the primary key column on the second
table.

I found that as the database grew, I was building an increasing number
of links, most of which would never be used during that run of the
program, so I stopped doing it that way. Now I only open the foreign
table if the application requests it, but then I have to find the
original table and update it with attributes representing the link to
the new table.

It gets more complicated than that, but that is the gist of it.

> >>>> class A(object):
> > ...    __slots__ = ('x','y','z')
>
> 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. 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__'.

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.

> > 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.

Thanks

Frank




More information about the Python-list mailing list