Object default value

Bengt Richter bokr at oz.net
Thu Sep 22 04:33:02 EDT 2005


On 20 Sep 2005 12:31:19 -0700, "ago" <agostino.russo at gmail.com> wrote:

>Is it possible to have a default value associated python objects? I.e.
>to flag an attribute in such a way that the assignment operator for the
>object returns the default attribute instead of the object itself, but
>calls to other object attributes are properly resolved? (I don't think
>so, but I am not sure)
>
>Example:
>
>class obj(object):
> x=1 #assume x is somehow made into a default value
> y=2
>
>Ideally this should be the result:
>
>myobj=obj()
normal

>print myobj #-> 1
expression myobj interpreted as myobj.x?

>print myobj.y #-> 2
normal

>x=myobj
normal, because expression myobj in this context of immediate assignment does not mean myobj.x?

>print x #-> 1
expression x is the same as expression myobj, which is intrpreted as myobj.x (alias x.x) if not assigned?

>print type(x) #int
ditto

>
If you wanted to have this effect inside a function, you could write a byte-code-munging
decorator to evaluate selected_name as selected_name.selected_attr except where
assigning to an alias name is all that a statement does, as in x = myobj.

But what if you actually wanted to pass the object per se somewhere, or return it from
a function? Maybe you could have the expression myobj.x mean the normal myobj, and vice
versa in a kind of terrible symmetry ;-)

Then usage might be something like
@agostino_effect(myobj='x') # eval myobj as myobj.x
def foo():
    myobj=obj()
    print myobj #-> 1
    print myobj.y #-> 2
    x = myobj
    print x #-> 1
    return x, myobj, x.y, myobj.x # with .x having "symmetrically-other" effect ;-)

    xval, myobjval, x_dot_y_val, myobj_per_se = foo() # assignment from function is not interfered with
    myobj_per_se.y #->2
    myobj_per_se #-> 1
    myobj_val.y -> AttributeError: 'int' object has no attribute 'y'

I'm not suggesting this is a good way to go forward, I am just playing with the feasibility of
doing what you want, even if it's not good for you ;-) I suspect there is a better way, but
it wouldn't be that hard to do the above, as you can see from the code of foo
that the agostino_effect decorator would be modifying:

 >>> def foo():
 ...     myobj=obj()
 ...     print myobj #-> 1
 ...     print myobj.y #-> 2
 ...     x = myobj
 ...     print x #-> 1
 ...     return x, myobj, x.y, myobj.x # with .x having "symmetrically-other" effect ;-)
 ...
 >>> import dis
 >>> dis.dis(foo)
   2           0 LOAD_GLOBAL              0 (obj)
               3 CALL_FUNCTION            0
               6 STORE_FAST               0 (myobj)

   3           9 LOAD_FAST                0 (myobj)
Here you'd notice that the next instruction was not STORE_FAST
so you'd insert a
                 LOAD_ATTR                1 (x)
similar to the .y access below

              12 PRINT_ITEM
              13 PRINT_NEWLINE

   4          14 LOAD_FAST                0 (myobj)
              17 LOAD_ATTR                2 (y)
Here you'd notice the above wasn't LOAD_ATTR (x) (which you'd otherwise have to remove for object-per-se)

              20 PRINT_ITEM
              21 PRINT_NEWLINE

   5          22 LOAD_FAST                0 (myobj)
              25 STORE_FAST               1 (x)
This you notice is an immediate assignment and you leave it alone, and note the alias

   6          28 LOAD_FAST                1 (x)
Here you notice the alias and insert
                 LOAD_ATTR                1 (x)
as before with myobj

              31 PRINT_ITEM
              32 PRINT_NEWLINE

   7          33 LOAD_FAST                1 (x)
insert
                 LOAD_ATTR                1 (x)
again
              36 LOAD_FAST                0 (myobj)
insert
                 LOAD_ATTR                1 (x)
again
              39 LOAD_FAST                1 (x)
              42 LOAD_ATTR                2 (y)
other attribute, no change to above byte code
              45 LOAD_FAST                0 (myobj)
              48 LOAD_ATTR                3 (x)
anti-attribute, remove above byte code
              51 BUILD_TUPLE              4
              54 RETURN_VALUE

You might want to do the same for LOAD_GLOBAL/STORE_GLOBAL, and
STORE_DEREF/LOAD_DEREF, I don't know. But it wouldn't be a big deal
to get a hack working. Thorough testing is another matter,
not to mention justifying it ;-)

Regards,
Bengt Richter



More information about the Python-list mailing list