One-Shot Property?

Discussion in 'Python' started by Kevin Smith, Jan 18, 2005.

  1. Kevin Smith

    Kevin Smith Guest

    I have many cases in my code where I use a property for calculating a
    value on-demand. Quite a few of these only need to be called once.
    After that the value is always the same. In these properties, I set a
    variable in the instance as a cached value and return that value on
    subsequent calls. It would be nice if there was a descriptor that would
    do this automatically. Actually, what would be really nice is if I
    could replace the property altogether and put the calculated value in
    its place after the first call, but the property itself prevents me from
    doing that. Is this possible?

    --
    Kevin Smith
    Kevin Smith, Jan 18, 2005
    #1
    1. Advertising

  2. Kevin Smith wrote:
    > I have many cases in my code where I use a property for calculating a
    > value on-demand. Quite a few of these only need to be called once.
    > After that the value is always the same. In these properties, I set a
    > variable in the instance as a cached value and return that value on
    > subsequent calls. It would be nice if there was a descriptor that would
    > do this automatically. Actually, what would be really nice is if I
    > could replace the property altogether and put the calculated value in
    > its place after the first call, but the property itself prevents me from
    > doing that. Is this possible?


    I was going to recommend taking a look at the "memoize" example on the
    Python wiki, but it seems to be missing at the moment. In any case,
    here's the URL:

    http://www.python.org/moin/PythonDecoratorLibrary

    There are also a few examples on the Cookbook, like this one:

    http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/325205

    It shouldn't be too difficult to adapt this technique so that it can be
    used to create properties. I wouldn't bother replacing the property with
    an attribute unless you have a specific reason to do so (performance,
    perhaps).

    HTH,
    Dave
    Dave Benjamin, Jan 18, 2005
    #2
    1. Advertising

  3. Kevin Smith wrote:
    > I have many cases in my code where I use a property for calculating a
    > value on-demand. Quite a few of these only need to be called once.
    > After that the value is always the same. In these properties, I set a
    > variable in the instance as a cached value and return that value on
    > subsequent calls. It would be nice if there was a descriptor that would
    > do this automatically. Actually, what would be really nice is if I
    > could replace the property altogether and put the calculated value in
    > its place after the first call, but the property itself prevents me from
    > doing that. Is this possible?


    If you use the old-fashioned __getattr__ method instead of properties.
    __getattr__ gets called only if the value can't be found in the instance
    dictionary.

    def __getattr__ (self, attrname):
    try:
    method = getattr (self, 'calculate_' + attrname)
    except AttributeError:
    raise AttributeError, attrname
    value = method ()
    setattr (self, attrname, value)
    return value

    And probably also through metaclasses. And decorators.

    Daniel
    Daniel Dittmar, Jan 18, 2005
    #3
  4. Kevin Smith

    John Lenton Guest

    On Tue, Jan 18, 2005 at 04:54:56PM +0000, Kevin Smith wrote:
    >
    > I have many cases in my code where I use a property for calculating a
    > value on-demand. Quite a few of these only need to be called once.
    > After that the value is always the same. In these properties, I set a
    > variable in the instance as a cached value and return that value on
    > subsequent calls. It would be nice if there was a descriptor that would
    > do this automatically. Actually, what would be really nice is if I
    > could replace the property altogether and put the calculated value in
    > its place after the first call, but the property itself prevents me from
    > doing that. Is this possible?


    consider this:

    1 >>> class C:
    2 ... x = property(str)
    3 ...
    4 >>> c = C()
    5 >>> c.x
    6 '<__main__.C instance at 0x4008d92c>'
    7 >>> setattr(c, 'x', c.x)
    8 >>> c.x
    9 '<__main__.C instance at 0x4008d92c>'
    10 >>> C.x
    11 <property object at 0x4009a7ac>
    12 >>> c.x = 2
    13 >>>

    in line 5 you see that the x property so defined works. In line 7 you
    remove it, replacing it with the computed value of the property. Line
    9 shows that it worked, line 11 shows that it didn't break the class,
    and line 13 (through the absence of an exception) shows that it no
    longer is 'special' (as it shouldn't be).

    --
    John Lenton () -- Random fortune:
    You can tune a piano, but you can't tuna fish.

    You can tune a filesystem, but you can't tuna fish.
    -- from the tunefs(8) man page

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.5 (GNU/Linux)

    iD8DBQFB7VZmgPqu395ykGsRApG8AKCWsaaRwbKN8gWCQw2E1gXryWCpZACgrbHz
    CjrrwkO6QkZ1ziMG6GKXQug=
    =+cST
    -----END PGP SIGNATURE-----
    John Lenton, Jan 18, 2005
    #4
  5. Kevin Smith wrote:
    > I have many cases in my code where I use a property for calculating a
    > value on-demand. Quite a few of these only need to be called once.
    > After that the value is always the same. In these properties, I set a
    > variable in the instance as a cached value and return that value on
    > subsequent calls. It would be nice if there was a descriptor that would
    > do this automatically. Actually, what would be really nice is if I
    > could replace the property altogether and put the calculated value in
    > its place after the first call, but the property itself prevents me from
    > doing that.


    This should do it:

    class CachingProperty(object):
    def __init__(self, attr_name, calculate_function):
    self._name = attr_name
    self._calculate = calculate_function

    def __get__(self, obj, type=None):
    if obj is None:
    return self
    else:
    value = self._calculate(obj)
    setattr(obj, self._name, value)
    return value

    And example code:

    >>> class Foo(object):

    .... def calculate_value(self):
    .... print 'Calculating...'
    .... return 42
    .... foo = CachingProperty('foo', calculate_value)
    ....
    >>> bar = Foo()
    >>> bar.__dict__

    {}
    >>> bar.foo

    Calculating...
    42
    >>> bar.foo # Notice that the print statement doesn't run this time

    42
    >>> bar.__dict__

    {'foo': 42}
    Leif K-Brooks, Jan 18, 2005
    #5
  6. Leif K-Brooks wrote:
    >
    > class CachingProperty(object):
    > def __init__(self, attr_name, calculate_function):
    > self._name = attr_name
    > self._calculate = calculate_function
    > def __get__(self, obj, type=None):
    > if obj is None:
    > return self
    > else:
    > value = self._calculate(obj)
    > setattr(obj, self._name, value)
    > return value
    >
    > And example code:
    > >>> class Foo(object):

    > ... def calculate_value(self):
    > ... print 'Calculating...'
    > ... return 42
    > ... foo = CachingProperty('foo', calculate_value)
    > ...
    > >>> bar = Foo()
    > >>> bar.__dict__

    > {}
    > >>> bar.foo

    > Calculating...
    > 42
    > >>> bar.foo # Notice that the print statement doesn't run this time

    > 42
    > >>> bar.__dict__

    > {'foo': 42}



    To build on this for Python 2.4:

    class Caches(object):
    def __init__(self, calculate_function):
    self._calculate = calculate_function

    def __get__(self, obj, _=None):
    if obj is None:
    return self
    value = self._calculate(obj)
    setattr(obj, self._calculate.func_name, value)
    return value


    class Foo(object):
    @Caches
    def foo(self):
    print 'Calculating...'
    return 42

    --Scott David Daniels
    Scott David Daniels, Jan 18, 2005
    #6
  7. On Tuesday 18 January 2005 12:33 pm, John Lenton wrote:
    >
    > consider this:
    >
    > 1 >>> class C:
    > 2 ... x = property(str)
    > 3 ...
    > 4 >>> c = C()
    > 5 >>> c.x
    > 6 '<__main__.C instance at 0x4008d92c>'
    > 7 >>> setattr(c, 'x', c.x)
    > 8 >>> c.x
    > 9 '<__main__.C instance at 0x4008d92c>'
    > 10 >>> C.x
    > 11 <property object at 0x4009a7ac>
    > 12 >>> c.x = 2
    > 13 >>>
    >
    > in line 5 you see that the x property so defined works. In line 7 you
    > remove it, replacing it with the computed value of the property. Line
    > 9 shows that it worked, line 11 shows that it didn't break the class,
    > and line 13 (through the absence of an exception) shows that it no
    > longer is 'special' (as it shouldn't be).


    It wasn't "special" before, either -- I tried this myself, because I wasn't
    familiar with properties yet, and I was trying to figure out what you
    meant by that.

    The catch is that I think you meant to type:

    > 1 >>> class C(object):


    (i.e. so that C is a "new-style" class).

    Then we get "special" behavior (which answers my first question):

    >>> class C(object):

    .... x = property(str)
    ....
    >>> C.x

    <property object at 0x401e8cd4>
    >>> c = C()
    >>> c.x

    '<__main__.C object at 0x401e984c>'
    >>> c.x = 2

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: can't set attribute
    >>>


    Unfortunately this seems to break your technique, too:

    >>> setattr(c, 'x', c.x)

    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    AttributeError: can't set attribute

    Too bad. I was kind of hoping it was just a typo. :-(

    Unless I'm missing something, anyway.

    Cheers,
    Terry

    --
    --
    Terry Hancock ( hancock at anansispaceworks.com )
    Anansi Spaceworks http://www.anansispaceworks.com
    Terry Hancock, Jan 28, 2005
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Saish

    screen shot of a page in c#

    Saish, May 31, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    4,134
    gabe garza
    Jun 7, 2005
  2. thomas

    one shot process

    thomas, Apr 1, 2004, in forum: VHDL
    Replies:
    1
    Views:
    1,758
    Thomas Stanka
    Apr 5, 2004
  3. Steven Menk

    Reseting on an edge or one-shot

    Steven Menk, Feb 13, 2006, in forum: VHDL
    Replies:
    6
    Views:
    1,660
  4. skipperdodle

    need help, retriggerable one-shot

    skipperdodle, Oct 5, 2007, in forum: VHDL
    Replies:
    1
    Views:
    765
    skipperdodle
    Oct 6, 2007
  5. skipperdodle
    Replies:
    1
    Views:
    665
    skipperdodle
    Oct 17, 2007
Loading...

Share This Page