Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decorator "object is not callable"

I'm trying to get to grips with decorators in Python and trying to implement a version of the CachedProperty decorator from the botocore library, but keep hitting an error:

TypeError: 'CachedProperty' object is not callable.

I've been Googling this for a while today but the examples I have found don't seem to be a direct equivalent of my issue. They mostly relate to people trying to call objects like int and failing.

When I step through the code the decorator calls __init__ in CachedProperty ok when I import sum_args(), but throws an error when I call the function itself from the unit test.

My unit test:

import unittest

from decorators.caching_example import sum_args

class TestCachedProperty(unittest.TestCase):

    def test_sum_integers(self):
        data = [1, 2, 3]
        result = sum_args(data)
        self.assertEqual(result, 6)

The function I'm trying to decorate:

from decorators.caching_property import CachedProperty

@CachedProperty
def sum_args(arg):
    total = 0
    for val in arg:
        total += val
    return total

The CachedProperty class I've lifted from botocore:

class CachedProperty(object):
    """A read only property that caches the initially computed value.

    This descriptor will only call the provided ``fget`` function once.
    Subsequent access to this property will return the cached value.

    """

    def __init__(self, fget):
        self._fget = fget

    def __get__(self, obj, cls):
        if obj is None:
            return self
        else:
            computed_value = self._fget(obj)
            obj.__dict__[self._fget.__name__] = computed_value
            return computed_value

Looking at the program I originally swiped this from, I was expecting it to pass the sum function to the CachedProperty class – creating an instance of it as it goes – and the instance to store the result in its internal instance variable self._fget.

What I'm actually getting is:

Error
Traceback (most recent call last):
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 59, in testPartExecutor
    yield
  File "/usr/local/Cellar/python/3.7.3/Frameworks/Python.framework/Versions/3.7/lib/python3.7/unittest/case.py", line 615, in run
    testMethod()
  File "/Users/bradley.atkins/PycharmProjects/brad/examples/tests/decorators/test_property_cache.py", line 11, in test_sum_integers
    result = sum_args(data)
TypeError: 'CachedProperty' object is not callable
like image 920
Kaliklipper Avatar asked Dec 15 '25 14:12

Kaliklipper


1 Answers

Your sum_args is evaluated as a CachedProperty, which does not implement any __call__ method, making it non-callable. That's why python throws this error when you try to call it with sum_args(data)

Try to change your code to:

class CachedProperty(object):

    def __init__(self, fget):
        self._fget = fget

    def __call__(self, obj):
        if obj is None:
            return obj
        else:
            computed_value = self._fget(obj)
            self.__dict__[self._fget.__name__] = computed_value
            return computed_value

@CachedProperty
def sum_args(arg):
    total = 0
    for val in arg:
        total += val
    return total

data = [1, 2, 3]
result = sum_args(data)
print(result) # >> 6
like image 53
olinox14 Avatar answered Dec 18 '25 22:12

olinox14



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!