how to add property "dynamically"?

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

    how to add property "dynamically"?

    hello,

    i need to add properties to instances dynamically during run time.
    this is because their names are determined by the database contents.
    so far i found a way to add methods on demand:

    class A(object) :
    def __getattr__(sel f, name) :
    if name == 'test' :
    def f() : return 'test'
    setattr(self, name, f)
    return f
    else :
    raise AttributeError( "'%s' object has no attribute '%s'" %
    (self.__class__ .__name__, name))

    this seems to work and i can invoke method test() on an object. it
    would be nice to have it as property though. so i tried:

    class A(object) :
    def __getattr__(sel f, name) :
    if name == 'test' :
    def f() : return 'test'
    setattr(self, name, property(f))
    return f
    else :
    raise AttributeError( "'%s' object has no attribute '%s'" %
    (self.__class__ .__name__, name))

    but this does not work, instance.test returns a callable but does not
    call it.

    i am not an expert in python, would someone please tell me what i am
    doing wrong?

    thanks
    konstantin
  • Christian Heimes

    #2
    Re: how to add property "dynamical ly"?

    akonsu wrote:
    i am not an expert in python, would someone please tell me what i am
    doing wrong?
    You can't add properties to an instance. They must be specified on the
    type (aka new style class). Descriptors and magic methods are only
    looked up on classes for various reasons - mostly performance reasons.
    Old style classes behave differently but properties don't work with old
    style classes.

    You can archive the same behavior by hooking into __getattr__,
    __setattr__ and __delattr__. Mind the speed penelty, though!

    Christian

    Comment

    • Larry Bates

      #3
      Re: how to add property "dynamical ly"?

      akonsu wrote:
      hello,
      >
      i need to add properties to instances dynamically during run time.
      this is because their names are determined by the database contents.
      so far i found a way to add methods on demand:
      >
      class A(object) :
      def __getattr__(sel f, name) :
      if name == 'test' :
      def f() : return 'test'
      setattr(self, name, f)
      return f
      else :
      raise AttributeError( "'%s' object has no attribute '%s'" %
      (self.__class__ .__name__, name))
      >
      this seems to work and i can invoke method test() on an object. it
      would be nice to have it as property though. so i tried:
      >
      class A(object) :
      def __getattr__(sel f, name) :
      if name == 'test' :
      def f() : return 'test'
      setattr(self, name, property(f))
      return f
      else :
      raise AttributeError( "'%s' object has no attribute '%s'" %
      (self.__class__ .__name__, name))
      >
      but this does not work, instance.test returns a callable but does not
      call it.
      >
      i am not an expert in python, would someone please tell me what i am
      doing wrong?
      >
      thanks
      konstantin
      Are you sure you can't get by by adding attributes to the instance that hold the
      values that the property would return?

      class A(object):
      def __init__(self, dbvaluedict):
      self.__dict__.u pdate(dbvaluedi ct)

      >>dbvaluedict = dict('test': 'test')
      >>a = A(dbvaluedict)
      >>print a.test
      test

      If this doesn't help. You might want to start at the beginning and explain what
      it is you are trying to accomplish. What you are trying to do is very unusual.

      -Larry

      Comment

      • Rafe

        #4
        Re: how to add property "dynamical ly"?

        On Aug 17, 5:09 pm, Bruno Desthuilliers
        <bdesth.quelque ch...@free.quel quepart.frwrote :
        akonsu a écrit :hello,
        >
        i need to add properties to instances dynamically during run time.
        this is because their names are determined by the database contents.
        so far i found a way to add methods on demand:
        >
        class A(object) :
        def __getattr__(sel f, name) :
        if name == 'test' :
        def f() : return 'test'
        setattr(self, name, f)
        return f
        else :
        raise AttributeError( "'%s' object has no attribute '%s'" %
        (self.__class__ .__name__, name))
        >
        this seems to work and i can invoke method test() on an object.
        >
        Nope. This adds per-instance *function* attributes - not *methods*.
        >
        class A(object) :
        def __getattr__(sel f, name) :
        if name == 'test' :
        def f(self) :
        return "%s.test" % self
        setattr(self, name, f)
        return f
        else :
        raise AttributeError(
        "'%s' object has no attribute '%s'" \
        % (self.__class__ .__name__, name)
        )
        >
        a = A()
        a.test()
        =Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        TypeError: f() takes exactly 1 argument (0 given)
        >
        To add methods on a per-instance basis, you have to manually invoke the
        descriptor protocol's implementation of function objects:
        >
        class A(object) :
        def __getattr__(sel f, name) :
        if name == 'test' :
        def f(self) :
        return "%s.test" % self
        m = f.__get__(self, type(self))
        setattr(self, name, m)
        return m
        else :
        raise AttributeError(
        "'%s' object has no attribute '%s'" \
        % (self.__class__ .__name__, name)
        )
        >
        it
        would be nice to have it as property though. so i tried:
        >
        class A(object) :
        def __getattr__(sel f, name) :
        if name == 'test' :
        def f() : return 'test'
        setattr(self, name, property(f))
        return f
        else :
        raise AttributeError( "'%s' object has no attribute '%s'" %
        (self.__class__ .__name__, name))
        >
        but this does not work, instance.test returns a callable but does not
        call it.
        >
        Properties must be class attributes. The only way (the only way I know)
        to get them to work as instance-attributes is to overload
        __getattribute_ _, which is tricky and may have pretty bad impact on
        lookup perfs - and ruins the whole point of using properties FWIW.
        >
        i am not an expert in python, would someone please tell me what i am
        doing wrong?
        >
        Wrong solution to your problem, I'd say. Let's start again:
        >
        """
        i need to add properties to instances dynamically during run time.
        this is because their names are determined by the database contents.
        """
        >
        Care to elaborate ? I may be wrong, but I suspect you're trying to roll
        your own python/database mapper. If so, there are quite a couple Python
        ORMs around. Else, please tell us more.
        I posted this to another thread, but...


        You can dynamically add properties (or anything else) to a CLASS just
        before returning the
        instance using __new__():

        class AClass(object):
        def __new__(cls):
        setattr(cls,"pr opName", property(fget = ...,
        fset = ...,
        fdel = ...,
        doc = ...) )

        obj = super(AClass, cls).__new__(cl s)
        return obj


        - Rafe

        Comment

        • Gabriel Genellina

          #5
          Re: how to add property &quot;dynamical ly&quot;?

          En Tue, 19 Aug 2008 15:02:29 -0300, Rafe <rafesacks@gmai l.comescribió:
          On Aug 17, 5:09 pm, Bruno Desthuilliers
          <bdesth.quelque ch...@free.quel quepart.frwrote :
          >akonsu a écrit :hello,
          >>
          i need to add properties to instances dynamically during run time.
          >>
          >Properties must be class attributes. The only way (the only way I know)
          >to get them to work as instance-attributes is to overload
          >__getattribute __, which is tricky and may have pretty bad impact on
          >lookup perfs - and ruins the whole point of using properties FWIW.
          >
          You can dynamically add properties (or anything else) to a CLASS just
          before returning the
          instance using __new__():
          >
          class AClass(object):
          def __new__(cls):
          setattr(cls,"pr opName", property(fget = ...,
          fset = ...,
          fdel = ...,
          doc = ...) )
          >
          obj = super(AClass, cls).__new__(cl s)
          return obj
          If you modify the class, this makes the property available to all existing
          instances, not just the one being created. Any previous property of the
          same name is overriden too.

          --
          Gabriel Genellina

          Comment

          • Bruno Desthuilliers

            #6
            Re: how to add property &quot;dynamical ly&quot;?

            Rafe a écrit :
            (snip)
            I posted this to another thread, but...
            And I answered there, explaining why it's not a proper solution.



            (snip about using __new__ to add class attributes, cf above link for more)

            Comment

            Working...