0

In Python, getters and setters for member data are generally frowned up in lieu of properties. The reasons emphasize cases where we might want to transparently swap out a computation and a value, and cases where members are likely to be read and assigned to in a single express.

What about members that cannot or cannot sensibly be assigned to? Are there any structural reasons to prefer a getter or a property in that case?

The specific case I have in mind is a class with computed members that might be cached.

Community
  • 1
  • 1
Praxeolitic
  • 22,455
  • 16
  • 75
  • 126
  • My instinct told me that your read only property or computed member data could well just be a method, eg. `get_computed_data()`, or be a attribute which is named wisely like `computed_result`. It should be quite obvious that it isn't for assignment. Both can be easily cached – Anzel May 16 '16 at 01:57

1 Answers1

1

It depends upon how the trait you have in mind should be perceived to be. Is it an attribute which can be accessed trivially, or should it appear to require "work" to get?

If your trait is a cached value, and the site of access should have no way to influence how that trait is retrieved, then needing to denote the fact that you're using a getter function means you're telling the consumer that there is a process that needs to be performed when there is no need for them to know about it. Why make someone think about the consequences when by design you say they don't need to know?

Suppose however, that your getter may need control at the site of access, like under some conditions, you might want to invalidate the cache. It may not be common in consumer code, but that's for you to decide. In that case, you'd either need a getter with parameters, or a reset method to go with your cached property.

One last, probably overdone, reason to prefer methods over properties would be the access time for a property descriptor is marginally slower than for a method call, so if the trait is accessed deep within a tight loop, using a property, even a cached one, can have a measurable impact.

EDIT - Clarifying Cost of Descriptors

When retrieving a method or descriptor, you're looking up the name's value. If you're using a function, it's just called after look up. If you're using a descriptor (@property), this is detected, and the descriptor's __get__ method is retrieved and called. This means that the descriptor has an extra look up step. This cost is minimal, and is practically immeasurable for common use, but if its accessed very frequently as in an inner loop, that price can accumulate.

In [1]: class Method(object):
   ...:     def get_my_value(self):
   ...:         return 1
   ...:

In [2]: class Property(object):
   ...:     @property
   ...:     def my_value(self):
   ...:         return 1
   ...:

In [3]: M = Method()

In [4]: %timeit M.get_my_value()
The slowest run took 14.74 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 133 ns per loop

In [5]: P = Property()

In [6]: %timeit P.my_value
The slowest run took 8.09 times longer than the fastest. This could mean that an intermediate result is being cached
10000000 loops, best of 3: 181 ns per loop
mobiusklein
  • 1,403
  • 9
  • 12
  • Why is a method expected to be faster than a comparable property? – Praxeolitic May 16 '16 at 03:09
  • I posted an update on the performance characteristic of method vs property last night. Because the resolution process is *within* the interpreter, its not possible to measure the individual look up steps and time each part. There is also some work on property resolution speed related to http://bugs.python.org/issue23910 in Python 3.5 – mobiusklein May 16 '16 at 17:17