There already was a similar question "When and how to use the builtin function property() in python", but I thing this is one is different.
I have a class that needs a method to get a counter of some work progress:
class Downloader():
def __init__(self, max_workers):
self.executor = ThreadPoolExecutor(max_workers)
#property
def unfinished_tasks_count(self):
return self.executor._work_queue.unfinished_tasks
I think it's better to do:
class Downloader():
...
def get_unfinished_tasks_count(self):
return self.executor._work_queue.unfinished_tasks
because when it's property looking at the interface (without looking at the docs and/or source code) it is not explicit that it's a read-only, computed attribute. When it's a method it is clear that it is only a getter of a computed value and it's not a simple attribute that can be set by an API client.
So my question is: When to use a getter method vs a read-only property?
The usage of properties should bear your intention and provide a reasonable expectation to your peers.
When not to use a property:
When it involves a computation that may take non-constant time. This would counter the intuition that accessing an attribute is a fast thing to do.
When it bears some external state, that is changed by someone else than your peer accessing the property. Doing so would counter the intuition that accessing the attribute twice yields the same result. On the other hand when you need the result of a method call twice, you usually store it in a local variable and thereby avoid it changing in between.
When to use properties:
Mainly when not using properties becomes a burden (syntactically).
When you need to implement a particular interface (duck typing) and there is no other way to do it.
As usual with such questions, answers are subject to taste and there are no hard rules. These guidelines may serve you well in many cases, but they do not remove the need to apply common sense.
Related
A method to achieve read-only access is to create a getter with no setter. This is the implementation in Python.
class Inventory:
_items: list[Item]
#property
def items(self) -> list[Item]:
return self._items
But given that Python has no notion of access restriction, ._items will still be viewable, readable, and modifiable externally.
Instead, I could remove the getter and treat .items as a normal member - since Python won't restrict access either way - reducing code overhead and the number of members to keep track of.
class Inventory:
items: list[Item]
The main benefit I can still see with the getter is that it signals to other developers by convention to avoid accessing the member. Are there any other arguments in its support?
._items will still be viewable, readable, and modifiable externally.
Yes, that is correct.
But someone who interacts with it should know better,
since it has clearly been marked Off Limits.
So there is some documentation value in this getter.
For one thing, code linters can notice inappropriate interaction
and ask CI/CD to fail the build.
With that said, the example you show is not a typical
pattern in production python code. A """docstring"""
or other explicit or implicit documentation will
usually make it clear if mutating an object attribute
should not be attempted.
For the truly paranoid, such a getter might choose
to return a shallow copy, or even a deep one, subject
to the obvious tradeoffs.
Notice that the object returned by the example getter
is mutable and can still be trashed by a caller that wants to.
Classes inheriting from Inventory might choose
to offer such copying behavior.
Independent of whether the parent has a getter,
child classes might also offer "transparent"
behaviors such as logging access frequency or object size.
I've been programming in Python for a long time, but I still can't understand why classes base their attribute lookup on the __dict__ dictionary by default instead of the faster __slots__ tuple.
Wouldn't it make more sense to use the more efficient and less flexible __slots__ method as the default implementation and instead make the more flexible, but slower __dict__ method optional?
Also, if a class uses __slots__ to store its attributes, there's no chance of mistakenly creating new attributes like this:
class Object:
__slots__ = ("name",)
def __init__(self, name):
self.name = name
obj = Object()
# Note the typo here
obj.namr = "Karen"
So, I was wondering if there's a valid reason why Python defaults to accessing instance attributes through __dict__ instead of through __slots__.
Python is designed to be an extremely flexible language, and allows objects to modify themselves in many interesting ways at runtime. Making a change to prevent that kind of flexibility would break a massive amount of other people's code, so for the sake of backwards compatibility I don't think it will happen any time soon (if at all).
As well as this, due to the way Python code is interpreted, it is very difficult to design a system that can look ahead and determine exactly what variables a particular class will use ahead of time, especially given the existence of setattr() and other similar functions, which can modify the state of other objects in unpredictable ways.
In summary, Python is designed to value flexibility over performance, and as such, having __slots__ be an optional technique to speed up parts of your code is a trade-off that you choose to make if you wish to write your code in Python. I can't answer whether this is a worthwhile design decision for you, since it's entirely based on opinion.
If you wish to have a bit more safety to prevent issues such as the one you described, there are tools such as mypy and pylint which can catch that sort of error.
I am exploring decorators in Python, and as a person who came to Python from other languages, I am a bit confused about the purpose of #property and its #xxx.setter brother. In Java and C++ get_xxx() and set_xxx() are usually the way to organize encapsulation. In Python we have these two decorators, which require specific syntax, and name matching in order to work. How is #property better than get-set methods?
I have checked this post and still, what are the advantages of #property besides the availability of the += operator?
The best part of using property for an attribute is that you don't need it.
The philosophy in Python is that classes attributes and methods are all public, but by convention - when you prefix their name with a single "_"
The mechanism behing "property", the descriptor protocol, allows one to change a previous dumb plain attribute into an instrumented attribute, guarded with code for the getter and setter, if the system evolves to a situation where it is needed.
But by default, a name attribute in a class, is just a plain attribute. You do person.name = "Name"- no guards needed, no setting method needed nor recommended. When and if it one needs a guard for that (say, to capitalize the name, or filter on improper words), whatever code uses that attribute needs no change: with the use of property, attribute assignment still takes place with the "=" operator.
Other than that, if using "=" does not look prettier than person.set_name("Name") for you, I think it does for most people. Of course, that is subjective.
I'm writing a library that parses a file, creates an object that represents the file, and allows exporting the object back to a file.
I want to validate that the required headers and columns are included any time those values are changed. Due to this, I was trying to setup validation with the #property decorator.
I noticed in the python documentation for #property they use '_variable' if the property name was 'variable'. I understand that a single underscore in front is to signify the variable is intended for weak internal use. However, I was under the impression the point of the #property decorator was that any call to set a variable would cause the setter function to run.
_headers = None
required_headers = ['FIELD_DELIM', 'VIDEO_FORMAT', 'FPS']
#property
def headers(self):
return self._headers
#headers.setter
def headers(self, value):
for header in self.required_headers:
if header not in value:
raise Exception
self._headers = value
While this code works, I know that I can still bypass my setter by doing myObject._headers=value.
Is there a way I can ensure that validation is always performed without relying on a user to respect _headers is for internal use?
Python is not designed to help you "ensure" that nobody misuses your objects like that. The underscore prefix for private attributes, and the #property mechanism for hiding attributes behind getters and setters, can ensure that it's obvious that people shouldn't use your objects like that, and make it harder for them to do so accidentally, but it can't prevent them from actually doing so maliciously.
While there are tricks you can use to hide your attributes even better, in a highly dynamic, introspectable language like Python, there's always going to be a way to get around that—look directly in your __dict__, or in whatever other attribute you hide them in, or just change the __class__ of your object to something less restrictive.
In other words, you already can rely on a user to respect that _headers is for internal use if all you're worried about is your users being idiots; if you're worried about them being malicious, Python is the wrong language for you.
You can use double underscore for name mangling or implement a custom descriptor, but one of Python's core tenets is that users are expected to be "consenting adults" who respect interfaces and do their best not to do things that break interfaces without a very good reason. Basically, don't worry about it and just use the single underscore to store the data on the object.
sort of. there's no real privacy in python and with a little work a user can circumvent your privacy safegauards.
if you want, you could implement __getattribute__ which checks any time you try to access an element of your class, but even that's not foolproof. check out this link Difference between __getattr__ vs __getattribute__
No, Python doesn't enforce the concept of private vs public like Java does
I used to be a java programmer and am currently changing to Python.
In Java all functions are class methods, but I'm not sure what the situation is in Python.
If I define a queue and want to know the size of the queue, what is the best design?
Define a variable __size, and define a method size()
Use #property at the method size to make __size readonly
Simply define variable self.size
My question is really focused on the coding style of Python, whether to make everything method or to use private variables.
Is it preferable to use #property getters & setters for every variable?
I agree with Eli's link, in that usually getters and setters are extra cruft.
However, in this particular case, you should define a __len__() method that will return the current size of your queue, allowing you to use the len(<obj>) builtin to retrieve the length. Among other things, it will allow you to easily get a boolean value to determine if your queue is empty.
The Pythonic approach is just to have an attribute. If you later happen to need more functionality behind that attribute, you can always use the #property decorator.
Read this for more details: http://eli.thegreenplace.net/2009/02/06/getters-and-setters-in-python/