Should properties have non-trivial initialization?

I have an object that is basically a Python implementation of an Oracle sequence. For a variety of reasons, we need to get the next Oracle sequence number, manually count when defining primary keys, and then update the sequence after the records have been inserted.

So the steps my object is following:

  • Construct an object with the attribute key_generator

    initially set to None.
  • Get the first value from the database by passing it to itertools.count.
  • Returns the keys from this generator using the next_key


I'm a little unsure where to go to step 2. I can imagine three possibilities:

  • Skip step 1 and do step 2 in the constructor. I find this evil because I don't like doing this kind of initialization in the constructor.
  • Make next_key

    get the first key from the database on the first call. I find this evil because properties are generally considered trivial.
  • Make next_key

    into a method get_next_key

    . I don't like this, because the properties here seem more natural.

Less than 3 is evil? I'm leaning towards # 2 because only the first call to this property will result in a database query.


source to share

3 answers

I think your doubts come from PEP-8 :

    Note 3: Avoid using properties for computationally expensive
    operations; the attribute notation makes the caller believe
    that access is (relatively) cheap.


Compliance with standard behavior is usually a good idea; and that would be a reason to reject decision # 2.

However, if you feel that the interface is better using a property than using a method, then I'll just document that the first call is more expensive and go with that (solution # 2).
Ultimately, the recommendations must be interpreted.



I agree that attribute access and whatever it likes (i.e. properties in the Python context) should be pretty trivial. If a property will perform a potentially expensive operation, use a method to make it explicit. I recommend a name like "fetch_XYZ" or "retrieve_XYZ" because "get_XYZ" is used in some languages โ€‹โ€‹(eg Java) as a shorthand for easy attribute access, is fairly general, and is not "expensive".

Good recommendation: if your property can throw an exception that is not related to a programming error, it should be a method. For example, throwing a (hypothetical) DatabaseConnectionError from a property is bad, but throwing an ObjectStateError would be fine.

Also, when I understand you correctly, you want to return the next key, whenever the next_key property is available. I highly recommend against side effects (besides caching, cheap lazy initialization, etc.) in your properties. Properties (and attributes for that matter) must be idempotent.



I decided that the key smell in the solution I was proposing was that the property I was creating contained the word "next" in it. So instead of creating a property, next_key

I decided to turn my DatabaseIntrospector class into a KeyCounter class and implement the iterator protocol (i.e. make a simple old next method that returns the next key).



All Articles