Jump to content

Python: Should be an Infinite Loop, But Isn't

straight_stewie

We are all well versed in this little program:
 

print("Hello World")

# OUTPUT: Hello World


And we are all well versed with importing another program and using it's contents using the "import statement".

So this:

import Hello_World

print("Hello World")
Hello_World

# OUTPUT: Hello World
#         Hello World


Should be an infinite loop outputting "Hello World" and then a new line. But it doesn't, it just outputs Hello World twice. 

Does anyone know why?

ENCRYPTION IS NOT A CRIME

Link to comment
Share on other sites

Link to post
Share on other sites

Why are you trying to make a loop by importing the program itself?

Do you know what a while loop is?

NEW PC build: Blank Heaven   minimalist white and black PC     Old S340 build log "White Heaven"        The "LIGHTCANON" flashlight build log        Project AntiRoll (prototype)        Custom speaker project

Spoiler

Ryzen 3950X | AMD Vega Frontier Edition | ASUS X570 Pro WS | Corsair Vengeance LPX 64GB | NZXT H500 | Seasonic Prime Fanless TX-700 | Custom loop | Coolermaster SK630 White | Logitech MX Master 2S | Samsung 980 Pro 1TB + 970 Pro 512GB | Samsung 58" 4k TV | Scarlett 2i4 | 2x AT2020

 

Link to comment
Share on other sites

Link to post
Share on other sites

I'm no python expert, but this doesn't seem like a loop to me.  Reminds me of a macro, or perhaps recursion.

Solve your own audio issues  |  First Steps with RPi 3  |  Humidity & Condensation  |  Sleep & Hibernation  |  Overclocking RAM  |  Making Backups  |  Displays  |  4K / 8K / 16K / etc.  |  Do I need 80+ Platinum?

If you can read this you're using the wrong theme.  You can change it at the bottom.

Link to comment
Share on other sites

Link to post
Share on other sites

while True:
  print "Hello World"

Pretty sure you should be doing this instead.

Frost | 7700K @ 4.9GHz 1.36v, delidded | Asus DUAL GTX 1060 6GB OC | Corsair LPX 16GB DDR4 2800MHz | Samsung 960 EVO 250GB SSD + Toshiba 1TB HDD + Toshiba 2TB HDD + Samsung 860 EVO 1TB SSD for macOS | Asus PRIME Z270-A | Fractal Design Celsius S24 | Seasonic M12-II 620W PSU | Corsair 400C White | NZXT Hue+

Samsung Galaxy S8 | Stock

Ticwatch E (Black) | Ticwatch Brown Leather Strap

Link to comment
Share on other sites

Link to post
Share on other sites

All this is doing at the moment is running the print("Hello World") statement, then running the other program that again just tells it to print("Hello World")

Link to comment
Share on other sites

Link to post
Share on other sites

7 minutes ago, NJHourigan said:

All this is doing at the moment is running the print("Hello World") statement, then running the other program that again just tells it to print("Hello World")

That crossed my mind but if this is supposed to be a "loop", I assume the import must be importing itself, not the other program... or at least, that was the intention.  Maybe you've solved this :P 

Solve your own audio issues  |  First Steps with RPi 3  |  Humidity & Condensation  |  Sleep & Hibernation  |  Overclocking RAM  |  Making Backups  |  Displays  |  4K / 8K / 16K / etc.  |  Do I need 80+ Platinum?

If you can read this you're using the wrong theme.  You can change it at the bottom.

Link to comment
Share on other sites

Link to post
Share on other sites

Why would this be a loop? The import just makes it print "Hello World" and then the subsequent print statement prints that message again. The final Hello_World doesn't do anything except return a module object. So as far as I know Python this isn't a loop.

Crystal: CPU: i7 7700K | Motherboard: Asus ROG Strix Z270F | RAM: GSkill 16 GB@3200MHz | GPU: Nvidia GTX 1080 Ti FE | Case: Corsair Crystal 570X (black) | PSU: EVGA Supernova G2 1000W | Monitor: Asus VG248QE 24"

Laptop: Dell XPS 13 9370 | CPU: i5 10510U | RAM: 16 GB

Server: CPU: i5 4690k | RAM: 16 GB | Case: Corsair Graphite 760T White | Storage: 19 TB

Link to comment
Share on other sites

Link to post
Share on other sites

Module-level code is executed when you import it, so when you first "import Hello World", it runs your full code and prints "Hello World". Then, it finishes executing the rest of the code from where it left off, printing "Hello World" again. Your fourth line is not actually calling anything, it just returns the object, as @tikker said.

Link to comment
Share on other sites

Link to post
Share on other sites

44 minutes ago, Ryan_Vickers said:

That crossed my mind but if this is supposed to be a "loop", I assume the import must be importing itself, not the other program... or at least, that was the intention.  Maybe you've solved this :P 

I think what you're thinking of is something known as recursion, but that involves stuff like functions which I'm guessing you haven't come across yet.

Link to comment
Share on other sites

Link to post
Share on other sites

3 hours ago, NJHourigan said:

I think what you're thinking of is something known as recursion, but that involves stuff like functions which I'm guessing you haven't come across yet.

4 hours ago, exercutor5 said:

Pretty sure you should be doing this instead.


Ouch, that hurts. 
 

4 hours ago, Ryan_Vickers said:

That crossed my mind but if this is supposed to be a "loop", I assume the import must be importing itself, not the other program... or at least, that was the intention.

Maybe I should have been clearer. because it was definitely my thought that that should happen, and I was looking for the reason (basically this is a question about how python works when importing) that it would print twice, but not indefinitely. What's more, if I do this:
 

import Hello_World

print("Hello World")
Hello_World

stop = input("HIT ENTER TO EXIT")

# OUTPUT: Hello World
#         HIT ENTER TO EXIT

It outputs "Hello World" followed by "HIT ENTER TO EXIT" rather than what I would have expected here, which would have been to print "Hello World" twice and then print "HIT ENTER TO EXIT".

To be very clear, I had thought, for no good reason other than that it makes logical sense that it should work, that it might be fun to try to find out if recursion could be accomplished this way. Apparently there is some built in mechanism that prevents this, or else I am using the wrong method to call the script. So my question is: Why doesn't this work, or alternatively, does anyone know in-depth how importing modules/scripts works in Python 3.xxx? 

ENCRYPTION IS NOT A CRIME

Link to comment
Share on other sites

Link to post
Share on other sites

Importing a module consists of two parts:  Loading the module, and adding to the current namespace.

 

Python only loads a module once.  If A imports imports B and C, but B also itself imports C, C will only be loaded once, but will be added (under the name 'C') to both the namespace of A and B.


That being said...I should add that loading IS execution.
 

There is a hidden variable called '__name__'.  This will contain the name of the current module with one exception.   The entry point for the interpreter (the initial script) will be named "__main__".

 

Therefore, any code that is not a class/function definition, or used to initialize a module, should always be inside of an if statement (preferably the last thing in the file):

if __name__ == '__main__':
	# do whatever here

 

As another note, there is a built in function to reload a module.

 

In python2 it is a built in 'reload(module)'.  so if you 'import spam', you 'reload(spam)'.

In python3 that functionality was moved to a module....well two...the 'imp' module was deprecated.  it is now (the same function) part of the 'importlib' module.

One thing to note about reload is it does not purge the loaded module before loading.  The load overwrites, but if something was removed, it will still be available after reload.  It's all based on dictionaries (just about everything in python is implemented as dictionaries, or a hierarchy of dictionaries), so it overwrites entries without first clearing the dictionary.

Link to comment
Share on other sites

Link to post
Share on other sites

9 hours ago, NJHourigan said:

I think what you're thinking of is something known as recursion, but that involves stuff like functions which I'm guessing you haven't come across yet.

I mentioned that it reminded me of that earlier up :P 

Solve your own audio issues  |  First Steps with RPi 3  |  Humidity & Condensation  |  Sleep & Hibernation  |  Overclocking RAM  |  Making Backups  |  Displays  |  4K / 8K / 16K / etc.  |  Do I need 80+ Platinum?

If you can read this you're using the wrong theme.  You can change it at the bottom.

Link to comment
Share on other sites

Link to post
Share on other sites

6 hours ago, straight_stewie said:


Ouch, that hurts. 
 

 

Well yes I am aware that it can be made using a simple loop but you seemed to be going for a recursion approach so.

6 hours ago, straight_stewie said:

 

Maybe I should have been clearer. because it was definitely my thought that that should happen, and I was looking for the reason (basically this is a question about how python works when importing) that it would print twice, but not indefinitely. What's more, if I do this:
 


import Hello_World

print("Hello World")
Hello_World

stop = input("HIT ENTER TO EXIT")

# OUTPUT: Hello World
#         HIT ENTER TO EXIT

It outputs "Hello World" followed by "HIT ENTER TO EXIT" rather than what I would have expected here, which would have been to print "Hello World" twice and then print "HIT ENTER TO EXIT".

To be very clear, I had thought, for no good reason other than that it makes logical sense that it should work, that it might be fun to try to find out if recursion could be accomplished this way. Apparently there is some built in mechanism that prevents this, or else I am using the wrong method to call the script. So my question is: Why doesn't this work, or alternatively, does anyone know in-depth how importing modules/scripts works in Python 3.xxx? 

Recreating what you've written it seemed to work for me so I'm not sure what went wrong but if I was in your position I would differentiate the print statements so you know which one is actually running.

Link to comment
Share on other sites

Link to post
Share on other sites

What SHOULD happen is the script will be imported twice.

 

I have made a modification to it that should make clear what is happening:

import Hello_World

print("Hello World from " + __name__) # note, that is two underscores
Hello_World # this line does nothing

stop = input("HIT ENTER TO EXIT")

# OUTPUT:
# Hello World from Hello_World
# HIT ENTER TO EXIT
# Hello World from __main__
# HIT ENTER TO EXIT

The interpreter session keeps a list of imported modules.  Similar to [proper] include guards in C/C++, the module name is registered at the beginning of the import, not at the end.  Whereas you can theoretically create a cyclic dependency graph, since importation is execution, and registration is effective start-of-file, any actual use of cyclically dependent attributes will be met with an error.  For example, the following code has a cyclical dependency on the function 'say_hello':

import Hello_World

Hello_World.say_hello(__name__)

def say_hello(mod):
  print("Hello World from " + mod)

will give an error that module Hello_World has no attribute say_hello.  The first thing that will happen, is module __main__ will begin execution.  It will reach the line 'import Hello_World', and search on the python path for a module of that name (being the same file is only a coincidence, it cares about module name and the entry point is always loaded with the name "__main__").

 

It will then begin import [read execution] of the module 'Hello_World'.  It will reach the line that states 'import Hello_World'.  It will see that a module by that name is already imported and skip it.

 

It will then reach "Hello_World.say_hello()".  As Hello_World has not reached that point in importation, it will be as-of-yet undefined.  This will throw an exception and the program will exit.

 

On the other hand, the following IS valid, as despite a cyclic import there are no cyclic dependencies:

import Hello_World

def say_hello(mod):
  print("Hello World from " + mod)

Hello_World.say_hello(__name__)
  
# OUTPUT:
# Hello World from Hello_World
# Hello World from __main__

This is because the def statement is making an entry in the module's symbol table, which IS a dict, and thereby a reference type.  But since each module is a singleton, the cyclical import is just creating a self-referential pointer in the current scope table (also a dictionary).

Since this is a reference to a singleton, it WILL be defined by the time it is called and is therefore not an error.

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×