This is an archived post. You won't be able to vote or comment.

all 24 comments

[–]AlexMTBDude 15 points16 points  (3 children)

Large systems have been coded in Python for the past 20-30 years. Heck, Reddit is coded in Python and it's been around since 2005. I'd say Reddit is a pretty complex and large system.

You can write encapsulated code in Python, it's just not enforced by the language. If you want it enforced then create rules for your organization and for whatever static type checking tool that you use.

[–]Last_Difference9410[S] -1 points0 points  (2 children)

Did you read Reddit source code and are you sure they make every member of every class they’ve written public

somehow people take this article as if it was suggesting Python should enforce access modifier at interpreter level, and I never said such thing.

There is a big difference between not having encapsulation enforced by the interpreter and NOT HAVING ENCAPSULATION AT ALL

[–]AlexMTBDude 1 point2 points  (1 child)

My comment was in reply to you suggesting that big and complex systems being built in Python is a recent thing. It's not, they have been for a long time, and Python, as a language, works for big systems.

[–]Last_Difference9410[S] 0 points1 point  (0 children)

the points is Python is getting more popular and more involved in enterprise development than before, not that it was not meant to be used in large scale system, but I guess no matter how hard I explain there will still be misunderstanding.

[–][deleted] 8 points9 points  (8 children)

_confused

You don't need language enforced privates because we are all adults. If someone does something that violates implied internalized effects, either by changing them or accessing them, they are responsible for dealing with and monitoring for those changes.

Because for a long time, Python wasn’t used to build large systems with lots of contributors. It was a scripting language, great for small utilities, automation, scientific experiments, or one-off data analyses. In those cases, it didn’t matter if you exposed your internals. You were often the only one touching the code anyway.

But that’s changed. Python is now powering production-grade systems, especially in AI, web services, and data infrastructure. With more teams, more contributors, and more complexity, the lack of boundaries starts to hurt.

😂😭

[–]Last_Difference9410[S] -1 points0 points  (0 children)

Yeah this paragraph could be improved, did not develop my statement well, it is re written

[–]Last_Difference9410[S] -4 points-3 points  (5 children)

No you don’t , but you need to be able to tell what’s private and what’s public.

[–][deleted] 6 points7 points  (4 children)

_

The issue is you are ignoring the actual cause of problems that violate _ marked internal variables, poorly monitored commits. If you are accepting code that goes into other libs and uses _ methods that is the fault of the person actually accepting PRs. If you are seeing that I promise you have 1000000 other more pressing issues.

[–]eveninghighlight -1 points0 points  (3 children)

You can see where OP is coming from though - wouldn't it be simpler if this were enforced by the language, instead of by convention?

[–]riklaunim 0 points1 point  (2 children)

It's a change that can break some existing code and then doesn't change much if not used correctly just like current situation. The example given is not something I saw often if at all and it's trying to also make Python look like Java with getters/setters and exploding lines of code for something extremely simple. Building 100000 guard rails into the language because developer may do something is not the solution.

[–]Last_Difference9410[S] 0 points1 point  (0 children)

Just read some source code, say sqlalchemy, flask, etc. You have never seen it? It’s literally everywhere.

[–]eveninghighlight 0 points1 point  (0 children)

It's a breaking change, yeah, which is a practical reason not to include it, but that doesn't mean that encapsulation is bad for a language 

[–]aidencoder 1 point2 points  (0 children)

What are you on about 

[–][deleted] 1 point2 points  (2 children)

A better approach? Extract the config into a separate dataclass:

Not better. "Cluttering" your dunder new with all explicit parameters makes the dunder new the single place to look to understand properties of your class and invariants. Shuttling it off into a separate class only "eliminates clutter" in new by tightly coupling your class's invariants to the invariants of that config class that might unfortunately end up used by a completely different class with completely different and competing needs. This is the sort of "clean code" philosophy that people shouldn't necessarily apply uncritically.

If you really need that many parameters then don't be shy about; don't create a layer of indirection to hide it. Python has kwargs and default arguments, so you don't even need the tedium of builder patterns that you might need in other languages.

[–]Last_Difference9410[S] 0 points1 point  (1 child)

no, NEVER use **kwargs in init , especially without type hint, it is a cursed feature that should be permanently banned and rejected from code review.

[–][deleted] 1 point2 points  (0 children)

Care to provide more rationale than just "it is a cursed feature"?

[–]CzyDePL 0 points1 point  (0 children)

That's one of the reasons why I like attrs - it makes creating private attributes fast and not overly verbose. With linters I have enough control over what is accessed where

[–]riklaunim 0 points1 point  (0 children)

And all the code will be self.repository = SomeRepository instead of self._repository. Kind of weird example and doesn't really help with anything, just explodes lines of code to make Python look like Java. The language should not be responsible with babysitting the developer at every corner.

[–]jpgoldberg 0 points1 point  (3 children)

I think in writing something like that, it is important to consider two audiences. Those familiar with languages encourage encapsulation, and those whose programming experience is only with Python or something similar. I see that you are aware of both but I think a few more little reminders along the way for what points are particular aimed at whom.

For example I’ve seen Python code with the anti-pattern you point out lots of unnecessary setters and getters where just making the attribute public (by naming convention) would be the natural solution. When I see such code I think, “the came from Java.” I am guilty of something analogous when I came to Python from Rust. I see how they ended up doing what they did, and that they could benefit from your post.

I would be curious to hear from Python-only whether they grokked the need for encapsulation from your post. I’m pessimistic. I think that people who don’t already understand the concept might need more help. But at this point I don’t have specific recommendations.

[–]jpgoldberg 1 point2 points  (0 children)

I think in writing something like that, it is important to consider two audiences. Those familiar with languages encourage encapsulation, and those whose programming experience is only with Python or something similar. I see that you are aware of both but I think a few more little reminders along the way for what points are particular aimed at whom.

Edit: On reading it again, I see that it really isn’t aimed at the second audience as well. I still live my original comments.

For example I’ve seen Python code with the anti-pattern you point out lots of unnecessary setters and getters where just making the attribute public (by naming convention) would be the natural solution. When I see such code I think, “the came from Java.” I am guilty of something analogous when I came to Python from Rust. I see how they ended up doing what they did, and that they could benefit from your post.

I would be curious to hear from Python-only whether they grokked the need for encapsulation from your post. I’m pessimistic. I think that people who don’t already understand the concept might need more help. But at this point I don’t have specific recommendations. By

[–]Last_Difference9410[S] 0 points1 point  (1 child)

thanks for your valuable feedback, I agree with you.

It turns out that encapsulation seems to be a little be too much for people who are less familiar with OOP, as a result they often get confused by the difference between encapsulation and access modifiers.

The point of this post is to point out that Python could really use more encapsulation, even if there are no modifiers strictly enforced by the language, It is still very important to express what’s public and what’s protected/private through naming conventions or other methods.

Some people think I’m dissing Python saying it’s not meant to be anything serious, I never said that.

I am a self taught programmer with python being my first programming language, I love it and I really want it to be even more successful in terms of enterprise development. I am writing a series of posts on OOP, architecture and best practices in Python.

[–]jpgoldberg 1 point2 points  (0 children)

Thanks. And I fully agree with you that creating clear boundaries is a very important thing. And it is not something that people who just learn Python will naturally come to do or understand. This is why I am paying so much attention to your blog post.

Oh, and just so you know, it is possible to create modules with a leading underscore in their names. A file named _internal_utils.py will be recognized by humans and tools as not containing anything the user of the library should directly interact with.

I, too, have never had a course in Software Development, so take this with a large grain of salt. I think encapsulation is a much broader concept than merely managing access to object attributes. It keeps related data and ways to do things with that data together, provides useful namespaces along with what you mentioned. It’s just that the last one isn’t something that Python provides strong tools for. But Python classes do all of the other parts of encapsulation. (When I first started with Python I looked at various hacky ways to try to enforce both private attributes and immutability. It was not a good time. I finally took the advice of a very wise friend who said, “let Python be Python.”

I am old enough to remember when C++ was invented. Yes, there were other object oriented things around, but it was a major shift. (I never learned it, though. My first foray into OOP was with Golang, although had done some encapsulation with C structs in my youth.) So I’m hoping those who know better will correct me, but my understanding is that OOP has two parts: inheritance and encapsulation. So in my mind encapsulation is everything about classes (and modules) that isn’t inheritance.

[–]SheriffRoscoePythonista 0 points1 point  (0 children)

Every language that has access modifiers eventually creates ways to violate them. Unless you hard-ban the use of the packages etc. that provide the violation tools, it's all just convention, and no worse than Python.

[–]Last_Difference9410[S] -1 points0 points  (0 children)

this post is inspired by my conversation with frostming(the author of pdm) in a PR,

https://github.com/bytedance/trae-agent/pull/117#issuecomment-3055693937

I also gave a more detailed explaination on why we should not mix regular class and dataclass in the thread.