This does exist in the form of "shebang" lines (#!/usr/bin/env python at the top of a script indicates on linux-like systems that this is a script meant to be run by calling /usr/bin/env python script), though these are not portable (particularly to windows) and they do not solve the issue of global variables mentioned in the video. However, combined with the def main if name main idiom, a shebang line can further signal that this is a script and improve clarity for the reader. Documentation is, of course, another great thing to have, though whether your code is documented is a somewhat orthogonal fight to fight :)
@@mCoding they are portable on windows as "py" extension are linked to py.exe wrapper in default cpython setup, which reading the hashbang and executing the mentioned python version
@@s.i.m.c.a the difference is you can't run python script without .py extension on Windows, because Windows decides which program to pass the path of a script file as first argument by its extension, file association registered once until it's changed by user or a program.
I was using this for years for the same reason. And the reason why I clicked this video - I already forgot why I started using it in the first place. Useful sometimes to just get back to where it all started
Another reason is that code inside functions actually runs faster (in CPython), since the used Opcodes are `STORE_FAST` and not `STORE_GLOBAL`. That is very noticeable in scripts that do a lot of loops for example.
@@BRLN1 if you have any time-crucial for-loops being interpreted by CPython then that's _game over_ already right there, never mind function scope vs global scope. Porting the crucial parts to a compiled language (or a library already implemented in another language) will bring _much_ more performance improvement than anything inside CPython. In some cases the (JIT-) compiled language can be Numba, which is easy to do from Python.
this stuff is great for someone who has learnt to code at uni, but you just get chucked in the deep end. see stuff like this everywhere but don't know what it means. great explanation
I am learning python and saw this in various places but didn't know what it did or why I should use it. Now I finally understand the reasoning behind it and why it should be used. Seems like this is something that should be explained by anyone who is going to teach python to others.
It's fun once you start in a bigger project. I did one for college and learnt alot as I went along it. You also learn things not to do in the future. Enjoy the journey!!
I really appreciate your vids and that you go the extra mile of example and explanation. 99% of tutorials show a cursory overview of some new shiny library or module, scattering global variable spaghetti to the four corners of your code base. In these days of stackoverflow copy pasta, your vids remind us that frequently more elegant and reliable implementations are not always 200% more effort.
Another reason to use a main function is it makes it easy to turn a script into a library. At one point, I made a script with a custom class. Then, in another script, I realized that class would be really useful. Since the first one had a main function, I could simply import that class from the first script.
You could have also mentioned "test driven programming": In test driven programming first some test code is written, which will check whether the main() function does what it is supposed to do. Having all important code in functions is needed to make it callable from those outside test modules. pytest is a great library which aids the test driven approach to programming.
I'm new to programming and I did come across projects that rely on this. Where do you think I can learn more about this test driven approach, specifically for python?
@@MaazAhmed My recipe for test driven development (aka TDD) is: 1. Plan your project and define its use-cases 2. Your use-case definitions should be as detailed and precise as possible. Particularly, they should define which inputs under which conditions should produce which outputs. E.g. "If the function log() is called with the parameters 'foo' and 'bar', after its execution there should be a file called 'foo.log' containing the text 'bar'." 3. From these definitions derive the API that you want to test. In the above case, this would be the function log(). As you can see, it should take two parameters of type str (in Python), so its function head should look something like "def foo(filename: str, content: str) -> None:". 4. Add dummy implementations (just the function head + the pass-keyword) in the place where you plan to do the actual implementation 5. Implement your tests so that they call the dummy implementation. One test per use-case should be enough, but you need to identify all use-cases. I.E. maybe the output should be a thrown exception if the user inputs None instead of a str. That would be another use-case. 6. Replace the pass-keyword with the actual implementation and use your already implemented tests, to ensure correctness.
@@scifino1 To clarify, the point of step 5 is to verify that the tests fail when calling the dummy functions, then step 6 verifies that they pass when calling the real ones. Thus, the test is actually correctly testing both sides of what it’s supposed to test. For use cases where doing nothing is the correct behavior, the dummy functions should do something (probably something that would be correct if the inputs had been different).
Another reason to do this is so you can order functions and functionality (except for the trivial and idiomatic if-name-main-main block) top-down, and thus roughly in the order they will call each other, which makes the code much easier to comprehend and understand.
@@mCoding I would probably consider making them smaller, and perhaps near the botton edge of screen. Many people here (including me) are happy with youu because of the straightforward profesional style, and this, in my opinion, slightly ruins it.
@@mCoding Those kept video very entertaining. I've been using this idiom forever and know the reasons but still watched to the end and I think this was why. The flashback to learning java actually made me laugh out loud.
@@mCoding I love them. But I think people who come here via search might consider them inappropriate, especially when the rest of the screen turns darker for a moment and the code is difficult to read due to the change of brightness. I would prefer them to be away from the viewers focus and not effect the rest of the view, so those who are interested can read it but anyone else can ignore it, which is not possible at the moment.
@@mCoding I can see what other people are saying but I like it. If you are going to change it by moving it to the side/bottom, Please leave it up for 1 second longer. I watch all your videos for the content and those blurbs are just a bonus so I'll be here either way. Maybe do a video on some more unwritten rules.
I do the same, but had a different motivation. I like it when I read a file top to bottom that the written order somewhat resembles the execution order. So a main function with high level function calls that describe the entire script will be the first thing you read.
In many languages the opposite is mandatory, requiring as the file is read top to bottom in one pass. In this case all calls must come after their definitions.
im a very new programmer starting a CS degree, my first programming class, once we learned what functions were, this was the first thing he taught us. Ive used it ever since
Thanks, I’ve been writing Python for quite a while and it never came across to me that leaving those variables global is a potential source of bugs. Now I’ll definitely put all those stuffs inside the main function!
Wow, I've been trying to figure that out for so long, and literally nobody I talked to could explain it. Thank you so much for finally clearing up the confusion
Yes, there’s a reason why the “higher learning-curve languages” like Java or C++ have a bigger learning curve than Python. It’s not because the people who designed Java were too dumb to create a language with a small learning curve, but rather because the additional structure of these higher-learning-curve languages is actually useful. We can manually add the additional structure of these more advanced languages to Python to gain the structural advantages, but then Python loses the advantage of being a easy-learn beginner language.
But in this case, is it really easy to learn ? If you can't understand underlying concepts ? As a java dev I can't understand what python does with type, structures, etc.. This video is a good example...
Being easy to learn and having additional structural advantages are not mutually exclusive, there are many "structural advantages" already that can be enabled e.g. 'typing' module and other modules which add certainly more complexity, but also structure. But python is becoming easier... You don't need to be complex to have features.
A less steep learning curve does not mean a lower utility ceiling. The advantage of python isn't that these confusing structures are useless and you'll never need them. It's that _you don't have to start off with them._ It lets you approach programming at a gentler pace, gradually working up to more complicated ideas. That's what learning curve means. The difficulty of each step in the learning process. It doesn't mean there are no complicated things to learn, nor that there's a limit to what the tool can do if you master it.
@@volbla yep, python learning curve is higher than any other programming language, but people mostly missunderstand what learning curve is. Python starts off being so easy, but as you go deep it can go as complex as any other language, for example in java from the start you will need to do what here is exaplain with the 'public static void main(...){...}' in order to just print something in the console, hence the learning curve is not that pronounced
I think I will never not feel horrible(?) whenever I use a dedicated `main` function, even if I understood all of the points you've given. Gotta get over this mindset
@@farris8503 I have it stuck on my head that entrypoint functions are C and Java things. Python doesn't need that. Whenever I see `main` functions, my brain immediately thinks that the code is "smelly" because there's no "need" for that. It "feels" like a "mistake" a beginner would make, who is trying to switch from a C-based language into Python. And it sucks because I know better than that and I'm trying hard to get over it now...
Depends on the types of projects you do. If you only ever write short scripts that are a single file of a few dozen or hundred lines and are never loaded by other scripts, then the benefits of this idiom are greatly reduced and the costs remain. In general, structure scales well but imposes costs on little projects.
As a security engineer, I'm meant to keep things as light as possible since I'm running my scripts 100s of times a day against 200k machines at my company. I'm the backup, I'm the "additional libraries", nobody else maintains/uses my stuff. There's no way I could get away with this, it would just be wasteful additional processing.
It's a single "if" and a function indirection. There's no usecase where you're at the same time using python AND avoiding a single function call is an actual valid performance concern.
Been already 5 months that I started learnint Bioinformatics (i was working a cook for 10 years) and feeling my head wants to blow up, but this realm is amazing! Sooooo much to learn and when finally you start to catch on a new stuff, the feeling is even better than a 200 cover dinner rush!
I work in PyCharm and artist software like Maya simultaneously when I write art tools. Including this helps steamline testing considerably! I will sometimes start roughing things out in Maya's console and then refactor my work in a separate IDE like PyCharm or Rider as a standalone script. I can then continue work in a coding environment but still be able to quickly test in context.
Python programmers: "Other languages are so constraining, forcing you to go through tedious steps to run something." Also python programmers: "We need to have these constrains so our code is easier to understand and to avoid errors."
Constraints can be fine if you need to write something of a size which needs it / something more permanent but can be a pain if you just want to test something. I primarely write c# and find it super annoying to do all the steps I have to do just to test out a new language feature or maybe a library I haven't used before. Just opening a file and writing a short "script" to test it sounds like a dream (even if it had to compile)
C Programmers: "We have to write code mem safe so we don't get any leaks!" Python Programmers: "Garabge Collection" every language has it's positive and negative perks, that's what makes them more individual I guess.
While Python can be written without any classes and functions, it's not recommended for big scale projects. And once you learn classes and functions, it's kinda ez and super neat. I can comeback to code months later, fully understanding it, as opposed to my noobier days, when I had to rewrite code cuz I didn't understand how to work with it after a week
Man, thank you. In my last job, people complained that my scripts were overly-complicated, and pointed at things like defining a main() function instead of just putting it in if __name__=="__main__". I still feel defensive every time I do it but it definitely rocked my self confidence.
Don't let those people get to you :). Even if using a main function didn't prevent all the subtle errors I talked about in this video, taking a chunk of code and refactoring it into a function is usually associated with *simplifying* code, not complicating it. Adding in a single function should not be too complex an operation by any reasonable coder's standard. Of course, if someone didn't make a main function and just used the if check, I probably wouldn't complain.
Good video. I tutor C and found that students find it more intuitive when there's only one main in the project. Lately, I had to explain to someone why, in functional languages (lisp in this case) you don't put "impure" behaviour (or any behaviour) at the top-scope of a given module/namescape. He had a web-request there. He found it much nicer to put everything into the top-scope because Haskell's syntax for main is so ugly. TLDR: I think that enforcing a single point of entry is easier to understand and that just-in-time execution is king (which is besides the point). Have a nice day. :)
as someone who dosent know how to use python or any programming language and isnt learning, your videos are entertaining and informative as to how python and other languages work at a simple level. Update a year later: I just started my computer science degree :)
Crazy how back a year or two I thought I'll never learn this crap. But now I fully understand it. And I usually just write libraries with classes and functions instead of just a script, so I'm good.
One of the things that's always bugs me is the fact that some of Python's best practices, like this one, are so... hideous. It's soured me to the language as a whole.
I learned Python from a very knowledgeable friend. He taught me best practices. At first i ignored all best practices and just wanted to code. After a while i started implementing def and class is my code and while I started adding if name.
This can even be useful for non-scripts as well. I often include a main in library modules that include an example or even test the module. That way an unfamiliar user can can run the file and see how the module behaves and how it to use it.
I was about to write the same. Keeping a "__name__ == '__main__'" as an example of how to properly use my libs has saved many hours of work from my coworkers.
@@wallacevieira8853 bad practice... So if your coworkers forget to remove your "example", they will deploy in production a library with an example embedded... I understand every day more with Python is chosen at my kid school to introduce them to coding...
Another reason to use "if name == main": When you use "if name == main", all your code is wrapped in a function, so all variables are local. Programs that use local variables are faster than those that don't. Therefore, the script with "if name == main" could run several times faster
Thats always kills me, when someone tries to squeeze another tiny bit of performace out of python, slowest language ever. If your python program need that, you did something wrong at the point when you chose python for your task.
if statement doesn't define a function, lol You've gotta learn what a code block and functions are. You could do something like: def main(): # do stuff main() without "if name == main" at all.
@@pawemarsza9515 ofc you're right, but it a little forces you to use main() function. And I think that your "you've gotta learn" phrase sounds offensive =)))
You're better off distinguishing between library modules (imported but not run) and scripts (run but not imported). Then the problem goes away with no need to write extra code. Reminds me of fixing a function getting unexpected null inputs by setting them to a non-empty default -- by guarding against the symptom, you make the root of the illness harder to spot later on. More generally, it's a bad idea to see something happening that "Should Never Happen," and then paper over it with a conditional. (Yes, I know "if main" is conventional in Python. So is the use of exceptions for control flow. Bad ideas are usually popular, and that goes double for Python.)
The multiprocessing reason is the reason why this has become my standard over the years. Took me ages to figure out what was wrong first time I stuffed it up!
One other benefit of using a main function is that it makes your script play nicely with other tools, e.g., setuptools' console_scripts. I'd even go further and say that main() should have no parameters and should only contain stdin and CLI arg handling/parsing/validation code (maybe file handling too). Business logic should either be in an external library, or for single-file scripts, there should be another function that acts as the entry-point for business logic. This way, the script can be used as a library.
So what we learnt here is that the python language hides it's script set-up to make things easier, however there are unspoken rules to its abstraction. Which is why we use c++.
I even recommend this idiom: if ___name___ == '__main__': import sys # only necessary if not yet imported of course sys.exit(main(sys.argv)) This way you can easily write unit test cases for testing your main() function as well and don't need to mock sys.argv or sys.exit(). The main() function then only is supposed to use its argument instead of the global sys.argv and it also just is supposed to return an exit value instead of using sys.exit directly. This also allows wrapping the main() function in some weird cases (call it from somewhere) without too much trouble.
Yup. I was gonna reply and say the same thing, seems sensible to exit with a value. I usually also have a try/except block around ‘sys.exit(main())’ that exits non-zero if an uncaught exception bubbles up. This is critical for utility scripts used in CI and other ‘headless’ setups, otherwise how can you tell if it failed?
While developing, I like to write the code directly in the if block, mainly so that if I run the file in interactive mode, the variables are there for me to inspect and modify to write the next lines. Not something you can do in a main() function without breakpoints.
@@bersK00 To run it directly on the correct version "#!/usr/bin/env python2" or "/usr/bin/env python3" (or old style #!/usr/bin/pythonX"). With the prefix (python2 script.py), the shebang is not used.
Eh... In larger python programs where you have multiple files, sure this could be useful. But I'm certainly not gonna put it "in all [my] Python scripts". Any single-file scripts can easily remain as they are and it keeps them simple.
Make the code clearer and easier to debug. I specifically love it when I write a more complex program with different classes in multi file project. It allows me to test different modules and have different behavior when called as a script or as a module if I want. Thanks for the great explanation, I think this is going to help a lot of people!
@@satunnainenkatselija4478 but thats exacly what everyone does. Why otherwise you think every typical java/c++ "OOP-best-practices" project end up in pile of managers, services, factories and DAO? That takes 1 week and 1000 SLOC to add 1 field to API... We've lived for 2+ decades when "best practice" is to prematurely complicate software and called it "clean architecture", not forget call everything else "spaghetti". Now we're slowly trying to throw that toxic idea away and return to normal programming
I like that I can put the main() function at the top of the script and define the functions that it calls lower down, without worrying about calling a function before it is defined.
I use this in files that have functionality that I want to be able to either import into another script or run from the command line. The main function parses the command arguments and then instantiates classes and runs functions based on those arguments.
@@BlkRider I both agree and disagree to this point. It really comes down to the scope of responsibilities of the code in the file. If the scope is narrow and I can write a very short main function to invoke it from the command line, then I can only see this as a bonus. Anyone looking at the code can now see a working example of how to use the code in the file (in addition to doc strings). If I find that I am rewriting/reusing classes/code from that file that isn't part of the main responsibility. That's when I refactor it into its own file.
I'm just an information scientist who happened to learn some Python in grad school and uses it once in a blue moon for very basic tasks, but even I use this because I was taught this way, even if I didn't know all of the reasons for it. (Well, I don't actually do this in every file; some very basic one-and-done standalones that no-one but me will ever see don't, but I know _why_ they don't need it.) There's usually a reason for traditional ways of doing things in a particular language.
Well I am using the《If __name__ == "__main__"》ideom for years already, but not the 《def main()》part, because I was not aware of the variables being put to the global scope. Knowing this converted me of course, but this a horrific nightmare. I also just see your video on how future variable initializations do alter python's evaluation behaviour. I guess this video is just another manifestation of that other video's matter. I was and still am a huge "fan" of python as it is a convenient and powerful language but these 2 videos changed my mind about python fundamentally.
The first reason I learned about creating the main if statement and the main function was actually for multiprocessing. I use Python for my mathematics hobby with the SymPy module or with SageMath and wanted to utilize all the threads of my CPU.
Super informative! I’ve known about using __main__ but never knew about this kind of problem. But it makes me wonder, is there a way to write functions which can only use variables that were passed to it as an argument (or defined within the function)? ie, the variable i was not passed to the function in the video example, so is there a way to have this result in an Error?
Python has a built-in locals() function that will return a dictionary of all the variables that are within only the function's namespace (i.e. not within globals). This includes any arguments passed to the function. You could use '[variable name] in locals()' to get True or False and throw an error accordingly.
So I guess the move could be to have functions in a separate py file? That would circumvent these types of issues? Not my favorite solution but it sounds like there might not be a clean alternative
it's all just context dependent. If all I have is a little trivial script that has like less than 10 lines of codes in it, why would I explicitly use an entry point? It's pointless, since it's already obvious that this is a script. For more complex programs yeah it's a good habit, you inform the reader of something that was not necessarily obvious at first glance
I've found a main function is also useful when making a tool that can either be used as a library in other projects or executed directly to perform a specific task in isolation. E.g. "convert the given binary file to a .csv" when executed vs only having a convert function when imported
Neat! This beautifully explained some quesstions, that I didn't even know how to ask, from when I first learned Python. Every now and then I'd get unexpected errors or bugs that I couldn't for the life of me deconstruct - and now I finally know! I'm looking forward to your future content and diving into your older stuff. Thank you! - Sincerely, a new subscriber.
As a hardware engineer who just dabbles in Python, but I still put if __name__ == '__main__': in my non-script/library files. It allows me easy file-specific debugging when running the file from the spyder terminal. It also lets me prototype/showcase how the file is supposed to be used. Lastly, it saves me the additional files for unittest, but I can still implement that if I so choose.
Just love cpp so much that I try to make all my python code like cpp Things are not only put in main, but also almost all the var are annotated with type hint
imo a good text editor/ide should be able to tell you the types without you needing to explicitly annotate them, and you don't really care about what the type is for local variables anyway. type annotations for functions, on the other hand, are great for documenting the contract. and cpp also supports type inference (auto keyword).
@@wsrgs4 You do care about the types of local variables. Autocompletion works a lot worse when you don't know the type (though in python you can't even know for sure even with the type). Often you can infer the type from the usage of the variable, but if you use a library without type hints you're out of luck.
@@gamekiller0123 good point about libraries without annotations. but in the case where all functions *are* typed, your editor should be able to infer the type of local variables and provide the correct autocompletions, I would think. I guess I shouldn't have said that one doesn't care about the type, but rather that it doesn't usually need to be explicitly written.
C still wins on the monstrosity potential; int B(void*X){return*(int*)&X;};int(*F(void*A,void*(*F)(void*)))(void*){int(*X)(void*)=&B;X(F(A));return X;}
I've been learning Python for quite some time now, and I've always wondered when I was browsing for code examples etc. why people were doing that basic-looking extra-hoop to jump through in their scripts. Now I know... And knowing is half the battle! *PY JOOOE*
I grew up with Borland: init(); run(); done(); so it makes sense to me. You could create your own idiom, or "top-level super structure", for loading code. It is the precept to OOP, prior to object definition. Borland and Microsoft considered it critical for GUI app development, large code base, and object class structure.
I'm very new to python (not programming). before i had some prejudices but currently i have to say that python is much better than expected. nevertheless the code style is a new world (so videos like this are really helpful here). What I would be interested in is the following: it is great that you can execute every script - so sometimes I write a test function directly under a library function. the problem is that the import of other components is often not working because the starting point in the folder structure is different (because the library-funktion is not in the same folder with the main-script). is there a best practice for this?
It's psychological. With the face on the screen you unconsciously try to make eye contact with that person (although only a video) to suggest that you pay attention. This is why you take your eyes off the screen/code numerous times during the lesson which can distract your brain. Without that other "person" you have nowhere else to look other than the code and you stay more focused.
I've been doing this for some time now. My motivation for doing this was and is to enable the order of code recommended in Clean Code: from high-level to low-level (helper functions), not vice versa. So it's def main(), def helper1(), def helper2(), ... and then if __name__ == ...
Fascinating and useful video. Basically this idiom serves a purpose similar to a C "#define IN_MAIN_C" guard near the top of "main.c", which signals to headers included below that that they're being included in a "main.c" context, rather than, say, "auxilliary.c" or "weather.c". Python makes such context-awareness easier by means of "__name__". (C's preprocessor also has the "__FILE__" macro, but that's not quite as easy to compare to a reference value as "__name__" is in Python.) I'm surprised and disappointed that so few of the people in the comments seem to understand this idiom, and how it differs from other idioms, such as shebangs (which serve a different purpose altogether, namely command-interpreter selection) and file names (which serve to describe what the file _does_ ), whereas "__name__" is for context-awareness (what file we're in, and whether it's the entry-point file). That being said, if-name-main is not really necessary for the kinds of Python scripts I've been writing so-far, as they're all single-file. However, I'll put this idiom at the bottom of some of my longer scripts anyway, as a reminder to myself to use it in any multi-file projects I may do in the future. Thanks for the tip.
I've had less experience with python as I did most of my coding in Java, C and C++. I've only really used it for ML models in Jupyter until recently. Never really thought about the Global scope issue in importing files as I've never had to bother with that with the other languages - you only ever make a variable global if you explicitly need it to be. If this is a problem of global scope in python, then you probably never want to use any global variables, especially in libraries. Good to know.
The single underscore in a variable name actually means that its private to the file / function / class depending on its scope - nothing is stopping you from using it in another script if it's scope is the entire file, but that's not its intention and you are breaking the silent rule. Assigning a value to a single underscore just means you are throwing the value away and you actually can't use it - it's not possible.
Just wanted to add that the 'i' global/local bug isn't just an oopsie. I see it as a sign of negligence that the code wasn't checked after writing it. (with e.g. unit test, peek definition or just highlighting the variable name).
I dunno man, I always treat python like script (replacement of bash and batch), so that thing isn't so useful Also it is a good practice for library to put all logic inside functions, running it directly won't do anything
Thanks for explaining this. I only use python for university stuff, so to me this is just a way to signal my professor that I know what I'm doing (which may or may not actually be the case). I like that the style of explaining with minimum viable examples, it leaves room for discussion and that room is used, as you can see from the other great comments. Usually, I don't care too much about python, but this was a great video. Keep it up and consider me a subscriber!
Great to hear! I also totally agree, my comments contain many gems and great suggestions from other experienced Python programmers! Awesome audience and glad you're part of it!
Couple of quick counter-arguments: Logic behind using __name__ == '__main__' totally works for me, but RE: making a 'main' function for every script, I feel that, 1) this is an unnecessary contrivance for really simple scripts, 2) slightly obscures the logic RE: what is the main workflow of the script (I know it's only one extra level, but, precious seconds, man!) and 3) if the rest of the code is sufficiently modular, would this ever really be needed?
It does come down to opinion, convention, and personal judgement at some level so you aren't wrong per se, but here's what I would retort with. 1) agreed, but simple scripts often turn into not simple scripts, and even a single shadowed variable can break even a simple script, 2) it depends on the reader but i would argue the opposite, main tells the reader this is where the script conceptually begins, like painting the start line for a race. Side note: precious seconds? I recommend abbreviations/template expansion! 3) how can the code be modular if you are doing work in the global scope with global variables leaking into all your function scopes?
@@mCoding Nice response, thanks for your thoughts! RE: use of globals: if I'm just writing a simple script to test out a method or workflow, and I want to e.g. run it a few times and manually vary some parameter(s), I often find it easiest to just chuck a couple of globals at the top so I can easily find and adjust them on each test run. But I take your point, you probably don't want that sort of thing ending up in your production/deployment version of a script! Anyway, really appreciate your helpful explainers, keep up the good work. :)
That's the function deep thought calculated in billions of years... and it's brilliant. Mathematicians say, the easiest looking solutions are the most advanced and elegant ones
I think the main inconvinience of if __name__ == '__main__': is during code development. I usually test the behaviour of smaller code segments in the global namespace, and if the results proves to be robust, then I incoorporate it into the rest of the script. Having everything in the global namespace, allows to very conveniently plot or print the variables of interest into the python shell. Using if __name__ == '__main__': disallows for such convenient access. I know this method of testing clunky seems for a regular python development, but it is insanely usefor for advanced scientific or math implementation. For advanced math implementation one can only check the code via creating purpose built diagnostic plots during software development, because a code can run without yielding appropriate results. Using assert or error handling in themselves are far from sufficients, because only plots could tell how the math went awry, and during testing the diagnostical plots should be run anyway.
I've used python for a while now, and I had no clue about the unwritten rules. Thanks for this
Glad it was helpful!
What about adding a single line on the top like "you can run this as a script"? Oh, and maybe document commands like arguments, if there are any?
This does exist in the form of "shebang" lines (#!/usr/bin/env python at the top of a script indicates on linux-like systems that this is a script meant to be run by calling /usr/bin/env python script), though these are not portable (particularly to windows) and they do not solve the issue of global variables mentioned in the video. However, combined with the def main if name main idiom, a shebang line can further signal that this is a script and improve clarity for the reader. Documentation is, of course, another great thing to have, though whether your code is documented is a somewhat orthogonal fight to fight :)
@@mCoding they are portable on windows as "py" extension are linked to py.exe wrapper in default cpython setup, which reading the hashbang and executing the mentioned python version
@@s.i.m.c.a the difference is you can't run python script without .py extension on Windows, because Windows decides which program to pass the path of a script file as first argument by its extension, file association registered once until it's changed by user or a program.
Reminding me about global variables converted me
Then the video was a success!
me too
I was using this for years for the same reason. And the reason why I clicked this video - I already forgot why I started using it in the first place. Useful sometimes to just get back to where it all started
@@IqweoR hahahaha, that's so true
Another reason is that code inside functions actually runs faster (in CPython), since the used Opcodes are `STORE_FAST` and not `STORE_GLOBAL`. That is very noticeable in scripts that do a lot of loops for example.
Interesting point! I hadn't considered that but I suppose it is yet another benefit of avoiding globals.
On the other hand if you have time crucial "for"-loops in your main routine ... well I would consider that bad style in itself.
I ran a simple "sum a bunch of numbers in a for loop" the global scope was half the speed of the function scoped run! :o
ya smoked some serius cpython sources
@@BRLN1 if you have any time-crucial for-loops being interpreted by CPython then that's _game over_ already right there, never mind function scope vs global scope. Porting the crucial parts to a compiled language (or a library already implemented in another language) will bring _much_ more performance improvement than anything inside CPython. In some cases the (JIT-) compiled language can be Numba, which is easy to do from Python.
this stuff is great for someone who has learnt to code at uni, but you just get chucked in the deep end. see stuff like this everywhere but don't know what it means. great explanation
Thanks for the kind words!
I am learning python and saw this in various places but didn't know what it did or why I should use it. Now I finally understand the reasoning behind it and why it should be used. Seems like this is something that should be explained by anyone who is going to teach python to others.
As someone just starting to learn Python, this gave me a headache :)
I have so much to learn...
Don't worry, you'll make it. Although, im nothing special myself
It's fun once you start in a bigger project. I did one for college and learnt alot as I went along it. You also learn things not to do in the future. Enjoy the journey!!
Don't worry, as long as you believe in yourself, nothing can stop you!
this is me :D let's not give up!
Same...
I really appreciate your vids and that you go the extra mile of example and explanation. 99% of tutorials show a cursory overview of some new shiny library or module, scattering global variable spaghetti to the four corners of your code base. In these days of stackoverflow copy pasta, your vids remind us that frequently more elegant and reliable implementations are not always 200% more effort.
Thanks for noticing! It is hard to convey these subtle issues to a large audience but I'm very happy to see people like you getting the point!
Another reason to use a main function is it makes it easy to turn a script into a library. At one point, I made a script with a custom class. Then, in another script, I realized that class would be really useful. Since the first one had a main function, I could simply import that class from the first script.
You could have also mentioned "test driven programming": In test driven programming first some test code is written, which will check whether the main() function does what it is supposed to do. Having all important code in functions is needed to make it callable from those outside test modules. pytest is a great library which aids the test driven approach to programming.
I'm new to programming and I did come across projects that rely on this. Where do you think I can learn more about this test driven approach, specifically for python?
@@MaazAhmed use your favorite search engine 😉
@@pefu512 haha thought you might know any useful resources, but of course, the search engine's always there. :)
@@MaazAhmed My recipe for test driven development (aka TDD) is:
1. Plan your project and define its use-cases
2. Your use-case definitions should be as detailed and precise as possible. Particularly, they should define which inputs under which conditions should produce which outputs. E.g. "If the function log() is called with the parameters 'foo' and 'bar', after its execution there should be a file called 'foo.log' containing the text 'bar'."
3. From these definitions derive the API that you want to test. In the above case, this would be the function log(). As you can see, it should take two parameters of type str (in Python), so its function head should look something like "def foo(filename: str, content: str) -> None:".
4. Add dummy implementations (just the function head + the pass-keyword) in the place where you plan to do the actual implementation
5. Implement your tests so that they call the dummy implementation. One test per use-case should be enough, but you need to identify all use-cases. I.E. maybe the output should be a thrown exception if the user inputs None instead of a str. That would be another use-case.
6. Replace the pass-keyword with the actual implementation and use your already implemented tests, to ensure correctness.
@@scifino1 To clarify, the point of step 5 is to verify that the tests fail when calling the dummy functions, then step 6 verifies that they pass when calling the real ones. Thus, the test is actually correctly testing both sides of what it’s supposed to test.
For use cases where doing nothing is the correct behavior, the dummy functions should do something (probably something that would be correct if the inputs had been different).
Another reason to do this is so you can order functions and functionality (except for the trivial and idiomatic if-name-main-main block) top-down, and thus roughly in the order they will call each other, which makes the code much easier to comprehend and understand.
This flashing "captions" are VERY funny. Keep 'em coming!
Thanks! I wasn't sure if people would like them or find them annoying! Anyone reading please do let me know!
@@mCoding I would probably consider making them smaller, and perhaps near the botton edge of screen. Many people here (including me) are happy with youu because of the straightforward profesional style, and this, in my opinion, slightly ruins it.
@@mCoding Those kept video very entertaining. I've been using this idiom forever and know the reasons but still watched to the end and I think this was why. The flashback to learning java actually made me laugh out loud.
@@mCoding I love them.
But I think people who come here via search might consider them inappropriate, especially when the rest of the screen turns darker for a moment and the code is difficult to read due to the change of brightness.
I would prefer them to be away from the viewers focus and not effect the rest of the view, so those who are interested can read it but anyone else can ignore it, which is not possible at the moment.
@@mCoding I can see what other people are saying but I like it. If you are going to change it by moving it to the side/bottom, Please leave it up for 1 second longer. I watch all your videos for the content and those blurbs are just a bonus so I'll be here either way. Maybe do a video on some more unwritten rules.
I do the same, but had a different motivation. I like it when I read a file top to bottom that the written order somewhat resembles the execution order. So a main function with high level function calls that describe the entire script will be the first thing you read.
In many languages the opposite is mandatory, requiring as the file is read top to bottom in one pass. In this case all calls must come after their definitions.
@@foodice11 and with the main() call at the very bottom that's no problem
no, the 1st thing you read is the docstring.
im a very new programmer starting a CS degree, my first programming class, once we learned what functions were, this was the first thing he taught us. Ive used it ever since
Thanks, I’ve been writing Python for quite a while and it never came across to me that leaving those variables global is a potential source of bugs. Now I’ll definitely put all those stuffs inside the main function!
british
Wow, I've been trying to figure that out for so long, and literally nobody I talked to could explain it. Thank you so much for finally clearing up the confusion
Yes, there’s a reason why the “higher learning-curve languages” like Java or C++ have a bigger learning curve than Python. It’s not because the people who designed Java were too dumb to create a language with a small learning curve, but rather because the additional structure of these higher-learning-curve languages is actually useful. We can manually add the additional structure of these more advanced languages to Python to gain the structural advantages, but then Python loses the advantage of being a easy-learn beginner language.
But in this case, is it really easy to learn ? If you can't understand underlying concepts ? As a java dev I can't understand what python does with type, structures, etc.. This video is a good example...
Being easy to learn and having additional structural advantages are not mutually exclusive, there are many "structural advantages" already that can be enabled e.g. 'typing' module and other modules which add certainly more complexity, but also structure. But python is becoming easier...
You don't need to be complex to have features.
A less steep learning curve does not mean a lower utility ceiling. The advantage of python isn't that these confusing structures are useless and you'll never need them. It's that _you don't have to start off with them._ It lets you approach programming at a gentler pace, gradually working up to more complicated ideas.
That's what learning curve means. The difficulty of each step in the learning process. It doesn't mean there are no complicated things to learn, nor that there's a limit to what the tool can do if you master it.
@@volbla yep, python learning curve is higher than any other programming language, but people mostly missunderstand what learning curve is. Python starts off being so easy, but as you go deep it can go as complex as any other language, for example in java from the start you will need to do what here is exaplain with the 'public static void main(...){...}' in order to just print something in the console, hence the learning curve is not that pronounced
@@oksatoki you mean lower?
At first i was like this dude wants to flex with fancy looking code, then came global variables in a pickle file. Consider me converted 🙏
Flexing programmers aren't really programmers in my opinion.
I think I will never not feel horrible(?) whenever I use a dedicated `main` function, even if I understood all of the points you've given. Gotta get over this mindset
The feeling goes away fast if you ever waste an hour due to one of the issues!
Interesting, why do you feel that way? For me it's the opposite, going from C to Python it felt really awkward not having a main function.
@@farris8503 I have it stuck on my head that entrypoint functions are C and Java things. Python doesn't need that. Whenever I see `main` functions, my brain immediately thinks that the code is "smelly" because there's no "need" for that. It "feels" like a "mistake" a beginner would make, who is trying to switch from a C-based language into Python. And it sucks because I know better than that and I'm trying hard to get over it now...
@@farris8503 Same here from Java
Depends on the types of projects you do. If you only ever write short scripts that are a single file of a few dozen or hundred lines and are never loaded by other scripts, then the benefits of this idiom are greatly reduced and the costs remain. In general, structure scales well but imposes costs on little projects.
As a security engineer, I'm meant to keep things as light as possible since I'm running my scripts 100s of times a day against 200k machines at my company. I'm the backup, I'm the "additional libraries", nobody else maintains/uses my stuff. There's no way I could get away with this, it would just be wasteful additional processing.
It's a single "if" and a function indirection. There's no usecase where you're at the same time using python AND avoiding a single function call is an actual valid performance concern.
Been already 5 months that I started learnint Bioinformatics (i was working a cook for 10 years) and feeling my head wants to blow up, but this realm is amazing! Sooooo much to learn and when finally you start to catch on a new stuff, the feeling is even better than a 200 cover dinner rush!
Really cool tip. As someone who just uses python as a hobby language, little tips like these are super helpful. Thanks
I work in PyCharm and artist software like Maya simultaneously when I write art tools. Including this helps steamline testing considerably! I will sometimes start roughing things out in Maya's console and then refactor my work in a separate IDE like PyCharm or Rider as a standalone script. I can then continue work in a coding environment but still be able to quickly test in context.
Python programmers: "Other languages are so constraining, forcing you to go through tedious steps to run something."
Also python programmers: "We need to have these constrains so our code is easier to understand and to avoid errors."
Constraints can be fine if you need to write something of a size which needs it / something more permanent but can be a pain if you just want to test something.
I primarely write c# and find it super annoying to do all the steps I have to do just to test out a new language feature or maybe a library I haven't used before. Just opening a file and writing a short "script" to test it sounds like a dream (even if it had to compile)
C Programmers: "We have to write code mem safe so we don't get any leaks!"
Python Programmers: "Garabge Collection"
every language has it's positive and negative perks, that's what makes them more individual I guess.
While Python can be written without any classes and functions, it's not recommended for big scale projects. And once you learn classes and functions, it's kinda ez and super neat. I can comeback to code months later, fully understanding it, as opposed to my noobier days, when I had to rewrite code cuz I didn't understand how to work with it after a week
@@aba22125 agreed
@@aba22125 You didn't understand it, becasue you didn't use classes/functions?
Man, thank you. In my last job, people complained that my scripts were overly-complicated, and pointed at things like defining a main() function instead of just putting it in if __name__=="__main__". I still feel defensive every time I do it but it definitely rocked my self confidence.
Don't let those people get to you :). Even if using a main function didn't prevent all the subtle errors I talked about in this video, taking a chunk of code and refactoring it into a function is usually associated with *simplifying* code, not complicating it. Adding in a single function should not be too complex an operation by any reasonable coder's standard. Of course, if someone didn't make a main function and just used the if check, I probably wouldn't complain.
Good video.
I tutor C and found that students find it more intuitive when there's only one main in the project.
Lately, I had to explain to someone why, in functional languages (lisp in this case) you don't put "impure" behaviour (or any behaviour) at the top-scope of a given module/namescape. He had a web-request there. He found it much nicer to put everything into the top-scope because Haskell's syntax for main is so ugly.
TLDR: I think that enforcing a single point of entry is easier to understand and that just-in-time execution is king (which is besides the point).
Have a nice day. :)
I've been doing Python on the side for personal projects and never even learned this in a college class about the language. Thanks for the info!
You're very welcome!
I was always taught to do this and never understood exactly why, so this was nice to learn.
as someone who dosent know how to use python or any programming language and isnt learning, your videos are entertaining and informative as to how python and other languages work at a simple level.
Update a year later: I just started my computer science degree :)
I've actually been using a dedicated "main" function for a while now.
It just seemed natural to *_not_* put your main code inside an if statement.
Crazy how back a year or two I thought I'll never learn this crap. But now I fully understand it. And I usually just write libraries with classes and functions instead of just a script, so I'm good.
One of the things that's always bugs me is the fact that some of Python's best practices, like this one, are so... hideous. It's soured me to the language as a whole.
*always bugged me
What's wrong with defining a function and calling it like this?
@@LianaStrife435 nothing, it's just visually repulsive in comparison to the rest of the language's simplistic beauty
After a while you'll get more confused if you don't see the if statement than the opposite. It will look for you as a button designed this way
I learned Python from a very knowledgeable friend. He taught me best practices. At first i ignored all best practices and just wanted to code. After a while i started implementing def and class is my code and while I started adding if name.
This can even be useful for non-scripts as well. I often include a main in library modules that include an example or even test the module. That way an unfamiliar user can can run the file and see how the module behaves and how it to use it.
I was about to write the same. Keeping a "__name__ == '__main__'" as an example of how to properly use my libs has saved many hours of work from my coworkers.
This ^^
@@wallacevieira8853 can you elaborate with an example?
Wouldn't it just be easier to write an example in the library documentation?
@@wallacevieira8853 bad practice... So if your coworkers forget to remove your "example", they will deploy in production a library with an example embedded... I understand every day more with Python is chosen at my kid school to introduce them to coding...
This is the best and most complete explanation I've seen on this question.
Another reason to use "if name == main":
When you use "if name == main", all your code is wrapped in a function, so all variables are local. Programs that use local variables are faster than those that don't. Therefore, the script with "if name == main" could run several times faster
Didn’t know that. Thanks!
Thats always kills me, when someone tries to squeeze another tiny bit of performace out of python, slowest language ever.
If your python program need that, you did something wrong at the point when you chose python for your task.
if statement doesn't define a function, lol
You've gotta learn what a code block and functions are. You could do something like:
def main():
# do stuff
main()
without "if name == main" at all.
@@pawemarsza9515 ofc you're right, but it a little forces you to use main() function.
And I think that your "you've gotta learn" phrase sounds offensive =)))
My reason why i started using this is to be able to define functions on lines below where they are used
You're better off distinguishing between library modules (imported but not run) and scripts (run but not imported). Then the problem goes away with no need to write extra code.
Reminds me of fixing a function getting unexpected null inputs by setting them to a non-empty default -- by guarding against the symptom, you make the root of the illness harder to spot later on. More generally, it's a bad idea to see something happening that "Should Never Happen," and then paper over it with a conditional.
(Yes, I know "if main" is conventional in Python. So is the use of exceptions for control flow. Bad ideas are usually popular, and that goes double for Python.)
The multiprocessing reason is the reason why this has become my standard over the years. Took me ages to figure out what was wrong first time I stuffed it up!
One other benefit of using a main function is that it makes your script play nicely with other tools, e.g., setuptools' console_scripts. I'd even go further and say that main() should have no parameters and should only contain stdin and CLI arg handling/parsing/validation code (maybe file handling too). Business logic should either be in an external library, or for single-file scripts, there should be another function that acts as the entry-point for business logic. This way, the script can be used as a library.
The multiprocessing fork bomb really surprised me!
I don't use it cuz it makes my code too readable and doesn't give enough juicy bugs
you are so quick, you make me feel that I don't know about Python at all, thanks for the video
Continue watching and I will bring you up to my level in time!
"C programmers know", yes that was like a personal attack
So what we learnt here is that the python language hides it's script set-up to make things easier, however there are unspoken rules to its abstraction. Which is why we use c++.
Using a main function also allows unit testing with pytest
I like how the thumbnail answered the title and was self explanatory but yet we still clicked on this video.
Presumably you want to know *why* you should do this and hear the reasons rather than blindly following advice from the internet. 🙃
Great tip about "name main" in PyCharm. I'm going to use that for every script from now on!
I am brand new to coding. I am very confused but I will keep watching.
I even recommend this idiom:
if ___name___ == '__main__':
import sys # only necessary if not yet imported of course
sys.exit(main(sys.argv))
This way you can easily write unit test cases for testing your main() function as well and don't need to mock sys.argv or sys.exit(). The main() function then only is supposed to use its argument instead of the global sys.argv and it also just is supposed to return an exit value instead of using sys.exit directly. This also allows wrapping the main() function in some weird cases (call it from somewhere) without too much trouble.
Yup. I was gonna reply and say the same thing, seems sensible to exit with a value. I usually also have a try/except block around ‘sys.exit(main())’ that exits non-zero if an uncaught exception bubbles up. This is critical for utility scripts used in CI and other ‘headless’ setups, otherwise how can you tell if it failed?
While developing, I like to write the code directly in the if block, mainly so that if I run the file in interactive mode, the variables are there for me to inspect and modify to write the next lines. Not something you can do in a main() function without breakpoints.
The shebang is also a must in (Python) scripts.
Even if you are on windows ;)
Was it about setting the proper python version ( v3 vs v2? ) or just being able to run it directly as a script without the python prefix.
@@bersK00 To run it directly on the correct version "#!/usr/bin/env python2" or "/usr/bin/env python3" (or old style #!/usr/bin/pythonX"). With the prefix (python2 script.py), the shebang is not used.
This video really *underscores* the importance of if __name_- == "__main__". Nicely done!
Eh... In larger python programs where you have multiple files, sure this could be useful. But I'm certainly not gonna put it "in all [my] Python scripts". Any single-file scripts can easily remain as they are and it keeps them simple.
Yeah, I do it in my more serious projects. For sketches I usually just blindly write anything just the way it is
Is this a joke? In a "larger python programs" you are having this approach??
Not a Python guy at or outside of work, but I've seen this enough to be curious about it
Good to know for the future if I ever dive into Python again!
There's a very good Corey Schafer video from 2015 that explains this very well. It doesn't talk about the global variables though.
I'm a .NET dev, but now I know why I do the thing I saw everyone do in pro Python code. Thanks!
Make the code clearer and easier to debug. I specifically love it when I write a more complex program with different classes in multi file project. It allows me to test different modules and have different behavior when called as a script or as a module if I want.
Thanks for the great explanation, I think this is going to help a lot of people!
Unnecessary complexity is all fun and games, until you actually need to do your job, you get paid for.
@@Acid31337 It's not unnecessary complexity lmao, you simply don't understand it and fear it. While in reality this is easy stuff and it helps you.
@@satunnainenkatselija4478 but thats exacly what everyone does.
Why otherwise you think every typical java/c++ "OOP-best-practices" project end up in pile of managers, services, factories and DAO? That takes 1 week and 1000 SLOC to add 1 field to API...
We've lived for 2+ decades when "best practice" is to prematurely complicate software and called it "clean architecture", not forget call everything else "spaghetti". Now we're slowly trying to throw that toxic idea away and return to normal programming
I like that I can put the main() function at the top of the script and define the functions that it calls lower down, without worrying about calling a function before it is defined.
I use this in files that have functionality that I want to be able to either import into another script or run from the command line. The main function parses the command arguments and then instantiates classes and runs functions based on those arguments.
yeah, you definitely should NOT do that. Just move the functions you'd like to reuse to a separate module to keep your code clean and readable.
@@BlkRider I both agree and disagree to this point. It really comes down to the scope of responsibilities of the code in the file.
If the scope is narrow and I can write a very short main function to invoke it from the command line, then I can only see this as a bonus. Anyone looking at the code can now see a working example of how to use the code in the file (in addition to doc strings).
If I find that I am rewriting/reusing classes/code from that file that isn't part of the main responsibility. That's when I refactor it into its own file.
I've been doing this for years but I never knew why. I just knew thats what youre supposed to do lol.
Thanks!
I like how straight-forward Python is, but conventions like this, along with tragic package management are really against the Zen of Python.
I'm just an information scientist who happened to learn some Python in grad school and uses it once in a blue moon for very basic tasks, but even I use this because I was taught this way, even if I didn't know all of the reasons for it. (Well, I don't actually do this in every file; some very basic one-and-done standalones that no-one but me will ever see don't, but I know _why_ they don't need it.) There's usually a reason for traditional ways of doing things in a particular language.
Additional advantage of this is you can organize the functions in any order.
Well I am using the《If __name__ == "__main__"》ideom for years already, but not the 《def main()》part, because I was not aware of the variables being put to the global scope. Knowing this converted me of course, but this a horrific nightmare. I also just see your video on how future variable initializations do alter python's evaluation behaviour. I guess this video is just another manifestation of that other video's matter.
I was and still am a huge "fan" of python as it is a convenient and powerful language but these 2 videos changed my mind about python fundamentally.
I put this in my vimrc so that I don't have to do it manually again and again lol it's a good practice indeed
The first reason I learned about creating the main if statement and the main function was actually for multiprocessing. I use Python for my mathematics hobby with the SymPy module or with SageMath and wanted to utilize all the threads of my CPU.
Mathematics. Hobby.
Super informative! I’ve known about using __main__ but never knew about this kind of problem. But it makes me wonder, is there a way to write functions which can only use variables that were passed to it as an argument (or defined within the function)? ie, the variable i was not passed to the function in the video example, so is there a way to have this result in an Error?
Interesting idea! You know I've actually never looked into it before, but as far as I know the language does not support a locals-only directive.
Python has a built-in locals() function that will return a dictionary of all the variables that are within only the function's namespace (i.e. not within globals). This includes any arguments passed to the function. You could use '[variable name] in locals()' to get True or False and throw an error accordingly.
@@swolekhine but that doesn't solve typos like they were shown in this video
So I guess the move could be to have functions in a separate py file? That would circumvent these types of issues? Not my favorite solution but it sounds like there might not be a clean alternative
one_has_a_name = 'Arya'
def test(plop):
print(plop, one_has_a_name)
faceless = types.FunctionType(test.__code__, globals={'print': print})
faceless('I will raise a name error')
I've had scripts break hard, until I did the \_\_name\_\_ == "\_\_main\_\_" thing. It's pretty important that you do it, for sure!
non discord but youtube notification gang
Welcome!
it's all just context dependent. If all I have is a little trivial script that has like less than 10 lines of codes in it, why would I explicitly use an entry point?
It's pointless, since it's already obvious that this is a script. For more complex programs yeah it's a good habit, you inform the reader of something that was not necessarily obvious
at first glance
Your videos are always great
I appreciate that! Thanks for watching!
I've found a main function is also useful when making a tool that can either be used as a library in other projects or executed directly to perform a specific task in isolation. E.g. "convert the given binary file to a .csv" when executed vs only having a convert function when imported
Neat! This beautifully explained some quesstions, that I didn't even know how to ask, from when I first learned Python.
Every now and then I'd get unexpected errors or bugs that I couldn't for the life of me deconstruct - and now I finally know!
I'm looking forward to your future content and diving into your older stuff.
Thank you!
- Sincerely, a new subscriber.
Great to have you watching!
As a hardware engineer who just dabbles in Python, but I still put if __name__ == '__main__': in my non-script/library files. It allows me easy file-specific debugging when running the file from the spyder terminal. It also lets me prototype/showcase how the file is supposed to be used. Lastly, it saves me the additional files for unittest, but I can still implement that if I so choose.
Just love cpp so much that I try to make all my python code like cpp
Things are not only put in main, but also almost all the var are annotated with type hint
imo a good text editor/ide should be able to tell you the types without you needing to explicitly annotate them, and you don't really care about what the type is for local variables anyway. type annotations for functions, on the other hand, are great for documenting the contract.
and cpp also supports type inference (auto keyword).
@@wsrgs4 You do care about the types of local variables. Autocompletion works a lot worse when you don't know the type (though in python you can't even know for sure even with the type). Often you can infer the type from the usage of the variable, but if you use a library without type hints you're out of luck.
@@gamekiller0123 good point about libraries without annotations. but in the case where all functions *are* typed, your editor should be able to infer the type of local variables and provide the correct autocompletions, I would think. I guess I shouldn't have said that one doesn't care about the type, but rather that it doesn't usually need to be explicitly written.
Wow, this is quality content. This channel is going big, mark my word.
Of course there's a reason to do it. We want to make Python as complicated as Java or C++.
Ahh yes, the language flex argument.
C still wins on the monstrosity potential;
int B(void*X){return*(int*)&X;};int(*F(void*A,void*(*F)(void*)))(void*){int(*X)(void*)=&B;X(F(A));return X;}
@@chri-k Can do in C++ too...
You can use this feature in libraries as well to contain localized unit tests, then you can literally run the library to prove out its functionality
I already use this all the time! :)
I've been learning Python for quite some time now, and I've always wondered when I was browsing for code examples etc. why people were doing that basic-looking extra-hoop to jump through in their scripts.
Now I know... And knowing is half the battle! *PY JOOOE*
They were doing that because it is spaghetti-style code
Just so you know f"__name__={__name__}" can be written like f"{__name__=}"
He knows it, I saw him doing it in one of his videos. I guess he wanted a ":" here, not "="
Edit: although I don't see any reasons for that tbh
I grew up with Borland: init(); run(); done(); so it makes sense to me. You could create your own idiom, or "top-level super structure", for loading code. It is the precept to OOP, prior to object definition. Borland and Microsoft considered it critical for GUI app development, large code base, and object class structure.
I'm very new to python (not programming). before i had some prejudices but currently i have to say that python is much better than expected. nevertheless the code style is a new world (so videos like this are really helpful here). What I would be interested in is the following: it is great that you can execute every script - so sometimes I write a test function directly under a library function. the problem is that the import of other components is often not working because the starting point in the folder structure is different (because the library-funktion is not in the same folder with the main-script). is there a best practice for this?
(here for the notification, SO failed me)
I'm a bit late, but I'm not sure I understand what you're asking
This was awesome, rewatching and rewriting my default tmp code block.. thank you!
Very welcome!
I'll be honest not having "you" at the corner let me focus on the subject a lot better.
😳
@@mCoding fwiw i like it! This way is fine too, but something about having a video feed makes it feel more like a class which i like
@@mCoding nah keep the facecam, you have an awesome face
It's psychological. With the face on the screen you unconsciously try to make eye contact with that person (although only a video) to suggest that you pay attention. This is why you take your eyes off the screen/code numerous times during the lesson which can distract your brain. Without that other "person" you have nowhere else to look other than the code and you stay more focused.
I've been doing this for some time now. My motivation for doing this was and is to enable the order of code recommended in Clean Code: from high-level to low-level (helper functions), not vice versa. So it's def main(), def helper1(), def helper2(), ... and then if __name__ == ...
watching this as a c++ programmer who's never worked with python before
Fascinating and useful video. Basically this idiom serves a purpose similar to a C "#define IN_MAIN_C" guard near the top of "main.c", which signals to headers included below that that they're being included in a "main.c" context, rather than, say, "auxilliary.c" or "weather.c". Python makes such context-awareness easier by means of "__name__". (C's preprocessor also has the "__FILE__" macro, but that's not quite as easy to compare to a reference value as "__name__" is in Python.)
I'm surprised and disappointed that so few of the people in the comments seem to understand this idiom, and how it differs from other idioms, such as shebangs (which serve a different purpose altogether, namely command-interpreter selection) and file names (which serve to describe what the file _does_ ), whereas "__name__" is for context-awareness (what file we're in, and whether it's the entry-point file).
That being said, if-name-main is not really necessary for the kinds of Python scripts I've been writing so-far, as they're all single-file.
However, I'll put this idiom at the bottom of some of my longer scripts anyway, as a reminder to myself to use it in any multi-file projects I may do in the future. Thanks for the tip.
I've had less experience with python as I did most of my coding in Java, C and C++. I've only really used it for ML models in Jupyter until recently. Never really thought about the Global scope issue in importing files as I've never had to bother with that with the other languages - you only ever make a variable global if you explicitly need it to be.
If this is a problem of global scope in python, then you probably never want to use any global variables, especially in libraries. Good to know.
The single underscore in a variable name actually means that its private to the file / function / class depending on its scope - nothing is stopping you from using it in another script if it's scope is the entire file, but that's not its intention and you are breaking the silent rule.
Assigning a value to a single underscore just means you are throwing the value away and you actually can't use it - it's not possible.
I didn't know dunder == double underscore
Just wanted to add that the 'i' global/local bug isn't just an oopsie. I see it as a sign of negligence that the code wasn't checked after writing it. (with e.g. unit test, peek definition or just highlighting the variable name).
I dunno man, I always treat python like script (replacement of bash and batch), so that thing isn't so useful
Also it is a good practice for library to put all logic inside functions, running it directly won't do anything
Thank you, I finally understood the idiom and the benefits of using it.
Thanks for explaining this. I only use python for university stuff, so to me this is just a way to signal my professor that I know what I'm doing (which may or may not actually be the case).
I like that the style of explaining with minimum viable examples, it leaves room for discussion and that room is used, as you can see from the other great comments.
Usually, I don't care too much about python, but this was a great video. Keep it up and consider me a subscriber!
Great to hear! I also totally agree, my comments contain many gems and great suggestions from other experienced Python programmers! Awesome audience and glad you're part of it!
Couple of quick counter-arguments:
Logic behind using __name__ == '__main__' totally works for me, but RE: making a 'main' function for every script, I feel that, 1) this is an unnecessary contrivance for really simple scripts, 2) slightly obscures the logic RE: what is the main workflow of the script (I know it's only one extra level, but, precious seconds, man!) and 3) if the rest of the code is sufficiently modular, would this ever really be needed?
It does come down to opinion, convention, and personal judgement at some level so you aren't wrong per se, but here's what I would retort with. 1) agreed, but simple scripts often turn into not simple scripts, and even a single shadowed variable can break even a simple script, 2) it depends on the reader but i would argue the opposite, main tells the reader this is where the script conceptually begins, like painting the start line for a race. Side note: precious seconds? I recommend abbreviations/template expansion! 3) how can the code be modular if you are doing work in the global scope with global variables leaking into all your function scopes?
@@mCoding Nice response, thanks for your thoughts!
RE: use of globals: if I'm just writing a simple script to test out a method or workflow, and I want to e.g. run it a few times and manually vary some parameter(s), I often find it easiest to just chuck a couple of globals at the top so I can easily find and adjust them on each test run. But I take your point, you probably don't want that sort of thing ending up in your production/deployment version of a script!
Anyway, really appreciate your helpful explainers, keep up the good work. :)
"flashbacks to learning java" - oh yeah, I feel your pain!
Also you can return a code from the main function, and have a exit statement with code as the return value.
0:15 When you create a library that defines the meaning of the universe
That's gonna be one popular library!
That's the function deep thought calculated in billions of years... and it's brilliant. Mathematicians say, the easiest looking solutions are the most advanced and elegant ones
I think the main inconvinience of if __name__ == '__main__': is during code development. I usually test the behaviour of smaller code segments in the global namespace, and if the results proves to be robust, then I incoorporate it into the rest of the script. Having everything in the global namespace, allows to very conveniently plot or print the variables of interest into the python shell.
Using if __name__ == '__main__': disallows for such convenient access.
I know this method of testing clunky seems for a regular python development, but it is insanely usefor for advanced scientific or math implementation. For advanced math implementation one can only check the code via creating purpose built diagnostic plots during software development, because a code can run without yielding appropriate results. Using assert or error handling in themselves are far from sufficients, because only plots could tell how the math went awry, and during testing the diagnostical plots should be run anyway.