Yes - you should use a property
only - and only if - access to the attribute involves something that will be computed live, and is more practical and readable to do this with an assignment (the operator =
) than calling a method.
If you won’t modify, filter, test anything in the attribute you’re using, you don’t have to create a Property.
There is a culture - which has developed in the wrong way - coming from other object-oriented languages that all access to attributes should be done by getters and setters' - and all attributes should be private.
Due to the choices and design of the Python language, where everything is open, you don’t win absolutely nothingness when creating extra getters and setters if you don’t have any relevant code within them. (As property
are the pythonic way of passing by the getter and Setter keeping the access syntax to the attribute clean - no need to call a method.
So, for example, in this case, you could use properties to ensure that the name is always a string:
class Person:
def __init__(self, name):
self.name = name
self.kind = kind
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("...")
self._name = value
but even this kind of checking -s efor done on all attributes, it’s kind of lame - the idea is that the language can accept any kind of parameter that works for what it needs, and let Runtime error happen if a parameter is passed that doesn’t work. Testing an attribute like this, exceptionally it’s one thing - if you’re testing them all, it’s Review the concepts and your style. In particular, current Python allows static check of data types - so you can create your entire system with the annotations
correct and use the mypy
to make sure everything is okay.
Continuing - realize that one of the great advantages of properties syntax is exactly that any attribute of a class can become a code-managed attribute - that is, a Property, or other type of data - without whom use the class needs to change nothing, not even know it.
That is: I can create a library that in version 1.0, the attributes "x" and "y" of a "point" class are normal instance attributes - and in version 2.0 of the same library turns them into a Property that ensures that they are always numbers - who used version 1.0 can continue using the same way with ponto.x = 10
.
This feature of Python, to access an attribute to pass through code, is not unique to properties - in fact, it is defined by the "descriptors protocol" (Descriptor Protocol), and I believe it is better documented in the document called "Data Model" language: any object that is a class attribute, and that has a name class method __get__
will be treated in a special way when accessed as attribute. A property
is just a rather convenient class to build these descriptors using class-own methods to access attributes - but the mechanism is also used to couple object fields to database columns, such as in Sqlalchemy ORM or Django ORM, and by the very functions of Python, which use the descriptors mechanism so that the attribute self
is automatically inserted when they are used as methods.
About attributes starting with two __
: Don’t use the prefix of __
for his attributes. You gain nothing from this - this activates a language Feature of changing the real name of the attribute at compile time, to avoid name collision in subclasses - it is not something like a "private attribute". In the second decade of Python’s existence (more or less from 2000 to 2013) a lot of documentation came out - tutorials, articles and books, treating the prefix __
as if it were the equivalent of private attributes of Java and C++ - no: private attributes do not exist in the syntax or Python specifications. They exist by convention only: that is, programmers agree that attributes and methods starting with one (and only one) _
must be accessed only by the developer of a class or module, and its behavior does not need to be documented, and may be subject to changes between versions of a library or package. But this is just a convention - language does nothing to "enforce" this.
On the other hand the __
activate this "name mangling" functionality - unless you know exactly what you want and what you’re doing, it’s more likely to cause a bug that’s hard to understand in your code than what you really want to happen (a clue: in 18 years developing in Python - and all kinds of advanced and absurd code, I never, not once, needed this functionality).
The example of trying to synchronize the attribute with an external storage, such as the database, is very good.
– jsbueno