S.B
S.B

Reputation: 16526

How does property decorator work internally using syntactic sugar(@) in python?

I know that my question seems to be very similar to others. but it's not actually, I've searched a lot and couldn't find my answer.

As we know:

@mydecorator
def myfn():
    pass

is (exactly?) translated to :

def myfn():
    pass
myfn = mydecorator(myfn)

consider the following class:

class C:
def __init__(self, language):
    self._language = language

@property
def language(self):
    return self._language

@language.setter
def language(self, value):
    self._language = value

if we want to translate these to the function + assignment statement, for the getter there is no problem:

def language(self):
    return self._language
language = property(language)

but what about setter? :

def language(self, value):
    self._language = value
language = language.setter(language)

I did exactly what I had done before but that's not going to work. after the previous stage(getter), label 'language' refered to the property object. now it's reassigned to a function(function comes first)! so this language.setter isn't going to work it's not a property anymore.

I thought maybe there is an extra step when we use @ syntax. if it is, what is that? and can we say they are roughly similar to each other.

if it's not, for example when we use decorator with property objects they behave a bit more than just translation into function + assignment statement ?

Upvotes: 6

Views: 526

Answers (1)

Thierry Lathuille
Thierry Lathuille

Reputation: 24242

The difference is exactly where you asked yourself if it was (exactly?) the same.

PEP 318 mentions it rapidly:

Current Syntax

The current syntax for function decorators as implemented in Python 2.4a2 is:

@dec2
@dec1
def func(arg1, arg2, ...):
    pass

This is equivalent to:

def func(arg1, arg2, ...):
    pass
func = dec2(dec1(func))

without the intermediate assignment to the variable func. (emphasis mine)

So, that's why everything works fine when you use the @decorator syntax.

You could make it work by using a different name:

class C:
    def __init__(self, language):
        self._language = language

    
    def language(self):
        return self._language
    language = property(language)
    
    
    def dummy_temporary_name(self, value):
        self._language = value
    language = language.setter(dummy_temporary_name)
    
    
c = C('fr')
print(c.language)
c.language = 'de'
print(c.language)

# fr
# de

Upvotes: 2

Related Questions