A memo about property
In the 2nd system [^ 1].
[^ 1]: In the 3rd series, it is unconditionally judged as a new style, so no trouble occurs even if you write the old style.
I'm writing something that isn't an old-style feature in the old-style, so it's 100% user-friendly.
foo.py
class New(object):
    def __init__(self):
        self._x = 10
    @property
    def x(self):
        return self._x * 2
    @x.setter
    def x(self, v):
        self._x = v
class Old():
    def __init__(self):
        self._x = 10
    @property
    def x(self):
        return self._x * 2
    @x.setter
    def x(self, v):
        self._x = v
if __name__ == '__main__':
    n = New()
    n.x = 10
    print ( n.x )
    o = Old()
    o.x = 10
    print ( o.x )
Both New and ʻOld are exactly the same except for the line of the class` declaration.
python
$ python foo.py
20
10
I researched various things [^ 2], but ↓ is the most intuitive
[^ 2]: Is there a Python version of Data :: Dumper or is there a B :: Deparse?
Change after main
if __name__ == '__main__':
    n = New()
    print (vars(n))
    n.x = 2
    print (vars(n))
    o = Old()
    print (vars(o))
    o.x = 2
    print (vars(o))
python
$ python foo.py
{'_x': 10}
{'_x': 2}
{'_x': 10}
{'x': 2, '_x': 10}
In short, Old
class Old():
    def __init__(self):
        self._x = 10
if __name__ == '__main__':
    o = Old()
    print (vars(o))
    o.x = 2
    print (vars(o))
Same thing as running.