Wow. I knew about name-mangling, but it's even worse than I expected. Maybe it has valid uses, but it definitely feels like a half-assed implementation of private variables that opens up far more traps than it solves.
@@SeanBracks Although the documentation does describe name mangling for creating "class private variables", it's not "private" in the conventional sense that it prevents users from accessing those attributes. The same explanation is also given by the doc's tutorial at section 9.6. "Private Variables", pointing out that the feature is only there for the use of collision avoidance. (yes, their terminology for this subject is all sorts of mixed up)
I had to extend some code that was written entirely like this and it was a nightmare. I ended up rewriting it in a new language. It's so infuriating, python is meant to be open and extensible and writing like this is like you're trying to write in C++, it really makes it worse
@@aantoniou96 And yet, it doesn't even achieve that, because you can re-use class names between modules further down the inheritance hierarchy. Not to even that it *is* used as a "soft" way of doing private variables in practice, because the two concepts are not a million miles apart.
You make top tier videos showcasing advanced Python topics. There is just too much beginner videos lying around. Therefore I'm glad to feel challenged by watching your videos
@@vectoralphaSec ...and: nerds love monty python, therefore: python is built for nerds. (Which is good in a computer language. You know what is NOT built for nerds? Microsoft office. 'nuf said.)
I remember learning about name mangling in my Intro to OOP class and we all just wished that we didn't have a question about that on the test. It's something that our lecturer told us to try and avoid and just use the convention of "underscore at the start means private - do not touch". Anyways, another informative and entertaining video from you :D
@@0neMadGypsy Thats the problem in Python. it doesnt have any way to declare some var as protected. and private doesnt really exist either, because you can use _classname__var to access __var. Its just convention to not mess with attributes (or methods for that matter) that start with an underscore. there is nothing stopping anybody from accessing those "private" attributes. while this seems kinda weird, its kinda nice to have this ability in a scripting language, which python is, because sometimes you want to manipulate some data without using the methods the library gives you and you dont want to do it the right way (which is probably to compile the library yourself with public attributes), because you just want a quick script to do some job, not some high quality solution that will stand the test of time until the universe burns out
you can use _classname_var to access members of an inherited class. This helps solving some of the puzzles you'll inevitably come up with when trying to solve the obvious resolution order problem arising from multiple inheritance. In fact, this actually makes dunder variables VERY useful given the adecuate context. Note that this context is NEVER publicly accessing members not designed for it.
php had __construct class methods builtin as default and the such built in to the oop part,whenever you defined some var with a new class too, you would EXPLICITLY name them so they would get called lol using those __ because they used to be like that in php and java is just a convention thing people took with them i guess personally i wouldn't touch python with a 10 foot pole if i didn't have to languaged with forced indenting are retarded. i don't trust languages that don't use semicolons as line enders, the entire basic-like structure falls flat if it means having to import C libraries for performance lol
Except if you're always using these variables as if they're ACTUALLY private, none of these implications matter. Use them in a sensical way, and you won't ever have an issue.
@@CrapE_DM if anyone else subclasses your class, you have to hope that they know to follow the rules. Otherwise you have left a hidden mine for them to step on. From personal experience, assuming outside users understand things like this is not a good assumption.
I have avoided these headaches by never using double underscore prefixes.. Im likely to keep that habit.. I get the sense that as Python blew up, it’s gotten pressure to have features of other lower level languages.. static typing and private/public attributes. But b/c those were afterthoughts and the solutions were retrofits, we get these wonky implementations.
99 times out of 100 if you reach for the word "class" in python (and you're not using it just like a struct), you're likely doing something wrong. The language just wasn't built for proper OO support so if you're not building a general-purpose library type like pandas dataframe, the whole thing is best avoided.
Or an even better solution: do not use inheritance from classes that are not interfaces (and thus don't have private fields) at all, and instead use composition, that is better in many ways. Avoid the problem completely basically.
I have definitely encountered this issue before and I am blown away by how much more complicated and weird the behavior is than I realized. My general approach has been to just avoid using the "feature".
Lately, due to many issues like these, I've been borrowing a lot of principles from functional, while still essentially using OO. For one, I try to make stuff immutable with named tuples or frozen dataclasses. Then I try to think of classes more in terms of types and its variables as defining its uniqueness. If something changes, it's a different instance of that type, so no counters. I've found that most of the time, moving counters out of classes makes for more readable, flexible, and loosely coupled code anyway. And if you learn how to leverage comprehensions, map, any, all, sum, itertools, etc., you often don't need counters. For things like widgets, use the ol' "composition over inheritance" mantra. You don't worry about stepping on any component's toes if you have to access them by their instance name anyway.
What about containers. Functional languages usually have copy-on-write optimizations for modifying them. In python you would need to shallow-copy any data structure (dict, list) when you add or remove anything, killing the performance. How do you get around this?
I knew about name-mangling, but I clicked on this video knowing I'd still learn something new. Had no clue about the mangling rules and was also happy you briefly showed the C code, which I was curious about!
I've been writing python since 2010, and consider myself a bit of a python expert. I've used name mangling in production... a whopping zero times. I've seen it in libraries only a handful of times. I've used it while messing around and found it kind of useless as long as you follow good hygiene. The answer to the question "how to avoid clobbering implementation details" is indeed look at the source code. Python is so heavily dynamic that if you feel the need to use _underscore attributes in a subclass, you really do need to know what the parent class is doing.
Well, if you have a variable that you don't want the user to have access too, I think making it private would be a usecase for doing so. The point of making somethng private is to make it more explicit that the variable can't be changed outside of it's scope.
@@steven7936 but that concept does not exist in Python; there is no 'private' and there is no way to prevent access (and there is no reason to do so anyway).
Ive used it where I had euclidean a vector class, and then needed a Gibbs version (complex values for quantum angular momentum)...so with mangling I was able to add a few lines do decide if abs() -> sum(getattr(j, self)**2 for j in 'xyz') or if getattr(j, self)*getattr(j, self).conjugate() was required. very slick.
I learned this a long time ago when I went deeper into the language syntax and semantics. If I use either _ or __ then it's because i dont want the property to be accessed directly outside of the class. The key things I learned were to bind it to the class in the constructor and learn how to intuit whether it should be used it or not. I only use getters and setters in certain circumstances, but if i expect the property to be accessed outside of the class, then there is no point in using either _ or __ and I completely drop the @property decorator. Personally, I abide by always binding properties to the class. I see no rationale for placing it outside of the constructor for the very reasons mentioned in this video. Regardless, this is A+ material and I enjoyed the deep dive as it was a refresher for something I learned years ago.
Thank you so much. I've spent half a day once trying to figure out what the hell is going on when one of the classes used different implementations of one of the functions depending on the conditions (self.__run_command = run_command_locally if local_machine else run_command_via_ssh). It was quite hellish exercise, until I found it out in a hard way. Switched to single underscore.
The name mangling feature is weird and widely unknown. And it has a serious Silent Fail problem! Doesn't the current convention say that if you want to protect fields then use only one underscore at the beginning?
The main thing name-mangling is legitimately used to avoid name collisions in code that needs to be able to subclass arbitrary types or otherwise inject some sort of extra management attribute into an object of an unknown type.
I have heard that the single underscore is preferred because you don't know how your classes are going to be used. Using double underscores ("private" variables) makes classes that have them unfriendly.
This is the most Python thing I've ever heard. You should know how your classes are supposed to be used (I mean, you designed and wrote them...), and should structure them such that they can only be used in valid ways - or at least such that it's difficult and obvious when you're using them in an unintended way.
Any interview that tests you on that is absolutely stupid. Interviews should not try to trick you or test whether you know some inane detail such as this, because it has no bearing on how competent you are as a developer.
What SHOULD happen, if it were designed properly, is an attempt to access the "private" variable __count would throw an exception for an access violation. This would put python in the same camp as other languages that have public and private keywords for class variables. Instead, it just mangles the name and it's on the programmer(s) to play nice and not abuse or work around it.
no, people should just learn the language instead of trying to copy Java. Why would you make something 'private' anyway? in some languages it makes sense, but not in Python: name conflicts are extremely rare in Python because it has Modules. instead of using getters/setters every real Python dev uses @property or writes custom descriptors. Learn to use the __set__ special method.
Guido van Rossum is very clever. That ends up being the source of a lot of python quirks like this. This is definitely a very clever way of implementing private variables in python with minimal overhead. In practice it turns out that people just never use it because its behavior is too strange. It's also difficult to figure out what would be a better solution given the design constraints of the language (that every object is basically just a dictionary of key value pairs). Somehow adding real private scopes seems "unpythonic", although I can't explain why. I think a lot of the confusion end up because the behavior results from a "magic" naming convention. Python doesn't really like adding keywords for stuff like this, but I can't help but think if name mangling was somehow linked to a "private" qualifier, that this confusion would not exist. That would have a drawback too though, in that you would have to qualify all uses of the field with "private". That's essentially what python already does actually, except they spell "private" (confusingly) as "__".
Real privacy is unpythonic because it's assumed that the programmer isn't trying to fuck themselves over intentionally. Getting/setting an _varname is basically telling the library that you think you know what you're doing, and if you really want to shoot yourself in the foot, then that's your right.
use properties for getters and setters: class A: __count = 42 @property def count(self): return self.__count @count.setter def count(self, value): self.__count = value Now if you repeat that code in sub class: class B(A): __count = -999 @property def count(self): [etcetera] then: .>>> a, b = A(), B() >>> a.count, b.count 42, -999 each class has a truly private unmangled count read/write public attribute that don't collide.
By clicking the video you have fallen for the trap, as advertised. It follows that the title was accurate. Maybe I should put something about mangling in there just so it is more searchable....
I did know about this, but the details get fuzzy after a while. I think the solution whenever possible is to use composition instead of inheritance, anyways.
Always thought: no underscore == public; single underscore == protected; double underscore == private. Don't see what the problem is. Also, can be thought as: no underscore == stable; single underscore == internal, can be changed at any time; double underscore == don't touch me. In my ten years programming in python name mangling has never been a problem.
How does the run-time naming handle conflicts between mangled names? If the mangled name ignores leading underscores in class names, could you not have some class "_____A" (5 underscores) and another class "____A" (4 underscores). If both of these classes have some internal variable __x, how would their mangled names be handled?
Great vid. Will say you missed a potential solution where you prefix the variables with a namespace like in C or ObjC. It’s not great and you do that in those languages of necessity, but it does solve the problem better IMO then manually pre mangling and you don’t have to follow the weird rules of that. Now it’s a bit hair splitting cause depending on how you namespace it’s the same _Class_Var is the same as just mangling but _Module_Class_Var or _pClass_Var is a technically not. It is still not a great solution considering Python is supposed to have built in namespacing, but as an ObjC dev I couldn’t help myself lol
I've seen some JavaScript code that was using IIFEs to create an exported object containing any functions and classes you would like to expose. And for some object attributes it was mangling them with a random string created when the IIFE was running.
i understand the tradeoffs of the different conventions for "private" variables, but i don't understand this last bit at the very end of the video: "in the wild, the most common approach is to use the single underscore and to just hope subclasses don't clobber your implementation details. if you're very good about keeping your classes defined as if they were statically typed, then you could also write a linter rule to help you." what would the linter rule be, and how would it help you with this problem? my guess is that you would just have your linter forbid you from overriding variables, but i dont see why this only makes sense in a context where you've defined your classes as if they were statically typed. id appreciate if anyone could shed some light!
You've got the right idea about the linter rule. As for why it only works if your classes are statically typed, if your classes are not statically typed, how does the linter know what the variables in your class or any of its parents are? If it doesn't know what they are, it can't warn you if there is an overlap. Keep in mind the linter does not run at runtime, so it cannot simply inspect the object in question. Instead, it operates on the source code, typically by computing the AST or CST and checking based off of that.
@@mCoding i still don't understand the problem. lets pretend someone implements a class ClassA which initializes a variable _counter to 0 on all of its instances. if i make a class ClassB that inherits from ClassA, and i initialize _counter as an empty list on all of my ClassB instances, shouldn't this be as much of a visible problem as if i initialized _counter as 100,000 on all of my ClassB instances? regardless of whether my linter can tell what type _counter is supposed to be, it should be able to see that it is being assigned in ClassA and overridden in ClassB, yeah? i must admit i don't know much about linters, so its possible i might just not have the background to understand the problem, but i think its equally possible i might just be misunderstanding the situation to begin with lol
If you TREAT them as private variables, you don't have to worry about any of the [seemingly] weird behaviors. (Other than how it mangles strange class names)
I think maybe this is behind the "bug" I encountered a long time ago. I no longer have the code, and don't recall details. But I was parsing XML. The code worked in the console. It worked in script. It worked when imported by a script. But it did not work when imported by a supporting library... It would run. Just the result of the XML parsing would be empty. IIRC I ultimately got around it by restructuring everything around it so that I didn't need the 2 levels of import to use it...
Python students taught by instructors that do not know better HAVE to fall for this, because those instructors would not know that Python classes do not have true private variables, unlike the languages they know (e.g. Java, C++) Don't ask me how I know. Haha
I discovered it last year in an article written by Dan Bader, and I didn't even think about someone trying to change the attribute using the "wrong" name.
I thought the convention was that a single underscore is supposed to represent a private variable. I don't recall hearing anything about two starting underscores. Edit: just got to the point in the video where he confirms that
So... what would happen, if I imported your Widget example, inherited from it, and my class would also be named Widget, and I also defined a `__count`? Both should mangle to `_Widget__count`. So the mangling wouldn't even meet it's purpose because we chose weird names? Weird.
Although it is certainly bad practice, Python will not stop you from creating two classes with the same name even if one inherits from the other. In this case, even mangled names will clobber each other. Think of it like a punishment for a bad decision. (Unless you didn't know some parent of a parent had the same name, in that case you just got blindsided).
If you inherit from a class and you name the daughter class like the mother class, that is completely on you, my man. Do not complain about hammer's functionality just because you keep hitting your fingers on purpose.
This name mangling is fine, it solves a real world problem. The only issue is with the rare side effects of the poor implementation, for example when modules a mangled (and sometimes not). But they're rare because mangling local variables is not an issue, after all it's already local, who cares of the name python uses to access the locals dictionary. That's why I think it's fine as it solves real world problem, as explained in the video. Speaking of the video, it focuses too much on those side effects that you will never hit, and if you do you can always look it up. I'm afraid that videos like this one deter programmers from python, thinking "wow this language is unpredictable".
@mCoding this seems utterly horrendous. But can it be made even more horrendous by combining with __slots__ ? And if so, how would such a monstrosity work?
@@mCoding I've also just seen someone combining it with slots and metaclasses and... wow. Just wow. So hurried to see if they could, they never stopped to ask if they should.
I tipically use name mangling in my projects and I've never had any issues with it regarding bugs or unpredictable code. But I guess that's just because I wasnt a moron that despite knowing those variables shouldnt be touched outside the class still attempted to do so...
If you treat it genuinely like a private field, then it kind of works. You just need to know that private things exist. But yeah I remember seeing the mangled name in my debugger for the first time. Wild…
You're right that class fields can also cause beginners confusion, though I did that here just to make the thumbnail less cluttered. Perhaps I should update it... Anyway, to answer your question, no you don't need to define a constructor because the base class object has a default one that does nothing, although in most classes you would typically want to do more than nothing.
I've never liked embedding semantic information into variable names, feels old-fashioned a little like Hungarian notation.. This feels like a funny way to build around something that is already not great. Are there channels similar to this one which detail quirks of other common programming languages like Java?
If I want to set a variable with a big "don't touch me" sign, I would also write a setter method that return an RuntimeError every time you try to set the variable. To me, single underscore variable means "this variable is for this class/instance and not accesible to other classes or intances of other classes". I know that that is not the correct use of the single underscore, but in general I'm the only one who touches my own code, so I know what I'm doing. Also, I may also write a comment over that protected variable explaining to myself why I didn't want that variable to be changed when I wrote it.
Seems like any use of a variable starting with double underscore other than "self.__foo" in the class definition should be an error.... (or warning.) Is there a function that returns the mangled name as a string, given a variable or property? (For setattr()/getattr(), debug messages, etc.)
I don't think they expose the official function, though you can feel free to copy the one from this video (and maybe optimize it a bit). I wrote it by going line by line though what the CPython implementation does and translating it to pure Python.
I never actually fell for this one. Mostly working with my own libraries, if I needed a private variable exposed, either I would make it not private or just add a getter/setter for it.
I have been learning and using Python for 4+ years. And even teaching an intro class a few times. And I run into new issues all the time. Right now I struggle with relative imports just because I wanted to be fancy and skip copying code. Two days later I was forced to figure out packaging and refactored a lot of the script I had to now have a module of utils. Feels good, but I still haven't solve my initial issues of reusing a complex function elsewhere. Can't import that anymore because it imports the relative utils package now -.-
Damn I knew about this and thought it probably makes sense as a middle ground between true private and no safeguarding at all, but never realized how many rough edges it has...
interesting overview, but i do use double underscore myself to denote private(although this is making me rethink that). On the one hand, I think you should NOT be able to access a variable that is suppose to be private from outside the class (which double underscore accomplishes), however on the otherside here, the ability to write a different double underscore variable from outside the class feels absurd. If we aren't going to get an language based update to block this, then perhaps we need a linter rule to block being able to write to double underscore from outside class implementation.
People in the comments are missing the point completely, and it is in part by how biased the video is. Just don't be stupid. In Python there are no private variables (in the sense of inaccesible) by design, so stop trying to get a behaviour that it is explicitly left out on purpose. _variables are a hint of the programmer: This is used internally by the code, and it is not designed to be used by the user directly, but if you know what you are doing, you may use them from time to time. __variables are another hint: This is really a part of the functionality of the code and should really not be used by users. I really do not understand the problem. I do not go around changing the __repr__ of my class and then complaining "bu... but why is the representation of my class all messed up?? What a terrible implementation!". It is like saying that metaclasses are confusing and useless because you do not know how to use them and they disrupt the expected behaviour: Yeah, that is the design on purpose. __variables, like metaclasses, are features of the language that allow programmers to achieve awesome behaviour that otherwise would be very hard, but they are not the first tool you should pick up, especially if you are a novice.
I don't understand why it is an issue, since private fields are meant to be PRIVATE. If you try to publicly access a field that is private, then it's no wonder that you get unexpected behavior (though, I would have preferred an illegal access exception or something, but that is just my Java brain). So yea, you gotta know what double underscore means and how to use it properly and if you really need to access a private field from a public context, then make sure you know what you're doing. In a way, prefixing the accessor of a private variable with _ in Python is like setting declared private fields to be accessible with reflection in Java. Both make private fields accessible, but they do it in a completely different way.
But you shouldn't get "unexpected behaviour", because that's simply confusing. You should get an error. I shouldn't need to "guess" that i made a mistake, i should know.
I agree. Why would anyone access a "private" field from outside the class? The video creator says every Python developer will fall for this feature. This implies that every Python developer doesn't know what they are doing, at least at some point.
Does this feature suck with all of its quirks and confusion? Yes. But the whole point of it is that you shouldn't think about it when using private variables. The idea is to be responsible. Just don't even try to access private variables of someone else and you'll be fine. You shouldn't be afraid to create private variables in your class because you'll practically never run into the issues mentioned. You SHOULD be afraid as hell when trying to access a private variable of someone else. Basically the confusion with this feature will only be for people who do bad practices in the first place and it's their fault for touching things they know they shouldn't. That being said, i usually use "protected" variables when i want them to not be exposed to users and only use private variables in rare cases when it's really, really important to me that the variable will not be touched by external users
Its not confusing at all if you regard any identiifier that begins with one or two underscores from being untouchable from outside the class, and severely dicipline any coder you catch trying to "reach around" the mangling. If you are trying to access a "psuedo-private" or mangled name then you know you are doing the wrong thing. If you need to access that mangled value, add in a getter/setter function to the class and do it the right way. Python has never pretended to protect you from your own stupidity. If you don't trust yourself to behave, then maybe try C++ or Java instead.
I think the thing folks forget about name mangling is that its like the cover of a switch, it doesn't stop you from using the switch, but it does give you a warning that the switch might do something bad
This also feels like some descriptor hell, because if defined outside of the class its not mangled, and the fact that the names or transformed on get/set of the variable, which would correspond the the behaviour of __get__ and __set__ of descriptors, if they were storing the name as `owner.__name__` + `self.__name__`
Just a feedback, the memes are kinda disrupting my focus and maybe of some other users too, i liked your previous video types, where we had no memes in between jumpscaring, just your serious voice and some serious feature analysis, thanks.
I think the lesson to learn here is that inheriting state in a non-controlled type hierarchy is something to try to avoid. This applies to OOP languages in general, not just Python. With Python having an extra reason for why, this lack of sane way of namespacing member variables across inheritance.
One should NEVER put state in a class to begin with. State is a singleton. There can be only one. Classes are the antithesis of singleton objects. Data can be in classes (where it is also usually misplaced), but state... never.
@@lepidoptera9337 I'm a little confused as to how you are using "state" and "data" in you comment. What I was referring to as "state" is mutable state stored within the instance, like mutable instance variables. When you say "data", do you mean like immutable (or read-only) stuff in the instance?
@@TechSY730 State is the persistent information that controls a program's primary function. Think about protocols between two communicating programs. If the sender requests a transmission, the receiver either has to guarantee reception by design and acknowledge that the data has been received (possibly even with a check sum mechanism) or flag a transmission error. What data is being transmitted is completely irrelevant to the protocol. The relevant state variables are only controlling that the transmission was valid. In a simple protocol that might be half a dozen binary flags, even if a GByte of data is flowing per second. A user interface of a program meant to be used by humans is, in this sense, also a protocol. The user expects that certain inputs produce reliable actions inside the program and he expects feedback about the progress of those actions. Whatever variables are being used to assure that, that is "state". If I click on "Save", I expect the program to save my data, no matter what is in that data. I expect some kind of confirmation that my data has been saved, even if it is subtle. If this doesn't happen, then there will be an extremely unhappy, insecure user. I had to work with programs that did none of that. I won't name names, but it was hell. So, yeah, the meaning of "state" here is NOT the entire content of your memory. State is what is really important and what can only exist once because the "user" only exists once. And this problem isn't just "external" to a program. It is also internal to the way classes communicate with each other. And this is where the problem begins to grow to epic proportions: how do you make sure that state is immutable if anybody can call a state changing member function? Yes, your "state variable" in an object may be local, but your call graph to the member function of that class isn't. Anybody can change your state, anywhere, any time and there is nothing in the syntax of a typical OOP language to prevent that from happening. OOP therefor gives this false sense of security, when in reality the atomizing of state across multiple classes makes it nearly impossible to track the actual state changes without constant analysis of the call graph.
Dunders are \_\_on\_both\_sides\_\_ of the variable name, not the same as name mangling. Don't use dunders for 'private' variables. Name mangling is to prevent (the majority of) *accidental* name shadowing. You're always *allowed* to mess with whatever you want; if you mess with something marked as internal (anything with a leading _, except dunders - which are magic), it's assumed that you have a good reason for doing so and that you understand what you're doing; not unlike C's philosophy, although without the potential for memory unsafety. TL;DR public _internal_but_might_be_useful_to_subclasses __internal_but_specific_to_this \_\_magic__ (powers stuff like len, str, repr, next; public but shouldn't be used directly by user code)
What I'd say to a trainee about name mangling: Just don't. You can probably solve your problems in a better name. Also, a subclass might want to intentionally mess around in it's superclass' internals. That becomes a pain with name mangling. The advantages are basically nil if you have a proper IDE, which will tell you about a variable already in use with the superclass, as well, so IMO that makes it even more useless.
"Explicit is better than implicit, so we threw in a bunch of implicit behavior. Oh, and you'll never be good at Python until you learn all the secret handshakes of the Society of the Idiomatic." Definitely my biggest criticism of Python. Still my favorite language to work in by far, though.
Something funny is going on with more than just the underscores. __count is a class variable. Main successfully references __count as an instance variable. That isn't possible.
Python will find a class variable as a fallback if an instance variable of the given name isn't found on the object. If both an instance variable and class variable are set, the instance variable will be found first.
@@JansthcirlU When you use these variables as if they're actually private (you can only access them from within the class definition), none of the "weird" behavior become a problem, since you won't run into them.
I stopped at 1 minute. This name mangling bit is there to provide private variables. Python doesn't strictly enforce private variables, but I use a convention where one underscore means it's internal and you shouldn't use it, but it's readily available just in case. But seriously, I'm a Python developer who's never had this issue.
8:48 I saw 424242 and immediately thought of b"BBB"... I wonder if you can use metaclasses to make this even worse. (Or maybe make it function "as you'd expect"?)
My first thought was "why is he using double underscore for a variable name? Where did he pick up that strange habit? And: Dunderscore has meaning in Python, you don't do that unless you know what you're doing, in which case: why is this a problem? Anyway: All this is just more reason to NEVER EVER access an class' internal variable directly. The other reasons ofcourse being that manually getting or setting an internal variable bypasses all validation of that value so you're literally creating a bug, and that you use classes *specifically because* you don't want the outside code to be coupled to your code in any other way than the interface you provide for the class.(And yes ofcourse it can be convenient to just access it directly and yes "we are all adults here", and the "one underscore means don't touch" is a nice gimmick, but you go ahead and deploy that strategy for a few years and tell me how it goes as developers come and go in your company and code gets forgotten about and updated and fixed and mutated. It doesn't go well) And yes, this means I have never fallen for this problem. Stop clickbaiting your titles.
If you are making trivial setters and getters, then you are accessing an internal variable directly, you are just making the runtime go around the block twice to do that. Basically all the "objects for idiots" guides are breeding idiots that way. The very reason for a class is to hide what's inside. This pattern doesn't. Of course, once you know that, then your next thought must be this: "Wait a minute... if I am limiting access to an internal variable, then the language stops being Turing complete!". Yep. That's right. OOP takes a Turing complete language and breaks it. That is exactly what it does. ;-)
Wow. I had a use for this feature 3 days ago, and I had long forgotten about it. I just refactored my code so that I no longer had a use for this feature. Maybe I'm better off forgetting it again.
Before I saw this video: If you want to use private variables, do it in C++, not Python. After I saw this video: If you want to use classes, do it in C++, not Python.
Whats confusing in your example is that you use __count as an instance variable but also initialize in as an class variable on A.__count = 0 tldr. the line after class A: should not be there
This pretty much echoes the embolism the more experienced devs have on StackOverflow when a less experienced dev tries to use double underscores in their variable names.
2 роки тому
OMG, thanks for the info! It was frightening before going to bed tonight.. :-O
What about the option where you tell people to not access a property directly and always use the setter/getter and if there is none defined for an attribute, it's because I don't want you to use it and if you do use it, then well, you get to support all the bug tickets from your now-broken code? Is there a reason why I wouldn't want to do that?
Indeed, for a private variable people outside of the class should not attempt to use it or modify it except through mechanisms the author provided. Because python is so dynamic and this feature is so unexpected, people often run into it on accident anyway. E.g. someone writing a subclass may try to modify the variable directly.
Wow. I knew about name-mangling, but it's even worse than I expected. Maybe it has valid uses, but it definitely feels like a half-assed implementation of private variables that opens up far more traps than it solves.
The point isn't to provide private variables, but to prevent name collision in subclasses.
@@aantoniou96 Not true. Read the docs. "it can be used to define class-private instance and class variables"
@@SeanBracks Although the documentation does describe name mangling for creating "class private variables", it's not "private" in the conventional sense that it prevents users from accessing those attributes. The same explanation is also given by the doc's tutorial at section 9.6. "Private Variables", pointing out that the feature is only there for the use of collision avoidance. (yes, their terminology for this subject is all sorts of mixed up)
I had to extend some code that was written entirely like this and it was a nightmare. I ended up rewriting it in a new language. It's so infuriating, python is meant to be open and extensible and writing like this is like you're trying to write in C++, it really makes it worse
@@aantoniou96 And yet, it doesn't even achieve that, because you can re-use class names between modules further down the inheritance hierarchy. Not to even that it *is* used as a "soft" way of doing private variables in practice, because the two concepts are not a million miles apart.
You make top tier videos showcasing advanced Python topics. There is just too much beginner videos lying around. Therefore I'm glad to feel challenged by watching your videos
I finally understand why they chose ‘Python’ for the name of the language! It wraps itself around your brain and squeezes all the sense out of you! :)
No Guido chose it because he liked Monty Python's Flying Circus
@@vectoralphaSec 😑
Yes, this is the official, or conscious, explanation :)
He could have chosen 'Parrot' (I know, Parrot is now occupied) or 'Monty'.
@@vectoralphaSec ...and: nerds love monty python, therefore: python is built for nerds. (Which is good in a computer language. You know what is NOT built for nerds? Microsoft office. 'nuf said.)
I remember learning about name mangling in my Intro to OOP class and we all just wished that we didn't have a question about that on the test. It's something that our lecturer told us to try and avoid and just use the convention of "underscore at the start means private - do not touch".
Anyways, another informative and entertaining video from you :D
m_ for member.
@@0neMadGypsy Thats the problem in Python. it doesnt have any way to declare some var as protected. and private doesnt really exist either, because you can use _classname__var to access __var.
Its just convention to not mess with attributes (or methods for that matter) that start with an underscore.
there is nothing stopping anybody from accessing those "private" attributes.
while this seems kinda weird, its kinda nice to have this ability in a scripting language, which python is, because sometimes you want to manipulate some data without using the methods the library gives you and you dont want to do it the right way (which is probably to compile the library yourself with public attributes), because you just want a quick script to do some job, not some high quality solution that will stand the test of time until the universe burns out
you can use _classname_var to access members of an inherited class.
This helps solving some of the puzzles you'll inevitably come up with when trying to solve the obvious resolution order problem arising from multiple inheritance.
In fact, this actually makes dunder variables VERY useful given the adecuate context.
Note that this context is NEVER publicly accessing members not designed for it.
@@0neMadGypsy yeah what this^ guy just wrote
php had __construct class methods builtin as default and the such built in to the oop part,whenever you defined some var with a new class too, you would EXPLICITLY name them so they would get called lol
using those __ because they used to be like that in php and java is just a convention thing people took with them i guess
personally i wouldn't touch python with a 10 foot pole if i didn't have to
languaged with forced indenting are retarded. i don't trust languages that don't use semicolons as line enders, the entire basic-like structure falls flat if it means having to import C libraries for performance lol
I was aware of the initial quirks, but didn't expect it to have so many implications. Thanks for this video; you saved future me a bunch of time.
Except if you're always using these variables as if they're ACTUALLY private, none of these implications matter.
Use them in a sensical way, and you won't ever have an issue.
@@CrapE_DM if anyone else subclasses your class, you have to hope that they know to follow the rules. Otherwise you have left a hidden mine for them to step on. From personal experience, assuming outside users understand things like this is not a good assumption.
I have avoided these headaches by never using double underscore prefixes.. Im likely to keep that habit..
I get the sense that as Python blew up, it’s gotten pressure to have features of other lower level languages.. static typing and private/public attributes. But b/c those were afterthoughts and the solutions were retrofits, we get these wonky implementations.
99 times out of 100 if you reach for the word "class" in python (and you're not using it just like a struct), you're likely doing something wrong. The language just wasn't built for proper OO support so if you're not building a general-purpose library type like pandas dataframe, the whole thing is best avoided.
I'm sure everything will be fixed in Python 4.0 🙃
@@mCoding I dont think so. At least not from how Guido described Python 4.0 when he was on Lex Fridman podcast.
type hint let the wrong people in.
6:26 - this is golden, you've really managed to capture and portray everyones feelings in 3 seconds
Or an even better solution: do not use inheritance from classes that are not interfaces (and thus don't have private fields) at all, and instead use composition, that is better in many ways. Avoid the problem completely basically.
I have definitely encountered this issue before and I am blown away by how much more complicated and weird the behavior is than I realized. My general approach has been to just avoid using the "feature".
it's like metaclass....you may never need it, but if you do: you'll know how to use it by then.
Lately, due to many issues like these, I've been borrowing a lot of principles from functional, while still essentially using OO. For one, I try to make stuff immutable with named tuples or frozen dataclasses. Then I try to think of classes more in terms of types and its variables as defining its uniqueness. If something changes, it's a different instance of that type, so no counters. I've found that most of the time, moving counters out of classes makes for more readable, flexible, and loosely coupled code anyway. And if you learn how to leverage comprehensions, map, any, all, sum, itertools, etc., you often don't need counters. For things like widgets, use the ol' "composition over inheritance" mantra. You don't worry about stepping on any component's toes if you have to access them by their instance name anyway.
What about containers. Functional languages usually have copy-on-write optimizations for modifying them. In python you would need to shallow-copy any data structure (dict, list) when you add or remove anything, killing the performance. How do you get around this?
BTW I find this very interesting, as I also see the huge benefits of such approaches.
Yeah, I like that approach, too. I write a lot of data mangling code, which can get complicated really fast.
I'm a bit fuzzy on the details, but don't frozen dataclasses effectively enforce private variables?
Frozen doesn't make the meners private. It makes them read only. SO once an object is constructed it is immutable. The same as tuples behave.
I knew about name-mangling, but I clicked on this video knowing I'd still learn something new. Had no clue about the mangling rules and was also happy you briefly showed the C code, which I was curious about!
great vid as always, was fun to watch with the editing 🤩
also loved the Star Wars references
Hey sexy, how are ya.
Thank you as always 😀
I've been writing python since 2010, and consider myself a bit of a python expert. I've used name mangling in production... a whopping zero times. I've seen it in libraries only a handful of times. I've used it while messing around and found it kind of useless as long as you follow good hygiene.
The answer to the question "how to avoid clobbering implementation details" is indeed look at the source code. Python is so heavily dynamic that if you feel the need to use _underscore attributes in a subclass, you really do need to know what the parent class is doing.
Well, if you have a variable that you don't want the user to have access too, I think making it private would be a usecase for doing so. The point of making somethng private is to make it more explicit that the variable can't be changed outside of it's scope.
Same; almost never needed it in 12years of using Python. Beginners should avoid this topic completely, simply because they don't need it.
@@steven7936 but that concept does not exist in Python; there is no 'private' and there is no way to prevent access (and there is no reason to do so anyway).
Ive used it where I had euclidean a vector class, and then needed a Gibbs version (complex values for quantum angular momentum)...so with mangling I was able to add a few lines do decide if abs() -> sum(getattr(j, self)**2 for j in 'xyz') or if getattr(j, self)*getattr(j, self).conjugate() was required. very slick.
I learned this a long time ago when I went deeper into the language syntax and semantics.
If I use either _ or __ then it's because i dont want the property to be accessed directly outside of the class.
The key things I learned were to bind it to the class in the constructor and learn how to intuit whether it should be used it or not.
I only use getters and setters in certain circumstances, but if i expect the property to be accessed outside of the class, then there is no point in using either _ or __ and I completely drop the @property decorator.
Personally, I abide by always binding properties to the class. I see no rationale for placing it outside of the constructor for the very reasons mentioned in this video.
Regardless, this is A+ material and I enjoyed the deep dive as it was a refresher for something I learned years ago.
changing instance attributes outside its own instance methods is a sin.
easy to avoid - don't use double underscores on class variable names if you plan to use them outside of the class.
Thank you so much. I've spent half a day once trying to figure out what the hell is going on when one of the classes used different implementations of one of the functions depending on the conditions (self.__run_command = run_command_locally if local_machine else run_command_via_ssh). It was quite hellish exercise, until I found it out in a hard way. Switched to single underscore.
The name mangling feature is weird and widely unknown. And it has a serious Silent Fail problem!
Doesn't the current convention say that if you want to protect fields then use only one underscore at the beginning?
Just don't touch underscored vars from outside. It is for a reason that they are considered to be private.
The main thing name-mangling is legitimately used to avoid name collisions in code that needs to be able to subclass arbitrary types or otherwise inject some sort of extra management attribute into an object of an unknown type.
I have heard that the single underscore is preferred because you don't know how your classes are going to be used. Using double underscores ("private" variables) makes classes that have them unfriendly.
This is the most Python thing I've ever heard. You should know how your classes are supposed to be used (I mean, you designed and wrote them...), and should structure them such that they can only be used in valid ways - or at least such that it's difficult and obvious when you're using them in an unintended way.
The funny thing is I fell for that in the worst place possible. In my interview.
May your career rest in peace lol. Just kidding, now you know, get back up and try again!
Any interview that tests you on that is absolutely stupid. Interviews should not try to trick you or test whether you know some inane detail such as this, because it has no bearing on how competent you are as a developer.
@@davepruitt agreed. but it was just one question. there were more. other questions weren't that bad.🥺
What SHOULD happen, if it were designed properly, is an attempt to access the "private" variable __count would throw an exception for an access violation. This would put python in the same camp as other languages that have public and private keywords for class variables. Instead, it just mangles the name and it's on the programmer(s) to play nice and not abuse or work around it.
no, people should just learn the language instead of trying to copy Java. Why would you make something 'private' anyway? in some languages it makes sense, but not in Python: name conflicts are extremely rare in Python because it has Modules. instead of using getters/setters every real Python dev uses @property or writes custom descriptors. Learn to use the __set__ special method.
Guido van Rossum is very clever. That ends up being the source of a lot of python quirks like this.
This is definitely a very clever way of implementing private variables in python with minimal overhead. In practice it turns out that people just never use it because its behavior is too strange. It's also difficult to figure out what would be a better solution given the design constraints of the language (that every object is basically just a dictionary of key value pairs). Somehow adding real private scopes seems "unpythonic", although I can't explain why.
I think a lot of the confusion end up because the behavior results from a "magic" naming convention. Python doesn't really like adding keywords for stuff like this, but I can't help but think if name mangling was somehow linked to a "private" qualifier, that this confusion would not exist. That would have a drawback too though, in that you would have to qualify all uses of the field with "private". That's essentially what python already does actually, except they spell "private" (confusingly) as "__".
Real privacy is unpythonic because it's assumed that the programmer isn't trying to fuck themselves over intentionally. Getting/setting an _varname is basically telling the library that you think you know what you're doing, and if you really want to shoot yourself in the foot, then that's your right.
use properties for getters and setters:
class A:
__count = 42
@property
def count(self):
return self.__count
@count.setter
def count(self, value):
self.__count = value
Now if you repeat that code in sub class:
class B(A):
__count = -999
@property
def count(self):
[etcetera]
then:
.>>> a, b = A(), B()
>>> a.count, b.count
42, -999
each class has a truly private unmangled count read/write public attribute that don't collide.
Least clickbait title ever, A+
By clicking the video you have fallen for the trap, as advertised. It follows that the title was accurate. Maybe I should put something about mangling in there just so it is more searchable....
ERROR: video object has no attribute __title, did you mean _video__title?
I did know about this, but the details get fuzzy after a while. I think the solution whenever possible is to use composition instead of inheritance, anyways.
I love that for every rule you introduce, you sound increasingly embarrassed that they exist
Always thought: no underscore == public; single underscore == protected; double underscore == private. Don't see what the problem is.
Also, can be thought as: no underscore == stable; single underscore == internal, can be changed at any time; double underscore == don't touch me.
In my ten years programming in python name mangling has never been a problem.
How does the run-time naming handle conflicts between mangled names? If the mangled name ignores leading underscores in class names, could you not have some class "_____A" (5 underscores) and another class "____A" (4 underscores). If both of these classes have some internal variable __x, how would their mangled names be handled?
Great vid. Will say you missed a potential solution where you prefix the variables with a namespace like in C or ObjC. It’s not great and you do that in those languages of necessity, but it does solve the problem better IMO then manually pre mangling and you don’t have to follow the weird rules of that. Now it’s a bit hair splitting cause depending on how you namespace it’s the same _Class_Var is the same as just mangling but _Module_Class_Var or _pClass_Var is a technically not. It is still not a great solution considering Python is supposed to have built in namespacing, but as an ObjC dev I couldn’t help myself lol
I've seen some JavaScript code that was using IIFEs to create an exported object containing any functions and classes you would like to expose. And for some object attributes it was mangling them with a random string created when the IIFE was running.
You just flipped my world and I'm surprised I never ran into this issue before. Must be because I rarely ever use classes.
i understand the tradeoffs of the different conventions for "private" variables, but i don't understand this last bit at the very end of the video:
"in the wild, the most common approach is to use the single underscore and to just hope subclasses don't clobber your implementation details. if you're very good about keeping your classes defined as if they were statically typed, then you could also write a linter rule to help you."
what would the linter rule be, and how would it help you with this problem? my guess is that you would just have your linter forbid you from overriding variables, but i dont see why this only makes sense in a context where you've defined your classes as if they were statically typed.
id appreciate if anyone could shed some light!
You've got the right idea about the linter rule. As for why it only works if your classes are statically typed, if your classes are not statically typed, how does the linter know what the variables in your class or any of its parents are? If it doesn't know what they are, it can't warn you if there is an overlap. Keep in mind the linter does not run at runtime, so it cannot simply inspect the object in question. Instead, it operates on the source code, typically by computing the AST or CST and checking based off of that.
@@mCoding i still don't understand the problem. lets pretend someone implements a class ClassA which initializes a variable _counter to 0 on all of its instances. if i make a class ClassB that inherits from ClassA, and i initialize _counter as an empty list on all of my ClassB instances, shouldn't this be as much of a visible problem as if i initialized _counter as 100,000 on all of my ClassB instances? regardless of whether my linter can tell what type _counter is supposed to be, it should be able to see that it is being assigned in ClassA and overridden in ClassB, yeah?
i must admit i don't know much about linters, so its possible i might just not have the background to understand the problem, but i think its equally possible i might just be misunderstanding the situation to begin with lol
I've always felt a little bad not using `__` on my instance variables, but apparently this feature isn't all its cracked up to be lol
If you TREAT them as private variables, you don't have to worry about any of the [seemingly] weird behaviors. (Other than how it mangles strange class names)
"Well, let me introduce you to the questionable feature behind all of this confusion: classes"
I think maybe this is behind the "bug" I encountered a long time ago. I no longer have the code, and don't recall details. But I was parsing XML. The code worked in the console. It worked in script. It worked when imported by a script. But it did not work when imported by a supporting library... It would run. Just the result of the XML parsing would be empty. IIRC I ultimately got around it by restructuring everything around it so that I didn't need the 2 levels of import to use it...
Python students taught by instructors that do not know better HAVE to fall for this, because those instructors would not know that Python classes do not have true private variables, unlike the languages they know (e.g. Java, C++)
Don't ask me how I know. Haha
Who are these people naming stuff with double underscore if they didn't intend to name mangle!
I discovered it last year in an article written by Dan Bader, and I didn't even think about someone trying to change the attribute using the "wrong" name.
I thought the convention was that a single underscore is supposed to represent a private variable. I don't recall hearing anything about two starting underscores.
Edit: just got to the point in the video where he confirms that
So... what would happen, if I imported your Widget example, inherited from it, and my class would also be named Widget, and I also defined a `__count`?
Both should mangle to `_Widget__count`. So the mangling wouldn't even meet it's purpose because we chose weird names?
Weird.
Can you even do class Animal(Animal): ...?
Although it is certainly bad practice, Python will not stop you from creating two classes with the same name even if one inherits from the other. In this case, even mangled names will clobber each other. Think of it like a punishment for a bad decision. (Unless you didn't know some parent of a parent had the same name, in that case you just got blindsided).
class Widget(module.Widget):
# ouch
If you inherit from a class and you name the daughter class like the mother class, that is completely on you, my man. Do not complain about hammer's functionality just because you keep hitting your fingers on purpose.
This name mangling is fine, it solves a real world problem.
The only issue is with the rare side effects of the poor implementation, for example when modules a mangled (and sometimes not). But they're rare because mangling local variables is not an issue, after all it's already local, who cares of the name python uses to access the locals dictionary.
That's why I think it's fine as it solves real world problem, as explained in the video. Speaking of the video, it focuses too much on those side effects that you will never hit, and if you do you can always look it up. I'm afraid that videos like this one deter programmers from python, thinking "wow this language is unpredictable".
@mCoding this seems utterly horrendous. But can it be made even more horrendous by combining with __slots__ ? And if so, how would such a monstrosity work?
Indeed it can be made more horrendous using slots, you end up with mangled slot names. I dare not post such cursed dark magic in the clear web.
@@mCoding I've also just seen someone combining it with slots and metaclasses and... wow. Just wow. So hurried to see if they could, they never stopped to ask if they should.
I tipically use name mangling in my projects and I've never had any issues with it regarding bugs or unpredictable code.
But I guess that's just because I wasnt a moron that despite knowing those variables shouldnt be touched outside the class still attempted to do so...
Man, I thought I understood this. Thanks for disabusing me of that misconception.
If you treat it genuinely like a private field, then it kind of works. You just need to know that private things exist.
But yeah I remember seeing the mangled name in my debugger for the first time. Wild…
This is a very informative yet, a very funny video, nice one james.
This applies to "private" methods as well
This is so awesome! So thorough but simply shown
After working with a strict language, it's incredibly hard to understand how Python works in many cases.
I thought the problem was it being a class field instead of an instance member.. Do you not need a constructor? maybe I don't know enough python
You're right that class fields can also cause beginners confusion, though I did that here just to make the thumbnail less cluttered. Perhaps I should update it...
Anyway, to answer your question, no you don't need to define a constructor because the base class object has a default one that does nothing, although in most classes you would typically want to do more than nothing.
I've never liked embedding semantic information into variable names, feels old-fashioned a little like Hungarian notation.. This feels like a funny way to build around something that is already not great.
Are there channels similar to this one which detail quirks of other common programming languages like Java?
If I want to set a variable with a big "don't touch me" sign, I would also write a setter method that return an RuntimeError every time you try to set the variable. To me, single underscore variable means "this variable is for this class/instance and not accesible to other classes or intances of other classes". I know that that is not the correct use of the single underscore, but in general I'm the only one who touches my own code, so I know what I'm doing.
Also, I may also write a comment over that protected variable explaining to myself why I didn't want that variable to be changed when I wrote it.
Seems like any use of a variable starting with double underscore other than "self.__foo" in the class definition should be an error.... (or warning.) Is there a function that returns the mangled name as a string, given a variable or property? (For setattr()/getattr(), debug messages, etc.)
I don't think they expose the official function, though you can feel free to copy the one from this video (and maybe optimize it a bit). I wrote it by going line by line though what the CPython implementation does and translating it to pure Python.
I never actually fell for this one. Mostly working with my own libraries, if I needed a private variable exposed, either I would make it not private or just add a getter/setter for it.
God I stuck on this bug once for days in Pygame where layers are set in the exact same way
I have been learning and using Python for 4+ years. And even teaching an intro class a few times.
And I run into new issues all the time. Right now I struggle with relative imports just because I wanted to be fancy and skip copying code. Two days later I was forced to figure out packaging and refactored a lot of the script I had to now have a module of utils. Feels good, but I still haven't solve my initial issues of reusing a complex function elsewhere. Can't import that anymore because it imports the relative utils package now -.-
I feel like if you need name mangling functionality, name-space your private methods/members by manually mangling instead so there's no dark magic
I took a deep breath with you.
As I used to know in earlier versions of python when you tries to reassign any strictly private property in a class you will get the error!
I feel like a deep understanding of this would prevent tens of hours of struggling. But I know I’m going to have to learn this the hard way
"buuuut your code looks horrible, and your co-workers hate you" :))))
The video started like something obvious, but actually I didn't know that "mangle" works so weird.
One more reason to choose functions over classes whenever possible 😀
Damn I knew about this and thought it probably makes sense as a middle ground between true private and no safeguarding at all, but never realized how many rough edges it has...
interesting overview, but i do use double underscore myself to denote private(although this is making me rethink that). On the one hand, I think you should NOT be able to access a variable that is suppose to be private from outside the class (which double underscore accomplishes), however on the otherside here, the ability to write a different double underscore variable from outside the class feels absurd. If we aren't going to get an language based update to block this, then perhaps we need a linter rule to block being able to write to double underscore from outside class implementation.
Private variables do not exist in Python. You are able to access everything by design. This is all about avoiding accidental name collisions.
To be fair in other languages nefarious authors can still access private fields via reflection (java), memory transmutation (rust), etc.
Woooa, I knew about this feature, but I didnt know how cursed is it. You can fell into this even if u don't use "private" variables.
So do we use __x for sudo "private" variables or should we just omit them entirely and have everything public by default like always.
Just use a single underscore.
It obviously prevents suckers like James to access the “private” variable so I call this feature a huge win.
pseudo
People in the comments are missing the point completely, and it is in part by how biased the video is.
Just don't be stupid.
In Python there are no private variables (in the sense of inaccesible) by design, so stop trying to get a behaviour that it is explicitly left out on purpose.
_variables are a hint of the programmer: This is used internally by the code, and it is not designed to be used by the user directly, but if you know what you are doing, you may use them from time to time.
__variables are another hint: This is really a part of the functionality of the code and should really not be used by users.
I really do not understand the problem. I do not go around changing the __repr__ of my class and then complaining "bu... but why is the representation of my class all messed up?? What a terrible implementation!".
It is like saying that metaclasses are confusing and useless because you do not know how to use them and they disrupt the expected behaviour: Yeah, that is the design on purpose.
__variables, like metaclasses, are features of the language that allow programmers to achieve awesome behaviour that otherwise would be very hard, but they are not the first tool you should pick up, especially if you are a novice.
exactly.
So many people expect Java-like behavior because they never actually read the Python manuals.
Your channel is awesome!
Thanks so much!
I don't understand why it is an issue, since private fields are meant to be PRIVATE. If you try to publicly access a field that is private, then it's no wonder that you get unexpected behavior (though, I would have preferred an illegal access exception or something, but that is just my Java brain). So yea, you gotta know what double underscore means and how to use it properly and if you really need to access a private field from a public context, then make sure you know what you're doing.
In a way, prefixing the accessor of a private variable with _ in Python is like setting declared private fields to be accessible with reflection in Java. Both make private fields accessible, but they do it in a completely different way.
But you shouldn't get "unexpected behaviour", because that's simply confusing. You should get an error. I shouldn't need to "guess" that i made a mistake, i should know.
@@badoli1074 - that's the IDE's job -- not Python's.
I agree. Why would anyone access a "private" field from outside the class? The video creator says every Python developer will fall for this feature. This implies that every Python developer doesn't know what they are doing, at least at some point.
Does this feature suck with all of its quirks and confusion? Yes. But the whole point of it is that you shouldn't think about it when using private variables.
The idea is to be responsible. Just don't even try to access private variables of someone else and you'll be fine. You shouldn't be afraid to create private variables in your class because you'll practically never run into the issues mentioned. You SHOULD be afraid as hell when trying to access a private variable of someone else.
Basically the confusion with this feature will only be for people who do bad practices in the first place and it's their fault for touching things they know they shouldn't.
That being said, i usually use "protected" variables when i want them to not be exposed to users and only use private variables in rare cases when it's really, really important to me that the variable will not be touched by external users
Its not confusing at all if you regard any identiifier that begins with one or two underscores from being untouchable from outside the class, and severely dicipline any coder you catch trying to "reach around" the mangling. If you are trying to access a "psuedo-private" or mangled name then you know you are doing the wrong thing. If you need to access that mangled value, add in a getter/setter function to the class and do it the right way. Python has never pretended to protect you from your own stupidity. If you don't trust yourself to behave, then maybe try C++ or Java instead.
I think the thing folks forget about name mangling is that its like the cover of a switch, it doesn't stop you from using the switch, but it does give you a warning that the switch might do something bad
This also feels like some descriptor hell, because if defined outside of the class its not mangled, and the fact that the names or transformed on get/set of the variable, which would correspond the the behaviour of __get__ and __set__ of descriptors, if they were storing the name as `owner.__name__` + `self.__name__`
newbie developer here; can I just not use __ in my class variables? Feels like it's just adding more headaches than its worth.
You can, just be aware of the tradeoffs and then you won't be surprised by any of this mangling
yes. it is actually very good.
1:23 what's that R🖊 icon shown near the line number 32's gutter in the pycharm?
Just a feedback, the memes are kinda disrupting my focus and maybe of some other users too, i liked your previous video types, where we had no memes in between jumpscaring, just your serious voice and some serious feature analysis, thanks.
I think the lesson to learn here is that inheriting state in a non-controlled type hierarchy is something to try to avoid.
This applies to OOP languages in general, not just Python.
With Python having an extra reason for why, this lack of sane way of namespacing member variables across inheritance.
One should NEVER put state in a class to begin with. State is a singleton. There can be only one. Classes are the antithesis of singleton objects. Data can be in classes (where it is also usually misplaced), but state... never.
@@lepidoptera9337 I'm a little confused as to how you are using "state" and "data" in you comment.
What I was referring to as "state" is mutable state stored within the instance, like mutable instance variables.
When you say "data", do you mean like immutable (or read-only) stuff in the instance?
@@TechSY730 State is the persistent information that controls a program's primary function. Think about protocols between two communicating programs. If the sender requests a transmission, the receiver either has to guarantee reception by design and acknowledge that the data has been received (possibly even with a check sum mechanism) or flag a transmission error. What data is being transmitted is completely irrelevant to the protocol. The relevant state variables are only controlling that the transmission was valid. In a simple protocol that might be half a dozen binary flags, even if a GByte of data is flowing per second.
A user interface of a program meant to be used by humans is, in this sense, also a protocol. The user expects that certain inputs produce reliable actions inside the program and he expects feedback about the progress of those actions. Whatever variables are being used to assure that, that is "state". If I click on "Save", I expect the program to save my data, no matter what is in that data. I expect some kind of confirmation that my data has been saved, even if it is subtle. If this doesn't happen, then there will be an extremely unhappy, insecure user. I had to work with programs that did none of that. I won't name names, but it was hell.
So, yeah, the meaning of "state" here is NOT the entire content of your memory. State is what is really important and what can only exist once because the "user" only exists once. And this problem isn't just "external" to a program. It is also internal to the way classes communicate with each other. And this is where the problem begins to grow to epic proportions: how do you make sure that state is immutable if anybody can call a state changing member function? Yes, your "state variable" in an object may be local, but your call graph to the member function of that class isn't. Anybody can change your state, anywhere, any time and there is nothing in the syntax of a typical OOP language to prevent that from happening. OOP therefor gives this false sense of security, when in reality the atomizing of state across multiple classes makes it nearly impossible to track the actual state changes without constant analysis of the call graph.
Wait, what? I thought we were told emphatically to not use dunder for private variables. Yet they have deliberate features for it?
Dunders are \_\_on\_both\_sides\_\_ of the variable name, not the same as name mangling. Don't use dunders for 'private' variables.
Name mangling is to prevent (the majority of) *accidental* name shadowing. You're always *allowed* to mess with whatever you want; if you mess with something marked as internal (anything with a leading _, except dunders - which are magic), it's assumed that you have a good reason for doing so and that you understand what you're doing; not unlike C's philosophy, although without the potential for memory unsafety.
TL;DR
public
_internal_but_might_be_useful_to_subclasses
__internal_but_specific_to_this
\_\_magic__ (powers stuff like len, str, repr, next; public but shouldn't be used directly by user code)
What I'd say to a trainee about name mangling: Just don't. You can probably solve your problems in a better name.
Also, a subclass might want to intentionally mess around in it's superclass' internals. That becomes a pain with name mangling.
The advantages are basically nil if you have a proper IDE, which will tell you about a variable already in use with the superclass, as well, so IMO that makes it even more useless.
A really good break down of the issue. Thank you☺
5:00 I feel thrown back to JavaScript's evaluation of values and how the weirdest shit can end up as false, true or just a string...
"Explicit is better than implicit, so we threw in a bunch of implicit behavior. Oh, and you'll never be good at Python until you learn all the secret handshakes of the Society of the Idiomatic."
Definitely my biggest criticism of Python. Still my favorite language to work in by far, though.
Something funny is going on with more than just the underscores. __count is a class variable. Main successfully references __count as an instance variable. That isn't possible.
Python will find a class variable as a fallback if an instance variable of the given name isn't found on the object. If both an instance variable and class variable are set, the instance variable will be found first.
@@mCoding That's weird. It should throw an attribute error. By, "should," of course I mean: logic would dictate.
I have known about name mangling for a while and I honestly don't think that the details are that bad, nor have I ever been confused by it.
Same here. But I also would never use it in my code anyway
you must be VERY smart, wow
@@JansthcirlU When you use these variables as if they're actually private (you can only access them from within the class definition), none of the "weird" behavior become a problem, since you won't run into them.
I stopped at 1 minute. This name mangling bit is there to provide private variables. Python doesn't strictly enforce private variables, but I use a convention where one underscore means it's internal and you shouldn't use it, but it's readily available just in case.
But seriously, I'm a Python developer who's never had this issue.
8:48 I saw 424242 and immediately thought of b"BBB"...
I wonder if you can use metaclasses to make this even worse. (Or maybe make it function "as you'd expect"?)
class Brain:
def __init__(self):
self.__cells = 0
def get_cells(self):
return self.__cells
brain = Brain()
brain.__cells = 2
print(brain.get_cells())
I lol'd
@@mCoding Mission complete!
My first thought was "why is he using double underscore for a variable name? Where did he pick up that strange habit? And: Dunderscore has meaning in Python, you don't do that unless you know what you're doing, in which case: why is this a problem?
Anyway: All this is just more reason to NEVER EVER access an class' internal variable directly.
The other reasons ofcourse being that manually getting or setting an internal variable bypasses all validation of that value so you're literally creating a bug, and that you use classes *specifically because* you don't want the outside code to be coupled to your code in any other way than the interface you provide for the class.(And yes ofcourse it can be convenient to just access it directly and yes "we are all adults here", and the "one underscore means don't touch" is a nice gimmick, but you go ahead and deploy that strategy for a few years and tell me how it goes as developers come and go in your company and code gets forgotten about and updated and fixed and mutated. It doesn't go well)
And yes, this means I have never fallen for this problem. Stop clickbaiting your titles.
If you are making trivial setters and getters, then you are accessing an internal variable directly, you are just making the runtime go around the block twice to do that. Basically all the "objects for idiots" guides are breeding idiots that way. The very reason for a class is to hide what's inside. This pattern doesn't. Of course, once you know that, then your next thought must be this: "Wait a minute... if I am limiting access to an internal variable, then the language stops being Turing complete!". Yep. That's right. OOP takes a Turing complete language and breaks it. That is exactly what it does. ;-)
This video seems like you rage quite a project and just had to vent in the most productive way possible
Wow. I had a use for this feature 3 days ago, and I had long forgotten about it. I just refactored my code so that I no longer had a use for this feature. Maybe I'm better off forgetting it again.
I wasn't aware of this, but it makes me glad that I don't start my member variables with __.
Before I saw this video: If you want to use private variables, do it in C++, not Python.
After I saw this video: If you want to use classes, do it in C++, not Python.
Moral of the story: Avoid using leading or trailing underscores for names whenever possible!
No? That is not it at all?
@@JackDespero read my post again.
Whats confusing in your example is that you use __count as an instance variable but also initialize in as an class variable on A.__count = 0
tldr. the line after class A: should not be there
This pretty much echoes the embolism the more experienced devs have on StackOverflow when a less experienced dev tries to use double underscores in their variable names.
OMG, thanks for the info!
It was frightening before going to bed tonight.. :-O
What about the option where you tell people to not access a property directly and always use the setter/getter and if there is none defined for an attribute, it's because I don't want you to use it and if you do use it, then well, you get to support all the bug tickets from your now-broken code? Is there a reason why I wouldn't want to do that?
Indeed, for a private variable people outside of the class should not attempt to use it or modify it except through mechanisms the author provided. Because python is so dynamic and this feature is so unexpected, people often run into it on accident anyway. E.g. someone writing a subclass may try to modify the variable directly.
My brain is now positively mangled after watching this.
You better see a __private practitioner!