When and how to use the built-in property of a function () in python

It seems to me that, with the exception of a little syntactic sugar, property () does nothing.

Of course, it's nice to write ab=2 instead of a.setB(2) , but hiding the fact that ab = 2 is not a simple assignment looks like a recipe for a problem, or because of an unexpected result like ab=2 , it actually causes ab like 1 . Or an exception occurs. Or a performance issue. Or just get confused.

Can you give me a concrete example for its good use? (using it to fix the problem code is not taken into account ;-)

+64
python properties
Oct. 12 '09 at 13:22
source share
7 answers

In languages ​​that rely on getters and setters such as Java, they are not supposed to and did not expect anything other than what they say - it would be surprising if x.getB() did nothing except return the current logical value attribute b , or if x.setB(2) did anything other than a small amount of internal work to make x.getB() return 2 .

However, there are no language guarantees regarding this expected behavior, i.e. restrictions associated with the compiler, with the body of methods whose names begin with get or set : rather, it left to common sense, social convention, "style guides" and testing.

The behavior of xb access and assignments, such as xb = 2 , in languages ​​that have properties (a set of languages, including but not limited to Python), is exactly the same as for getter and setter methods in, for example, Java: the same expectations, the same disadvantages of warranties guaranteed by languages.

The first gain for properties is syntax and readability. To write, for example,

 x.setB(x.getB() + 1) 

instead of the obvious

 xb += 1 

screaming for revenge on the gods. In languages ​​that support properties, there is absolutely no reason to force class users to go through such Byzantine patterns, affecting their readability of the code without any problems.

In Python, in particular, there is another great potential for using properties (or other descriptors) instead of getters and setters: if and when you reorganize your class so that the base setter and receiver are no longer needed, you can (without if you break the class, published API), simply eliminate those methods and the property that uses them, making b normal "stored" attribute of class x , and not the "logical" obtained and set computationally.

In Python, executing directly (when possible), and not through methods, is an important optimization, and the systematic use of properties allows you to perform this optimization whenever possible (always exposing the "normal stored attributes" directly, and only those that really need computation when access and / or configuration using methods and properties).

So, if you use getters and setters instead of properties, without affecting the readability of your users' code, you also spend machine cycles for free (and the energy that comes to their computer during these cycles ;-), again without a good reason.

Your only argument against the properties is, for example, that "the external user will not expect any side effects as a result of the assignment, as a rule"; but you overlook the fact that the same user (in Java, where getters and setters are everywhere) does not expect (observable) “side effects” as a result of calling the setter (or even less for the getter ;-). They are reasonable expectations, and you, as the author of the class, try to fit them - regardless of whether your setter and getter are used directly or through a property, it does not matter. If you have methods with important observable side effects, do not call them getThis , setThat and do not use them through properties.

The complaint that the "hide implementation" properties is completely unfounded: most OOPs are information hiding implementations - creating a class responsible for representing the logical interface to the outside world and its implementation as best as possible. Getters and setters, like properties, are tools to achieve this. Properties simply improve performance (in languages ​​that support them;).

+117
Oct 12 '09 at 15:16
source share

The idea is to allow you to avoid writing getters and setters until they need you.

So, for starters, you write:

 class MyClass(object): def __init__(self): self.myval = 4 

Obviously now you can write myobj.myval = 5 .

But later you decide that you need a setter, since you want to do something smart at the same time. But you don’t want to change all the code that your class uses, which is why you wrap the setter in the @property decorator and it all just works.

+30
Oct. 12 '09 at 13:34
source share

but hiding the fact that ab = 2 is not a simple appointment looks like a recipe for a problem

You do not hide this fact; this fact never happened. This is python, a high-level language; not assembly. Few of the “simple” statements in it boil down to individual CPU instructions. To read simplicity in a task, you need to read things that are not there.

When you say xb = c, perhaps all you need to think about is that "all that just happened, xb should now be c".

+14
Oct 12 '09 at 14:01
source share

The main reason is that she looks better. These are more pythons. Especially for libraries. something.getValue () looks less pleasant than something.value

In plone (a fairly large CMS), you had a document.setTitle () document that performs many functions, such as storing a value, indexing it, etc. Just doing document.title = "something" is better. You know that a lot is still happening behind the scenes.

+5
Oct 12 '09 at 13:38
source share

You're right, it's just syntactic sugar. Perhaps this is not good use, depending on your definition of the problematic code.

Note that you have a Foo class that is widely used in your application. Now this application has gotten large enough and, in addition, allows us to say that it has become popular.

You determine that Foo is causing a bottleneck. Perhaps you can add some caching to Foo to speed it up. Using properties will allow you to do this without changing the code or tests outside of Foo.

Yes, of course, this is problematic code, but you just saved a lot of $$, fixing it quickly.

What if Foo is in a library for which there are hundreds or thousands of users? Well, you saved yourself by telling them to make an expensive refactor when they upgrade to the new version of Foo.

The release notes have a line item about Foo instead of a paragraph wrap guide.

Experienced Python programmers do not expect more from ab=2 than ab==2 , but they know that this may not be true. What happens inside the class is your own business.

+3
Oct 12 '09 at 20:51
source share

Here is an old example. I wrapped the C library, which had functions such as "void dt_setcharge (int atom_handle, int new_charge)" and "int dt_getcharge (int atom_handle)." I wanted to execute "atom.charge = atom.charge + 1" at the Python level.

The property decorator makes this easy. Something like:

 class Atom(object): def __init__(self, handle): self.handle = handle def _get_charge(self): return dt_getcharge(self.handle) def _set_charge(self, charge): dt_setcharge(self.handle, charge) charge = property(_get_charge, _set_charge) 

10 years ago, when I wrote this package, I had to use __getattr__ and __setattr__, which made this possible, but the implementation was much more error prone.

 class Atom: def __init__(self, handle): self.handle = handle def __getattr__(self, name): if name == "charge": return dt_getcharge(self.handle) raise AttributeError(name) def __setattr__(self, name, value): if name == "charge": dt_setcharge(self.handle, value) else: self.__dict__[name] = value 
+2
Oct 12 '09 at 17:40
source share

getters and setters are necessary for many purposes and are very useful because they are transparent to the code. Having a Something object with a property height, you assign the value Something.height = 10, but if the height has a getter and setter, then at the time you assign this value, you can do many things in procedures, for example, to check the minimum or The maximum value of a value, for example, triggering an event, because the height has changed, automatically setting other values ​​in the function of the new height value, is all that can happen when Something.height is assigned. Remember that you do not need to call them in your code, they are automatically executed when you read or write the value of the property. In a way, they are similar to event procedures when property X changes the value and when the value of property X is read.

0
Jan 02 '15 at 2:40
source share



All Articles