Object default value

A

ago

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()
print myobj #-> 1
print myobj.y #-> 2
x=myobj
print x #-> 1
print type(x) #int

Those are my half-working solutions so far:

1) using __get__ descriptor within the class,

def __get__(self,parent,parenttype): return self.x

then

print myobj #works
print myobj.y #does not work! equivalent to: print 1.y

2) Use a __call__ method without a __get__ descriptor.

def __call__(self): return self.x

then:

print myobj() #works, but not the same as: print myobj
print myobj.y #works
 
L

Larry Bates

The prints can be done by defining an __str__ method on the
class, but I don't think you will get the type(obj) to work
the way you want.

class obj(object):
__default=1
y=2

def __str__(self):
return str(self.__default)

myobj=obj()
print "myobj=", myobj
print "myobj.y=", myobj.y
 
A

ago

The print statement was only for illustrative purposes, when calling
varx=myobj I need to receive obj.x as opposed to the instance of obj,
but I also need to call vary=myobj.y. Something like that exists for
com objects/VB, for instance an excel range object uses value as the
default attribute, so that you can write

set rng=range(...);
x=rng
y=rng.value
'x==y
z=rng.attributeXYZ
 
J

James Stroud

I think you want to overload the assignment operator here. I'm not sure that
is allowed in python (I've never seen it done). You can overload the
equality, lt, gt, le, ge operators (==, <, ...) such that

class Thing:
x = 5
def __str__(self):
return str(self.x)
def __eq__(self, other):
if hasattr(other, 'x'):
return self.x == other.x
else:
return self.x == other

py> athing = Thing()
py> athing.x
5
py> bob = athing.x
py> athing == bob # having overlaoded equality for athing
True
py> athing is bob # not the same object
False

But I don't think assignment overloading is allowed in python:

py> athing = Thing()
py> print athing # having overloaded __str__()
5
py> bob = athing
py> type(bob) # will not be an int ==> python language constraint
<type 'instance'>

James

The print statement was only for illustrative purposes, when calling
varx=myobj I need to receive obj.x as opposed to the instance of obj,
but I also need to call vary=myobj.y. Something like that exists for
com objects/VB, for instance an excel range object uses value as the
default attribute, so that you can write

set rng=range(...);
x=rng
y=rng.value
'x==y
z=rng.attributeXYZ

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
J

James Stroud

See this recent clpy thread:

http://www.thescripts.com/forum/thread19253.html

The print statement was only for illustrative purposes, when calling
varx=myobj I need to receive obj.x as opposed to the instance of obj,
but I also need to call vary=myobj.y. Something like that exists for
com objects/VB, for instance an excel range object uses value as the
default attribute, so that you can write

set rng=range(...);
x=rng
y=rng.value
'x==y
z=rng.attributeXYZ

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
P

Paul McGuire

I think you want to overload the assignment operator here. I'm not sure
that
is allowed in python (I've never seen it done).

You can't because assignment is not an operator in Python.

Is it safe to assume that the OP's next question will be how to invoke
functions without the ()'s? To save you the trouble, then answer is 'no'.

Python is simple, VB is simple, but Python is not VB.

-- Paul
 
D

Diez B. Roggisch

ago said:
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)

You're descriptions aren't very clear. Maybe you can put that in a
greater context - what do you want to achieve?

And the assignment-operator isn't overloadable - that is for sure!

Diez
 
A

ago

I am trying to write a generic DataAttribute class in order to simplify
access to object attributes and attached attribute-metadata for end
users with little programming experience.

Requirement 1: accessing the "default" value should be easy (using
assignment operator, via descriptors like __get__ and __set__).

Requirement 2: access to the attribute-metadata should also be as
intuitive as possible.

Requirement 3: possibly the DataAttribute should also be callable, to
return for instance, an history of its values.

class DataAttribute(object):
value=1 #default
old=2
....

class Obj(object): attr=DataAttribute()

#From end user prospective, ideally:
obj=Obj()
x = obj.attr #x=1
xold = obj.attr.old #xold=2
obj.attr = 3 #obj.attr.value=3
xold = obj.attr.old #xold=1
xhistory = obj.attr(startdate, enddate) #xhistory = [[date1,
4],[date2,5],[date3,6]]
xtimestmap = x.attr.timestamp
print obj.attr == obj.attr.value #True

If I use __get__ then I cannot access the metadata.

I could create a separate Obj attribute for each metadata item, but
then I would litter the Obj namespace (typical object will have several
attributes each with lots of metadata) and potentially create name
conflicts. Not to mention that DataAttributes should be
attached/deleted on the fly and if each attribute becames a set of
attributes this operation is complex (metclasses?).

If I use __call__ + __set__ but then I am introducing an asymmetry:

x = obj.attr()
obj.attr = 2

I could use getters and setters but that is not really convenient nor
intuitive
 
A

ago

Is it safe to assume that the OP's next question will be how to invoke
functions without the ()'s? To save you the trouble, then answer is
'no'.

You probably nailed it, thanks for the answer. I suspected that was the
case. I think I'll use __call__ + __set__
 
A

ago

In fact even IF I could get a default value to work as mentioned, then
I would be creating potential name conflicts between the
DataAttribute.DefaultValue and the other metadata. I.e. when calling
obj.attr.x I could refer to DataAttribute.x or DataAttribute.value.x.
It's a no go.
 
S

Scott David Daniels

James said:
I think you want to overload the assignment operator here. I'm not sure that
is allowed in python (I've never seen it done)....
But I don't think assignment overloading is allowed in python:

Exactly correct. Assignment is an operation on a namespace using a new
value, and does not involve the former value. Something similar to
assignment overloading is possible with properties, but you need to be
using object attributes, not names in a module (or function locals).

class SomeDemo(object):
def _read_foo(self):
print 'Reading foo'
return self._foo

def _write_foo(self, value):
print 'Writing foo as %r' % value
return self._foo

def _del_foo(self):
print 'Deleting foo'
del self._foo

foo = property(_read_foo, _write_foo, _del_foo)

obj = SomeDemo()
obj.foo = 123
obj.foo += 1
del obj.foo

--Scott David Daniels
(e-mail address removed)
 
F

Fredrik Lundh

ago said:
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)

No.

You can overload certain methods to make an object behave like one
of its attributes in certain contexts (e.g. comparisions, math operations,
conversions), but you cannot do it for all operations.

Especially not the "assignment operator", since there is no such thing in
Python. (assignment is a statement, and it's an operation on the target
namespace, not the source object).

(As always, Python works better if you use it to write Python programs)

</F>
 
J

James Stroud

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)

I was thinking about this last night and it seemed an interesting problem. I
thought you might want to change the way you look at it, using the python
equivalent to type casting (maybe its called "coercing", sorry for my poor
command of python vocabulary). I have overridden __int__ and __float__ for
this example. You might want to look into __coerce__. This should have the
behavior you desire while having the explicit syntax expected of good python
code.

Inheriting from list allows you to use a stack-like behavior you described in
a previous email. You can further modify __getattribute__, __setattribute__,
__delattribute__, etc. Overriding __iter__ gives you the history in "correct"
order, but may begin to embark on a non-intuitive interface--you be the
judge. I think this is about as close as you can get in python to what you
are thinking (don't know the oldest python version this is backwards
compatible with):


py> class Thing(list):
.... def __init__(self, start_value):
.... list.__init__(self)
.... self.append(start_value)
.... def __setattr__(self, anattr, aval):
.... if (anattr == 'top'):
.... self.append(aval)
.... else:
.... list.__setattr__(self, anattr, aval)
.... def __getattr__(self, anattr):
.... if (anattr == 'top'):
.... return self[-1]
.... elif (anattr == 'old'):
.... try:
.... return self[-2]
.... except IndexError:
.... raise NameError, "No old value yet"
.... else:
.... list.__getattr__(self, anattr)
.... def __iter__(self):
.... return list.__iter__(self[::-1])
.... def __int__(self):
.... return int(self.top)
.... def __float__(self):
.... return float(self.top)
.... def __str__(self):
.... return str(self.top)
....
py> athing = Thing(5) # should init with a reasonable value
py> athing.top # __getattr__
5
py> int(athing) # __int__
5
py> print athing # __str__
5
py> float(athing) # __float__
5.0
py> athing.top = 4 # __setattr__
py> print athing
4
py> athing.old # __getattr__
5
py> athing.top = 42 # __setattr__
py> [x for x in athing] # __iter__
[42, 4, 5]
py> y = float(athing) # closest you can get to assignment overloading
py> print y # y is a float
42.0
py> athing # Thing inherits from list, so you get list.__repr__() here
[5, 4, 42]



Here it is without the prompts:

class Thing(list):
def __init__(self, start_value):
list.__init__(self)
self.append(start_value)
def __setattr__(self, anattr, aval):
if (anattr == 'top'):
self.append(aval)
else:
list.__setattr__(self, anattr, aval)
def __getattr__(self, anattr):
if (anattr == 'top'):
return self[-1]
elif (anattr == 'old'):
try:
return self[-2]
except IndexError:
raise NameError, "No old value yet"
else:
list.__getattr__(self, anattr)
def __iter__(self):
return list.__iter__(self[::-1])
def __int__(self):
return int(self.top)
def __float__(self):
return float(self.top)
def __str__(self):
return str(self.top)

--
James Stroud
UCLA-DOE Institute for Genomics and Proteomics
Box 951570
Los Angeles, CA 90095

http://www.jamesstroud.com/
 
B

Bengt Richter

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:
... 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 ;-)
... 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
 
R

Reinhold Birkenfeld

ago said:
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)

Python is not Visual Basic.

In Visual Basic, objects could have a default property which was set when
the object variable was assigned to, but that was only possible because
object variables had to be set with "Set", not "Let".

Reinhold
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,264
Messages
2,571,323
Members
48,005
Latest member
ChasityFan

Latest Threads

Top