Reputation: 68
I'm having some difficulty with Python decorators, and I think it has to do with the fact I am passing a class as a parameter to a function decorator, when the function being decorated is a method of the class being passed.
I have no clearer explanation of the problem than that, so hopefully some code will help:
from typeChecking import *
class Vector:
@accepts(Vector, float, float, float) #Vector hasn't been defined yet... In c++ I could forward declare...
def __init__(self, x, y, z):
self._x = float(x)
self._y = float(y)
self._z = float(z)
...
I don't think the definition of @accepts
is important, but I'll leave it here just in case:
def accepts(*types):
def check_accepts(f):
assert len(types) == f.func_code.co_argcount
def new_f(*args, **kwds):
for (a, t) in zip(args, types):
assert isinstance(a, t), \
"arg %r does not match %s" % (a,t)
return f(*args, **kwds)
new_f.func_name = f.func_name
return new_f
return check_accepts
I get the following error:
File "raytracerBase.py", line 41, in <module>
class Vector:
File "raytracerBase.py", line 42, in Vector
@accepts(Vector, float, float, float)
NameError: name 'Vector' is not defined
I think my comment explains what I think is happening: The class hasn't been defined yet (because, I'm in the process of defining it) and therefore I can't pass it.
Is there a neat workaround that isn't:
assert isinstance(self, Vector), "Something is wrong... very wrong..."
I am aware I'm type checking more than is deemed necessary, but I would like to know how to solve this sort of problem anyway.
Edit: I'm also aware that @accepts
isn't actually valid Python. But, It's the outline of the code I intend to implement.
Upvotes: 4
Views: 237
Reputation: 59168
The short answer is No, you can't refer to your class like that before you've finished defining it.
Type-checking is a subject under active discussion among the Python development team at the moment, and to the extent that there's a consensus, it's that function annotations are the way forward: PEP 484 describes the direction Guido wants to take in implementing it.
The workaround for forward references proposed in that PEP is to just use a string instead:
When a type hint contains names that have not been defined yet, that definition may be expressed as a string, to be resolved later. For example, instead of writing:
def notify_by_email(employees: Set[Employee]): ...
one might write:
def notify_by_email(employees: 'Set[Employee]'): ...
Upvotes: 5