I started learning programming in Python and was never exposed to the concept of public/private for a while. After learning about the concept with Java I still didn't see too much use for it and was always fond of Python's "we're all consenting adults" principle. Especially when the usual get/set methods add so many lines of code to otherwise one-liners. Eventually after programming substantial projects in C++ I started to understand its benefits such as allowing encapsulating implementation details. It also clearly expresses when a variable should not be set directly as its setting should have side effects.
When my Python programs became large enough I often forget whether an attribute is only used internally and do not know whether the attribute is safe to change. Often I end up changing the attribute, running the program, encountering an exception, fixing the error in dependent code, and repeating. In Python we can use the leading underscore pseduo-private convention and the property function to gain these advantages while still allowing code to access what it wants.
As an example here is a point class. The attributes 'x' and 'y' should really not be allowed to be set directly because the 'distance' attribute needs to be recomputed any time (this may also be a sufficiently complicated expression that recomputing each time would take too long).
class Point:
def __init__(self, x, y):
self._x = x
self._y = y
self._distance = (x**2 + y**2) ** (1/2)
@property
def x(self):
return self._x
@property
def y(self):
return self._x
@property
def distance(self):
return self._distance
If your attributes are read-only the code can be quite concise.
class Point:
x = property(lambda self: self._x)
y = property(lambda self: self._y)
distance = property(lambda self: self._distance)
def __init__(self, x, y):
self._x = x
self._y = y
self._distance = (x**2 + y**2) ** (1/2)
I've really taken to the later style but haven't really used it extensively. Is there any disadvantages of making most "public" attributes properties? I can only think of:
Make attributes read-only if it's necessary to do so. Don't make every attr read-only by default.
There's nothing wrong with using properties to implement read-only attributes. That's one of the reasons why properties are a part of Python. On the other hand, there's nothing especially right about making most attributes read-only. It goes against the standard Python idiom and makes your classes harder to interact with (especially from within your own code base). Keep in mind that there is no actual equivalent for the C++ private keyword in Python. For example, even though x is read-only, there's nothing stopping a user dedicating to shooting themselves in the foot from just doing self._x = 19 anyway.
Generally, it's enough to use the leading underscore _name convention to mark internal vs public attributes:
class Foo:
def __init__(self, bar, baz):
self._mine = bar
self.public = baz
As designed, the x and y attributes of your Point class are good candidates for read-only attributes. However, I'd say that it's more Pythonic to design your class flexibly and make distance a method:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def distance(self):
return (x**2 + y**2) ** (1/2)
Or, if performance is an issue, leave distance as a property but recompute it whenever x or y change:
class Point:
@staticmethod
def _distance(x, y):
return (x**2 + y**2) ** (1/2)
@property
def x(self):
return self._x
@x.setter
def x(self, x):
self._x = x
self._distance = Point._distance(x, self._y)
@property
def y(self):
return self._y
@y.setter
def y(self, y):
self._y = y
self._distance = Point._distance(self._x, y)
distance = property(lambda self: self._distance)
def __init__(self, x, y):
self._x = x
self._y = y
self._distance = Point._distance(x, y)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With