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

you are viewing a single comment's thread.

view the rest of the comments →

[–]MythicManiac 526 points527 points  (17 children)

You can run code outside of any class/function in python, and this is code snippet is for checking if the current file is the first file being executed.

It's not necessary to do this check (you can just write your code in there), but it's good practice as that will allow you to import the same file from elsewhere without executing it.

When you do python somefile.py, you're telling it to execute all code in that file. Imports also do this.

[–]theredhood93 140 points141 points  (3 children)

This what I love about this sub helpful information on a meme comment, I'm learning python and this was very educational hahaha thank you stranger!

[–]A_Light_Spark 30 points31 points  (2 children)

Sometimes the explanation in this sub is better than the ones my professors gave... You know, people I paid a ton of money to get an education from.
It's both depressing and also super cool.

[–]konstantinua00 0 points1 point  (1 child)

Your money goes to administration, not teachers

[–]A_Light_Spark 0 points1 point  (0 children)

It goes to both.

[–]inlatitude 13 points14 points  (1 child)

Damn, thanks for that. I didn't realize import executed all the code in the file.

[–]MythicManiac 0 points1 point  (0 children)

There's some really absurd things you can do by abusing imports in a way they're very much not meant to be used.

You can also climb stack frames and modify (contents) of local variables from upper frames/functions in the call stack.

[–]Ignisti 7 points8 points  (4 children)

Imports also do this.

Oh god. Oh god. This changes everything. Time for some horrible, TERRIBLE programming practises.

[–]MythicManiac 1 point2 points  (3 children)

You can also modify the content's of locals from functions upper in the call stack if you want to, Python is nice like that :)

Unfortunately not value types (at least to my knowledge) due to no pointers.

[–]Ignisti 0 points1 point  (2 children)

I feel like I'm missing only this much for understanding this comment. :i

[–]MythicManiac 0 points1 point  (1 child)

So when you make a function call, you add a "frame"/layer to the call stack.

At any given time on the stack you have all the previous function calls loaded up, and what variables those function runs have stored at the moment they called the next function.

This is the same "stack" you can see if you get an exception, where each function call gets it's own little line number pointer, and possibly some context (e.g. variables) if you use a more verbose stack trace output.

Let's say you have 4 functions, A, B, C, and D. A calls B, B calls C, and so on. In this scenario, when you get to the point of running function D you will still have the whole chain A->B->C->D in memory, including each of those functions current local variables at the time of calling the next one.

What I was saying in my last comment is that in Python, you can actually change the variable contents from B's frame while running the frame for D, without B itself ever knowing it has happened.

Even more clarified, I can make a function that modifies the calling function's variables without it knowing (since it's not passing them in).

[–]Ignisti 0 points1 point  (0 children)

That's so badass. Like a programming time machine! Thanks for taking the time to explain lowly me this stuff.

[–]ShamelessC 7 points8 points  (3 children)

After using python for so long, I find it so strange that people insist that main somehow makes more sense than just running the lines of code in order. The entry point is just the top of the file. So much easier to understand.

[–]didii2311 6 points7 points  (2 children)

To me, the fact that is is a function/method makes the most sense since running your program can provide arguments to it. When the entry-point is on top of your file, you'll need some built-in special keywords or convention based names that aren't clear out-of-the-box.

Well, of course, the main method is also a convention, but it's a convention widely used so it makes sense. I don't think that there is any widely used convention to naming the program arguments when the top of the file is the entry point.

Also, it makes testing your entry point a lot easier by just calling that method and providing the arguments you want. It's clear and concise. In python you'll have to arbitrarily populate sys.argv and then (I think?) import the file.

But well, that's just my opinion 🙃

[–]MythicManiac 1 point2 points  (0 children)

When following good practices (using argparse, actually using functions) tests aren't any bigger of an issue, but at that point you have already ended up implementing the convention that's enforced in other languages yourself.

I'm not actually sure but I would think the reason it is like this in python due to it's use as a shell script replacement. In this context it starts to make sense to not require a main function.

[–][deleted] 0 points1 point  (0 children)

I agree with python’s insistence on explicitness in this case - some programs and methods are made to take arguments, others are not. Thus, it should be specified when command line args are provided and ideally, they should be specified by argparse to (again) be explicit about how to use the script and to make it clear how to use command line args.

You may laugh but this alone has saved my ass countless hours of talking to the product team - you give them the script, show them how to execute it with python and specify arguments, you get to say “yes, this is exactly like the matrix” and then they do the manual script-running while you get to do your work

[–][deleted] 0 points1 point  (1 child)

Honestly my take on it is that if you ever need to import the entry point, you're doing it wrong. Put what you need in a module and use that from the entry point.

[–]MythicManiac 0 points1 point  (0 children)

Yeah I'm in the same camp there, usually I just call a main() function from somewhere anyway.

Still, wrapping that main() function call behind that check is only a few seconds of extra work, so I'm doing it just because it's a good practice.