title: Is there an advantage of using the property decorator compared to the property class?
body: <p>I can see two very similar ways of having properties in Python</p>
  
  <h2>(a) Property class</h2>
  
  <pre><code>class Location(object):
  
      def __init__(self, longitude, latitude):
          self.set_latitude(latitude)
          self.set_longitude(longitude)
  
      def set_latitude(self, latitude):
          if not (-90 &lt;= latitude &lt;= 90):
              raise ValueError('latitude was {}, but has to be in [-90, 90]'
                               .format(latitude))
          self._latitude = latitude
  
      def set_longitude(self, longitude):
          if not (-180 &lt;= longitude &lt;= 180):
              raise ValueError('longitude was {}, but has to be in [-180, 180]'
                               .format(longitude))
          self._longitude = longitude
  
      def get_longitude(self):
          return self._latitude
  
      def get_latitude(self):
          return self._longitude
  
      latitude = property(get_latitude, set_latitude)
      longitude = property(get_longitude, set_longitude)
  </code></pre>
  
  <h2>(b) Property decorator</h2>
  
  <pre><code>class Location(object):
  
      def __init__(self, longitude, latitude):
          self.latitude = latitude
          self.longitude = latitude
  
      @property
      def latitude(self):
          """I'm the 'x' property."""
          return self._latitude
  
      @property
      def longitude(self):
          """I'm the 'x' property."""
          return self._longitude
  
      @latitude.setter
      def latitude(self, latitude):
          if not (-90 &lt;= latitude &lt;= 90):
              raise ValueError('latitude was {}, but has to be in [-90, 90]'
                               .format(latitude))
          self._latitude = latitude
  
      @longitude.setter
      def longitude(self, longitude):
          if not (-180 &lt;= longitude &lt;= 180):
              raise ValueError('longitude was {}, but has to be in [-180, 180]'
                               .format(longitude))
          self._longitude = longitude
  </code></pre>
  
  <h2>Question</h2>
  
  <p>Are those two pieces of code identical (e.g. bytecode wise)? Do they show the same behavior? </p>
  
  <p>Are there any official guides which "style" to use?</p>
  
  <p>Are there any real advantages of one over the other?</p>
  
  <h2>What I've tried</h2>
  
  <h3>py_compile + uncompyle6</h3>
  
  <p>I've compiled both:</p>
  
  <pre><code>&gt;&gt;&gt; import py_compile
  &gt;&gt;&gt; py_compile.compile('test.py')
  </code></pre>
  
  <p>and then decompiled both with <a href="https://pypi.org/project/uncompyle6/" rel="noreferrer">uncompyle6</a>. But that just returned exactly what I started with (with a bit different formatting)</p>
  
  <h3>import + dis</h3>
  
  <p>I tried</p>
  
  <pre><code>import test  # (a)
  import test2  # (b)
  dis.dis(test)
  dis.dis(test2)
  </code></pre>
  
  <p>I'm super confused by the output of <code>test2</code>:</p>
  
  <pre><code>Disassembly of Location:
  Disassembly of __init__:
   13           0 LOAD_FAST                2 (latitude)
                2 LOAD_FAST                0 (self)
                4 STORE_ATTR               0 (latitude)
  
   14           6 LOAD_FAST                2 (latitude)
                8 LOAD_FAST                0 (self)
               10 STORE_ATTR               1 (longitude)
               12 LOAD_CONST               0 (None)
               14 RETURN_VALUE
  </code></pre>
  
  <p>whereas the first one was way bigger:</p>
  
  <pre><code>Disassembly of Location:
  Disassembly of __init__:
   13           0 LOAD_FAST                0 (self)
                2 LOAD_ATTR                0 (set_latitude)
                4 LOAD_FAST                2 (latitude)
                6 CALL_FUNCTION            1
                8 POP_TOP
  
   14          10 LOAD_FAST                0 (self)
               12 LOAD_ATTR                1 (set_longitude)
               14 LOAD_FAST                1 (longitude)
               16 CALL_FUNCTION            1
               18 POP_TOP
               20 LOAD_CONST               0 (None)
               22 RETURN_VALUE
  
  Disassembly of set_latitude:
   17           0 LOAD_CONST               3 (-90)
                2 LOAD_FAST                1 (latitude)
                4 DUP_TOP
                6 ROT_THREE
                8 COMPARE_OP               1 (&lt;=)
               10 JUMP_IF_FALSE_OR_POP    18
               12 LOAD_CONST               1 (90)
               14 COMPARE_OP               1 (&lt;=)
               16 JUMP_FORWARD             4 (to 22)
          &gt;&gt;   18 ROT_TWO
               20 POP_TOP
          &gt;&gt;   22 POP_JUMP_IF_TRUE        38
  
   18          24 LOAD_GLOBAL              0 (ValueError)
               26 LOAD_CONST               2 ('latitude was {}, but has to be in [-90, 90]')
               28 LOAD_ATTR                1 (format)
               30 LOAD_FAST                1 (latitude)
               32 CALL_FUNCTION            1
               34 CALL_FUNCTION            1
               36 RAISE_VARARGS            1
  
   19     &gt;&gt;   38 LOAD_FAST                1 (latitude)
               40 LOAD_FAST                0 (self)
               42 STORE_ATTR               2 (latitude)
               44 LOAD_CONST               0 (None)
               46 RETURN_VALUE
  
  Disassembly of set_longitude:
   22           0 LOAD_CONST               3 (-180)
                2 LOAD_FAST                1 (longitude)
                4 DUP_TOP
                6 ROT_THREE
                8 COMPARE_OP               1 (&lt;=)
               10 JUMP_IF_FALSE_OR_POP    18
               12 LOAD_CONST               1 (180)
               14 COMPARE_OP               1 (&lt;=)
               16 JUMP_FORWARD             4 (to 22)
          &gt;&gt;   18 ROT_TWO
               20 POP_TOP
          &gt;&gt;   22 POP_JUMP_IF_TRUE        38
  
   23          24 LOAD_GLOBAL              0 (ValueError)
               26 LOAD_CONST               2 ('longitude was {}, but has to be in [-180, 180]')
               28 LOAD_ATTR                1 (format)
               30 LOAD_FAST                1 (longitude)
               32 CALL_FUNCTION            1
               34 CALL_FUNCTION            1
               36 RAISE_VARARGS            1
  
   24     &gt;&gt;   38 LOAD_FAST                1 (longitude)
               40 LOAD_FAST                0 (self)
               42 STORE_ATTR               2 (longitude)
               44 LOAD_CONST               0 (None)
               46 RETURN_VALUE
  </code></pre>
  
  <p>Where does that difference come from? Where is the value range check for the first example?</p>