Issue
I want to create a class property with a decorator that accepts an optional argument. Normally I would write
def MyProperty(func, optional=None):
def getter():
"""magic goes here"""
return func() if not optional else optional(func())
return property(getter)
class MyClass(object):
@MyProperty
def myFunction(foo):
return foo
MyClass().myFunction(5.)
>>> 5.0
This is all fine, but when I now also pass a function along the decorator like this:
class MyClass(object):
@MyProperty(int)
def myFunction(foo):
return foo
and I now call
MyClass().myFunction(5)
>>> TypeError: 'property' object is not callable
while I expect to get int(5)
as result.
Solution
When you write
@MyProperty(int)
def myFunction(foo)
...
what that means is that MyProperty(int)
is called, and whatever that returns is then called with myFunction
as an argument. So MyProperty
should be a function that returns a function that accepts a function and returns a function.
So you could write your decorator something like this:
def MyProperty(optional=None):
def decorator(func):
def getter(*args, **kwargs):
"""unspecified magic goes here"""
return func(*args, **kwargs) if not optional else optional(func(*args, **kwargs))
return getter
return decorator
So MyProperty(int)
returns a function (decorator
), and decorator
returns whatever you are decorating.
However, when you call it without an argument, you'd still need to call it @MyProperty()
instead of @MyProperty
, otherwise you miss a stage of unwrapping.
>>> class MyClass:
... @MyProperty()
... def f1(foo):
... return foo
... @MyProperty(int)
... def f2(foo):
... return foo
...
>>> MyClass.f1(1.5)
1.5
>>> MyClass.f2(1.5)
1
I'm not sure about your use of property
. Both your functions in the example are just functions inside a class. They don't have a self
argument or a cls
argument, and you're calling them from the class itself, not from an instance. It's somewhat unclear what you were aiming for.
When I tried this in Python 2 I had to declare the functions as static methods for this to work.
>>> class MyClass(object):
... @staticmethod
... @MyProperty()
... def f1(foo):
... return foo
... @staticmethod
... @MyProperty(int)
... def f2(foo):
... return foo
...
>>> MyClass.f1(0.5)
0.5
>>> MyClass.f2(1.5)
1
Answered By - khelwood
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.