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