Decorator for variables?

When I had been studying the documentation for the typing module, I found this:

To mark a function or a class as final we do this:

class Base:
   @final
   def final_method(): ...

@final
class FinalClass: ...

but when we want to mark a variable as final, we do this:

MAX_SIZE: Final = 9000
class Connection:
    TIMEOUT: Final[int] = 10

So, I was wondering: what if we could decorate a variable too?

@final
MAX_SIZE = 9000

class Connection:
     @final
     TIMEOUT: int = 10

There are also other uses for:

class Point2D(TypedDict):
    x: int
    y: int
    @not_required
    label: str

class Point3D(TypedDict, total=False):
    @required
    x: int
    @required
    y: int
    label: str

@annotated(ValueRange(-10, 5))
SliderA: int = 0
@annotated(ValueRange(-20, 3))
SliderB: int = -10

I’m curious about what you think of it. Especially if you have found other use for it outside of the typing module :slight_smile:

1 Like

I had the same though previously. To me it makes sense to be able to annotate a variable.

How would this work at runtime? What would/could the decorator do?

Well, I think if this:

@dec
def fn(): pass

is turned into this:

def fn(): pass
fn = dec(fn)

Then this:

@dec
v = 9

should be turned into this:

v = 9
v = dec(v)

However, after a bit of thought, I’m inclined into this behavior:

@dec
v: int = 9
#same as:
v = 9
v = dec(v, int)

#-------
@dec
x = True
#same as
x = True
x = dec(x, None)

This way it would work with types and my examples in my top post then could do its “magic”

You can already write v = dec(9). The point of decorator syntax is that class and def statements don’t have a clear value for the decorator to be applied to before the statement is processed. Assignment statements do.

I see the final decorator as a fix to the problem that you can’t annotate a function or class name before “assignment”, not something to expand into other use cases. For example, I have an open issue for mypy to accept code like:

foo: Final[Callable[[int], int]]
def foo(x):
   ...

(True, this adds a redundant refernce to foo, but some callable types are complicated enough that it would be nice to capture them in a single alias rather that distributing them among the parameters and return type explicitly.)

7 Likes

You are right, I haven’t well thought out the idea. It was something that came out of my sleeve during reading :frowning:

I think it might have got some use if variables were one of first-class citizens in Python. But I think this is a topic for another post :wink:

Yeah, this couldn’t ever work. The point of names (variables) is that they give a name to an object. If they were objects, then they’d have to be able to have their own names (recursively, even). But x = y already means that x becomes a name for the object y is naming, not for the name y itself.

1 Like

Classes and functions are values in Python. Variables are not values. Decorators are applied to values.

3 Likes