Object default value

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • ago

    #1

    Object default value

    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,pa rent,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

  • Larry Bates

    #2
    Re: Object default value

    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.__defa ult)

    myobj=obj()
    print "myobj=", myobj
    print "myobj.y=", myobj.y
    [color=blue][color=green][color=darkred]
    >>> myobj= 1
    >>> myobj.y= 2[/color][/color][/color]

    ago wrote:[color=blue]
    > 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,pa rent,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
    >[/color]

    Comment

    • ago

      #3
      Re: Object default value

      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.attribute XYZ

      Comment

      • James Stroud

        #4
        Re: Object default value

        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

        On Tuesday 20 September 2005 13:05, ago wrote:[color=blue]
        > 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.attribute XYZ[/color]

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


        Comment

        • James Stroud

          #5
          Re: Object default value

          See this recent clpy thread:



          On Tuesday 20 September 2005 13:05, ago wrote:[color=blue]
          > 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.attribute XYZ[/color]

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


          Comment

          • Paul McGuire

            #6
            Re: Object default value

            > I think you want to overload the assignment operator here. I'm not sure
            that[color=blue]
            > is allowed in python (I've never seen it done).[/color]

            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


            Comment

            • Diez B. Roggisch

              #7
              Re: Object default value

              ago wrote:[color=blue]
              > 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)[/color]

              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

              Comment

              • ago

                #8
                Re: Object default value

                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(o bject):
                value=1 #default
                old=2
                ....

                class Obj(object): attr=DataAttrib ute()

                #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(startd ate, enddate) #xhistory = [[date1,
                4],[date2,5],[date3,6]]
                xtimestmap = x.attr.timestam p
                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

                Comment

                • ago

                  #9
                  Re: Object default value

                  > 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__

                  Comment

                  • ago

                    #10
                    Re: Object default value

                    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.D efaultValue and the other metadata. I.e. when calling
                    obj.attr.x I could refer to DataAttribute.x or DataAttribute.v alue.x.
                    It's a no go.

                    Comment

                    • Scott David Daniels

                      #11
                      Re: Object default value

                      James Stroud wrote:[color=blue]
                      > 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:[/color]

                      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
                      Scott.Daniels@A cm.Org

                      Comment

                      • Fredrik Lundh

                        #12
                        Re: Object default value

                        "ago" <agostino.russo @gmail.com> wrote:
                        [color=blue]
                        > 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)[/color]

                        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>



                        Comment

                        • James Stroud

                          #13
                          Re: Object default value

                          On Tuesday 20 September 2005 12:31, ago wrote:[color=blue]
                          > 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)[/color]

                          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__(s elf)
                          .... self.append(sta rt_value)
                          .... def __setattr__(sel f, anattr, aval):
                          .... if (anattr == 'top'):
                          .... self.append(ava l)
                          .... else:
                          .... list.__setattr_ _(self, anattr, aval)
                          .... def __getattr__(sel f, 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__(s elf[::-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__(s elf)
                          self.append(sta rt_value)
                          def __setattr__(sel f, anattr, aval):
                          if (anattr == 'top'):
                          self.append(ava l)
                          else:
                          list.__setattr_ _(self, anattr, aval)
                          def __getattr__(sel f, 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__(s elf[::-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


                          Comment

                          • Bengt Richter

                            #14
                            Re: Object default value

                            On 20 Sep 2005 12:31:19 -0700, "ago" <agostino.russo @gmail.com> wrote:
                            [color=blue]
                            >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()[/color]
                            normal
                            [color=blue]
                            >print myobj #-> 1[/color]
                            expression myobj interpreted as myobj.x?
                            [color=blue]
                            >print myobj.y #-> 2[/color]
                            normal
                            [color=blue]
                            >x=myobj[/color]
                            normal, because expression myobj in this context of immediate assignment does not mean myobj.x?
                            [color=blue]
                            >print x #-> 1[/color]
                            expression x is the same as expression myobj, which is intrpreted as myobj.x (alias x.x) if not assigned?
                            [color=blue]
                            >print type(x) #int[/color]
                            ditto
                            [color=blue]
                            >[/color]
                            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.s elected_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_effec t(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 "symmetrica lly-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:
                            [color=blue][color=green][color=darkred]
                            >>> def foo():[/color][/color][/color]
                            ... myobj=obj()
                            ... print myobj #-> 1
                            ... print myobj.y #-> 2
                            ... x = myobj
                            ... print x #-> 1
                            ... return x, myobj, x.y, myobj.x # with .x having "symmetrica lly-other" effect ;-)
                            ...[color=blue][color=green][color=darkred]
                            >>> import dis
                            >>> dis.dis(foo)[/color][/color][/color]
                            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

                            Comment

                            • Reinhold Birkenfeld

                              #15
                              Re: Object default value

                              ago wrote:[color=blue]
                              > 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)[/color]

                              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

                              Comment

                              Working...