[Python-Dev] Class Methods

Tim Peters tim.one at home.com
Wed Apr 25 00:52:36 EDT 2001


[Thomas Heller]
> ...
> There are cases however (although not in the python library),
> where class attributes do not only provide _default_ values
> for the instance, but are shared among _all_ instances of this class.

Sure.

> Here is my actual example:
>
> I want to define C Structure-like classes, which can be used to wrap
> memory blocks, and allow access via attribute names.
>
> Take the following C code:
>
> struct POINT{
>     int x, y;
> };
>
> which I would like to define in python in this way:
>
> class POINT(Structure):
>     _names = "x", "y"
>     _format = "ii"     # specified in the way the struct-module uses
>
> and use in this way:
>
> p = POINT(10, 20)
> p.x # would return 10
> p.x = 100
> p._getaddr() # would return the address of the memory block containing
>              # a struct POINT.

I think we're in danger of over-specifying the problem here <wink>.

> POINT.size_in_bytes
>   or
> POINT.size_in_bytes() # would return the same as the C code
> sizeof(struct POINT)
>
> I would like to retrieve the size_in_bytes attribute _before_
> the first instance of POINT is created, so I cannot calculate
> this in the first __init__() call, a magic class method,
> automatically called just after the class creation, would come
> very handy.

That's reasonable enough -- but you know there are many ways to accomplish
this already, right?  I'm afraid I greatly *prefer* an explicit call to some
sort of do_magic_stuff_to_class(POINT) after the class definition, to make it
clear that you're playing unexpected games with the class definition (e.g.,
there is nothing in the body of POINT to suggest to anyone other than the
original author-- and even then only right after writing it --that instances
will grow .x and .y attributes out of thin air; and I don't care if you have
to write an extra line of code if in return readers get a *clue* that dynamic
trickery may be afoot).

In my experience, there are three kinds of metaclass users in Python:  those
who blissfully ignore the possibilities; those who endured the metaclass
essay to the end, tried it once or twice, shrugged their shoulders and moved
on; and those who lived to regret taking it seriously.  It makes code a
godawful obscure mess, and so even the relatively few people who understand
it steer clear of it whenever possible (for example, the Python-level hook
has been in since 1.5a3, and it *still* hasn't found a use in the std
library).

I understand that you're not after something as encompassing as the metaclass
hook, but if what you want *can* be spelled with an explicit call, I'm
inclined to let it rest there.

import struct

def do_magic_stuff(c):
    c.size_in_bytes = struct.calcsize(c._format)

class Structure:
    def __init__(self, *args):
        if len(self._names) != len(args):
            raise TypeError("wrong # of args")
        self.__set_attrs_from_values(args)

    def __set_attrs_from_values(self, values):
        i = 0
        while i < len(values):
            setattr(self, self._names[i], values[i])
            i += 1

    def pack(self):
        values = [getattr(self, attr) for attr in self._names]
        return struct.pack(self._format, *values)

    def unpack(self, blob):
        values = struct.unpack(self._format, blob)
        self.__set_attrs_from_values(values)

class POINT(Structure):
    _names = "x", "y"
    _format = "ii"
do_magic_stuff(POINT)

After that,

>>> POINT.size_in_bytes
8
>>> p = POINT(10, 20)
>>> p.x
10
>>> p.y
20
>>> p.pack()
'\n\x00\x00\x00\x14\x00\x00\x00'
>>> p.unpack('\n\x00\x00\x00\x34\x00\x00\x00')
>>> p.x
10
>>> p.y
52
>>>

What does that look like in *your* ideal world?  I doubt it will be
substantially simpler, but suspect it will be even more obscure.





More information about the Python-list mailing list