[Tutor] Tutor Digest, Vol 104, Issue 60

eryksun eryksun at gmail.com
Tue Oct 16 12:45:30 CEST 2012


On Tue, Oct 16, 2012 at 3:53 AM, Osemeka Osuagwu <abasiemeka at gmail.com> wrote:
> On Sun, 14 Oct 2012 16:21:38 +0100 Alan Gauld wrote:
>
> Just to clarify, if I went with the top level function; then I guess
> I'll define a 'name' attribute for each individual grid and then pass
> that name in place of the 'grid' argument in your example. Is this
> correct?

No, you'd just pass a grid object, but you probably want an instance
method, anyway. Perhaps some background can clarify.

Here's a function and a class that have no relation:

    >>> def f(grid): pass
    >>> class Test(object): pass

The __get__ method-wrapper of the function can bind it as a method of
a Test object:

    >>> f.__get__(Test(), Test)
    <bound method Test.f of <__main__.Test object at 0x96d5d6c>>

If f is accessed as an attribute of Test, it behaves the same as above:

    >>> Test.f = f
    >>> Test().f
    <bound method Test.f of <__main__.Test object at 0x96d5d8c>>

The first argument of a function, when the function is intended to be
a method, is conventionally called "self". The bound method created by
__get__ automatically supplies this argument for you. If you instead
make the function global (module level), it's best to use a name that
suggests the kind of object you expect as the first argument (e.g.
grid). But really, if it expects to work on a particular grid, you
should make it a method of Grid.

Other kinds of methods:

If the instance is None, __get__ returns an unbound method:

    >>> f.__get__(None, Test)
    <unbound method Test.f>

A classmethod binds to the class instead of an instance:

    >>> classmethod(f).__get__(None, Test)
    <bound method type.f of <class '__main__.Test'>>

    >>> classmethod(f).__get__(Test(), Test)
    <bound method type.f of <class '__main__.Test'>>

When a function is intended to be a classmethod, it's common to name
the first argument "cls".

Finally, a staticmethod has no binding at all. Its __get__
method-wrapper simply returns the wrapped function:

    >>> staticmethod(f).__get__(None, Test)
    <function f at 0x96daae4>

    >>> staticmethod(f).__get__(Test(), Test)
    <function f at 0x96daae4>

There's not much use for this.

Refer to the Descriptor HowTo Guide for more details:

http://docs.python.org/howto/descriptor.html


> I don't quite get this one; I intended state to be just the value of
> the particular cell in the concerned instance. I don't think it gets
> shared by all the grids. The edit method was meant as a way of seeding
> the initial cell configuration, so it just writes whatever it is
> passed in the 'state' arg over that cell location; then again, I'm
> probably missing something here...

Grid.__array is used throughout the class definition. This is a class
attribute. Instances will not get their own copy. Instead, create the
list of lists in Grid.__init__:

        def __init__(self, rows=26, cols=26):
            '''Create a rows x cols grid'''
            self._array = [[''] * cols for i in range(rows)]
            print 'A %d x %d cell World has been Created' % (rows, cols)

Note that this uses a list comprehension to create each row as a
unique list. If instead it multiplied a list literal by a number, each
row would be the *same* list. For example:

    >>> rows = [[''] * 2] * 2
    >>> rows[0][0] = '##'
    >>> rows
    [['##', ''], ['##', '']]

Also note that it uses _array with a single leading underscore. This
is the convention for 'private' data or methods. It signals to other
developers that this is not part of the public API. Using a leading
double underscore causes the compiler to use name mangling in order to
prevent a subclass from easily overriding an attribute; it's used
infrequently.

Here's how the edit_cell method changes now that _array is instance data:

        def edit_cell(self, cells, state='##'):
            '''cells is a list of tuples containing coordinates of
            the cells to edit
            '''
            for row, col in cells:
                self._array[row][col] = state
            return


More information about the Tutor mailing list