EDIT
2025-11-21 22:37 Coordinated Universal Time
TL;DR: I propose to add a keyword to mark fields and classes as private. My proposal for the keyword name is local, or what else.
Why:
-
Speed. Python in recent releases is focusing on speed. If an attribute can be marked as
local, Python can be sure this is “really” private, and can do some optimizations. -
It’s granular. Now, if you want to make attributes “private”, you should use
@dataclass(frozen=True). This is all or nothing. You can’t choose to make only some attributes “private” and some other “public”. Furthermore, in a future, you could potentially have a@dataclass(locals=true)to have all memberslocal, if you really want that. -
It will be easier to refactor a class. You don’t have to rename all the occurrences of the field, just add or remove
local -
it will give to people that fights against the mantra that Python is “not good for corporate code” another strong point against this.
Why local:
- IMO more pythonic that
private - open to other future uses. Note the word “future”. My proposal is restricted to classes only for now.
Examples:
local:
a = 1
print(a) # prints 1
print(a) # NameError: name 'a' is not defined
##########################################################################
for local k, local v in d.items()
print(k, v)
print(k, v) # NameError
##########################################################################
# file my_useless_module.py
local import math
local from datetime import datetime
local x = 2
now = datetime.now()
sqrt2 = math.sqrt(2)
local def f(): pass
local class A: pass
# If you import `my_useless_module`, only `now` and `sqrt2` are exposed,
# without the need of underscores, `__all__` or `del`
##########################################################################
# alternative to the previous idea
local a = 2
print(a) # prints 2
def f():
print(a)
f() # NameError: name 'a' is not defined
##########################################################################
def g():
local a = 3
print(a)
def h()
print(a)
h()
g() # prints 3 and then raises NameError: name 'a' is not defined
Original post (2025 remastered)
When you write a class, “private” fields and methods are prepended with underscore. Python borrowed that from Unix, if my memory it’s not wrong.
In theory, you can write a class without “private” fields and methods, not adding any underscore as prefix. If, in a future, you want to turn them private, you can use @property to restrict the accessibility to, for example, read-only. Or you can simply add the underscore and turn it private.
But in the real world, no one do that. People prefers to write _field from the start, to say loudly “Hey, don’t touch it. It’s a bad, bad idea”. This is impossible using a field without underscore from the start and then making it private with @property or adding an underscore after.
Why? Because it’s more simple to mark internal fields and methods as private with the underscore instead of writing them all without underscore. If you do this, and later a lot of people that uses your code need to use a field that’s private, the dev can make it public without any problem.
On the contrary, if you write all the fields without underscore, people can use them all without any fear. They don’t see any underscore and they think “Hey, I can use it”. But, if at a certain point you decide to render one of them private, using a read-only @property or adding an underscore to make it completely private, it will be a big problem: the code of the people that used that field will break.
So, in practice, no one writes all the fields without the underscore and use later @property or adds the underscore. Furthermore, @property is incompatible with the fantastic @dataclass.
That’s why IMO Python should introduce the local, private or whatelse keyword. It’s not only easier this way to refactor a class, but also give to people that fights against the mantra that Python is “not good for corporate code” another strong point against this.
Yeah, this is yet-another-discussion-about-private.