Addressing the last element of a list

Bengt Richter bokr at oz.net
Tue Nov 15 20:29:30 CET 2005


On Tue, 15 Nov 2005 03:23:11 -0600, Chris Mellon <arkanes at gmail.com> wrote:

>On 11/14/05, Bengt Richter <bokr at oz.net> wrote:
[...]
>> You may be interested in reviewing
>>
>>     http://groups.google.com/group/comp.lang.python/browse_thread/thread/=
>f96b496b6ef14e2/32d3539e928986b3
>>
>> before continuing this topic ;-)
>
>I read that thread, and am glad I did before asking like I was going
>to, if only to avoid being yelled at for not understanding Python
>variables ;)
>
>I understand them, I really do, and I know why they act the way they
>do, but I still wanted a reference type for binding GUI objects to
>data values - for example, a spinner control to an int value. In C++,
>I do it by passing a pointer to an int to the control and letting it
>do its thing. Theres no simple obvious way to do the same thing in
>Python - I ended up by passing a namespace(any object) and an
>attribute (by name) and then setting it via setattr in in the control,
>which is non-obvious and icky.
>
ISTM that there are two main issues involved.
1) Can you code your intentions with some clean syntax?
1a) Is there clean syntax to help you think more fluently?
2) Is the implementation efficient enough for your use case?

(Ok, I couldn't help introducing 1a, because I think that is
where Python shines).

I think 2) can be ignored until we have a good proposal for 1) ;-)

IIUC what you want boils down to wanting to replace a value
via a reference object that you pass to a function, where the value
is known by name in some namespace, and you don't want
to use a (namespace, namestring) tuple as a reference object.

Actually, in general the value could be known by some access expression
that doesn't necessarily end in a name, like a[42]. Our magic ref expression
(let's use function syntax for now for creating the reference) becomes
more tricky. We now also have ref(a[42]) as well as ref(name).

For easy discussion of the concept, let's assume that refobj = ref(expr) works
for some subset of exprs and refobj lets us access the expr target via
refobj.value for assignment or in an expression. Note that the name 'value'
is not the name in ref(name), but is always 'value'. We can discuss later
whether we want syntactic sugar to spell refobj.value as @refobj or maybe
even plain refobj, but let's postpone that until we have agreed functionality
and some ideas on implementation.

So, to summarize, we have

    refobj = ref(expr)

and we can assign to the indirect target and and use it in an expression

    refobj.value = refobj.value + 1

with a fixed syntax that does not identify any of the original expression
(since "value" is an arbitrarily chosen mnemonic and attribute access is
an arbitrarily chosen accessor mechanism for discussion expediency).

For your example of ref(namespace.name) we could use my PNS class [1]
to get a refobj that acts as above, e.g.,

 >>> from pns import PNS
 >>> namespace = type('NS',(),{})() # an object providing attr namespace
 >>> refobj = PNS(namespace, 'name')
 >>> refobj.value = 'should wind up in namespace'
 >>> namespace.name
 'should wind up in namespace'
 >>> refobj.value
 'should wind up in namespace'
 >>>

[1] http://groups.google.com/group/comp.lang.python/msg/54a7ab01906683ca

But how would ref(a[42]) work? By analogy we might have a class PLE (pointer
to list element) and instantiate it by refobj = PLE(a, 42). That would be easy.
One could even imagine a multimethod __init__ for a PXX class that would handle
a number of common ref(expr) situations, if you pass the appropriate pieces of expr
as args. One could imagine automating this in various ways. E.g., treating ref
as a keyword and automatically detecting it in a module's AST and translating
the call to pick apart the passed expression suitably to make a call that
generates the refobj. But this is premature implementation ;-)

Let's get the requirements down first. One thing that pops up immediately
if you think about ref(namespace.name) vs ref(a[42]) is preservation of
the dynamic access semantics whose execution is deferred in time. I.e.,
a dangling pointer problem with additional twists.

If the essential ref infos are (namespace, name) and (a, 42), we must note that
we really implicitly made it
    (namespace, ('__getattr__', '__setattr__', '__delattr__'), name)
and
    (a,         ('__getitem__', '__setitem__', '__delitem__'), 42)

(at least I did in the way I defined PNS, because deferred use of the refobj
to set a value implied doing getattr(namespace, name) at that time.
Accessor methods could also be bound at ref call time, with different semantics
resulting. I.e., we could have ref info stored as

    ((namespace.__getattr__, namespace.__setattr__, namespace.__delattr__), name)
and
    ((a.__getitem__, a.__setitem__, a.__delitem__), 42)

What is the real meaning desired for a refobj ? How should ref(42) be handled?
Should it become a legal refobj that only fails if used as assignment target,
so that it can be passed transparently to read-only users as well as references
to mutables that wind up only being used read-only?

Regards,
Bengt Richter



More information about the Python-list mailing list