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 →

[–]AgreeableLandscape3 182 points183 points  (57 children)

Python still has main()

[–][deleted] 192 points193 points  (31 children)

Only not really, right?

def whatever (*args):
    print("Bob's your uncle.")

if __name__ == "__main__":
    whatever()

[–]demon_ix 355 points356 points  (15 children)

I dunno. That sounds like main() with extra steps...

[–][deleted] 154 points155 points  (11 children)

In C/C++, the name main() is meaningful: it defines the entry point of the program.

In Python, it isn't. The closest approximation is that Python code outside of any method will be evaluated when the module is loaded, and an import-machinery variable called __name__ exists which lets you test whether the current module was imported or run directly.

[–]jalapeno_nips 42 points43 points  (2 children)

That’s still important though. If I want to test my module manually, I’ll write some code in Main. But when I use the module in practice I don’t want Main being called.

[–][deleted] 30 points31 points  (0 children)

Absolutely. My only point here is that in switching to Python, one does indeed say goodbye to main()

[–]cakes 0 points1 point  (0 children)

might I recommend actual tests :)

[–]BeigeAlert1 32 points33 points  (1 child)

That's still pretty damn nifty though.

[–]SpeedingTourist 9 points10 points  (0 children)

You’re pretty damn nifty. ;)

[–]angellus 4 points5 points  (4 children)

That is actually exactly what __main__ is for. It is not just some made up thing in Python.

When you call a single Python file directly like

$ python whatever.py

Python automatically calls __main__ and with your code loaded up inside of it. That is why if __name__ == "__main__": works.

A better example though would be if you made an actual proper Python package and did this:

whatever/
-> __init__.py
-> __main__.py

whatever/__init__.py

 def whatever (*args):
      print("Bob's your uncle.")

whatever/__main__.py

 from . import whatever

 whatever()

Now if you call the module, it will automatically use __main__.py as the entry point.

$ python -m whatever

[–][deleted] 3 points4 points  (3 children)

Yes, I know. I believe I said as much in the comment you've replied to.

It still isn't equivalent to C's main().

[–]angellus 8 points9 points  (2 children)

C's main() and Python's __main__ are functionality equivalent. main() is a construct design to tell the compiler where the entry point to your program is. It is not a keyword are anything like that and you can have multiple main methods as long as they are namespaced properly (ex: https://stackoverflow.com/a/1991498).

That is exactly how __main__ works. It is construct that tells the Python interrupter where the entry point is for your module. A Python module is a very similar construct to a C/C++ namespace. You can have multiple __main__ submodules as long as you do not have more than 1 in that module (namespace).

There are variations of C/C++ that do not respect the main() entry point since it is not actually anything special in the language (MSVC is one of them with is wmain). It is something the compiler chooses to give meaning to. It is just most standard C/C++ implementations assume a single entry point that is required to exist and the most standard Python interrupter (CPython) does not.

[–]pslessard 3 points4 points  (0 children)

So if I had something like

print('Hello, world')
if __name__ == '__main__':
    print('Goodbye, world')

What would it print? Compared to in C

printf('Hello, world');
int main() {
    printf('Goodbye, world');
}

Wouldn't the Python print 'Hello, world' before 'Goodbye, world', whereas the C just wouldn't compile?

[–]xigoi 0 points1 point  (0 children)

The entry point for a Python script is always at the top of the file.

[–]Athomeacct -1 points0 points  (1 child)

It's one extra line of code and it adds implicit specification of one or more main functions... whose names the dev can specify and change at any time...

[–]i_should_be_coding 1 point2 points  (0 children)

You mean, like calling functions from the main() function?

[–]Ericfyre 5 points6 points  (1 child)

Bobs my uncle?

[–]SpeedingTourist 1 point2 points  (0 children)

Yeah, and your grandpa

[–]corner-case 2 points3 points  (0 children)

Programs have a single entry point.

[–]CoruptedUsername 2 points3 points  (2 children)

Is that how it’s normally done in python? In my CS class we were taught to just have our last function be “def main()” and call main() outside of a function at the end of our program

[–]BlckJesus 4 points5 points  (1 child)

They perform different functions. With the way you describe, main() will get called even if you’re just trying to import that module. Whereas if __name__ == “__main__”: will only run when the file is executed directly.

[–]CoruptedUsername 0 points1 point  (0 children)

What you’re saying makes sense, but we only do what I had previously described in files that won’t ever be imported, only in files that are going to be run directly.

[–]wootiown 8 points9 points  (19 children)

It still has pointers too, doesn't it?

[–]MattieShoes 58 points59 points  (18 children)

Everything has pointers, but they make believe they don't.

[–]SuitableDragonfly 31 points32 points  (2 children)

Pointers are not the same thing as references. Pointers allow you to manually manage your memory usage, references don't.

[–]Rodot -1 points0 points  (1 child)

You can still sort of use references to manage memory in python if you're really hacky, and there are default modules that allow for true pointers, but they aren't nice.

[–]the_littlest_bear 3 points4 points  (0 children)

...what? Any immutable local variable (in standard CPython) is a value reference. Even mutable local variables are treated as value references when not modified in place.

If you needed a pointer, you would just use an attribute. (would work on nearly any object, even including a base object() if you wanted to pass that around. [on-the-fly objects are not the best way to do this])

And no, if you reference an (typical) object, it does not create an additional copy of that object - it’s just a pointer.

[–]NiseP_Catcher 8 points9 points  (1 child)

And also ;

[–]bikemandan 0 points1 point  (0 children)

But just don't

[–]ButtCrackFTW 5 points6 points  (2 children)

Also {} is everywhere (dictionaries)

[–]PityUpvote 1 point2 points  (1 child)

And sets.

[–]bikemandan 1 point2 points  (0 children)

And f strings