BASIC PROBLEM
I'm getting a name import error, but not in a way that is consistent between two files. I can import names from file A to file B, but not the other way around.
Update Based on Comments
I (stupidly) named the file "mix_max.py" instead of "min_max.py". I have changed the file accordingly and updated the GitHub repo. I have also updated the code in my question to reflect that.
CONTEXT AND CODE
Rather than reproduce all code here, I made a repo to show what I'm talking about.
I have the following min_max.py file:
https://github.com/jeffnyman/tic_tac_toe/blob/master/min_max.py
You can see a line in there to import from tic_tac_toe:
from tic_tac_toe import available_moves, apply_move, has_winner
That works just fine and I'm able to use those functions in min_max.py, such as on lines 74, 84, and 88.
However, I also have the following tic_tac_toe.py file:
https://github.com/jeffnyman/tic_tac_toe/blob/master/tic_tac_toe.py
You'll notice a line that does a similar import the other way around:
from min_max import min_max_player
PROBLEM
However when I try to use that (see line 126):
if __name__ == '__main__':
play_game(random_player, min_max_player, log=True)
This does not work. And it does not work because my from/import leads to "cannot import name min_max_player" when I try to run tic_tac_toe.py.
Workaround 1
I found I can fix this by changing my import to this:
import min_max
And then changing the code like this:
if __name__ == '__main__':
play_game(random_player, min_max.min_max_player, log=True)
The key change there being min_max.min_max_player.
What I don't see is why this is necessary, particularly since I didn't have to do this when importing from tic_tac_toe.py to min_max.py.
Workaround 2
I can apparently defer the import like this:
if __name__ == '__main__':
from min_max import min_max_player
play_game(random_player, min_max_player, log=True)
That works.
I'm coming to Python from a Ruby and Java context so I fear I'm missing something terribly obvious here. So maybe those things I list as "workarounds" are, in fact, the actual solution?
Based on the help of Stack and hurturk, who both pointed me in the right direction (see their comments), it looks like the concept I was missing and/or not seeing was the circular reference as well as perhaps the race condition therefrom.
So I believe one answer to my question are the workarounds that I posted in the original question.
Workaround 2 is to essentially to defer the import, as such:
if __name__ == '__main__':
from min_max import min_max_player
play_game(random_player, min_max_player, log=True)
I do find it perhaps odd that this doesn't lead to the same issue since the "defer" isn't really all that deferred; given that I handle this in the very first lines of tic_tac_toe.py that get executed.
I'm honestly not sure why either workaround is the answer necessarily, but they do have the benefit of working. It seems that it's just a matter of what kind of expression I have in place.
I like the Workaround 2 one because it allows me to use "min_max_player" similar to how I call "random_player". Workaround 1 forces me to use "random_player" and "min_max.min_max_player".
Related
This seems pretty basic, so I must be missing something obvious. Goal is to import a module from the same directory. I've broken it down about as simple as I can and I'm getting the nameerror.
file import_this.py:
def my_function(number) :
print number + 2
file import_test.py:
import import_this
my_function(2)
Do I have to specify the directory the import file is in? (It's in the same as the test file). Also, can I test to see what modules are imported?
You are accessing the function incorrectly.
Either use the following
import import_this
import_this.my_function(2)
or do,
from import_this import my_function
my_function(2)
Alternatively (apart from #mu's answer above),
>>>import import_this as it
.. and then,
>>> it.my_function(2)
I am here to ask what seems to be a very dumb question, but just cannot find a fix for it. I'm just a beginner and I've also searched StackOverflow for multiple results but such problems are not related to mine. If I've missed one, I'm sorry about that.
my problem is that I'm trying to re-create one of my first console games into an OOP one, but for some reason, I cannot import modules?
firs, I would like to say that I created this on my laptop with Pop os. and that the mentioned two file are the only file on the directory.
so I created a battle_main.py and battle_mechanics.py
on the battle_mechanics.py, it only has the following lines:
class User_Interface:
def __init__(self):
self.player_health = 30
self.squid_health = 30
and on the battle_main.py:
from battle_mechanics import User_Interface
ui = User_Interface()
it's literally just that, yet I cannot import it. it's resulting in ImportError: cannot import name 'User_Interface' from 'battle_mechanics' I know that it's a very simple problem, but I really can't find any fix to it? in fact, I think there's not even a problem in the way I'm importing it. it just wont work. any help is appreciated.
I'm not sure as to why the method your trying isn't working. To the best of my knowledge what your doing already is correct. However one alternative workaround is to put battle_mechanics.py inside a folder package. Include __init__.py inside that folder with the following code:
from .battle_mechanics import *
Then when you use battle_main.py you can use the following import statement.
from package import User_Interface
This should sort out your issue.
Essentially, I have two .py files which lie in the same directory. Namely, foo_v02 and bar_v01.
In bar_v01, I want to import a class from foo_v02. However, for the sake of convenience, I want to use the statement from foo import myClass (ignoring the version number). However, as my file isn't called foo, of course python throws an error as there's no file called foo.py.
My Question: Is there a way I can just use from foo import myClass without having to rename my foo_v02.py file?
Note: I already have code which works but it uses from foo_v02 import myClass, so I'm not experiencing a problem as such. Also, I'm asking this question as my foo_xx.py file will undergo frequent editing so there will be multiple versions (so I don't want to have to edit the import statement with every new version). Also, there's only ever going to be one foo_xx.py in the directory as all the previous versions are moved to a different directory once they're outdated.
EDIT:
I've posted an answer for now, but if anyone has a better way, please feel free to post it!
I think the below code maybe works:
import glob
foo = __import__(glob.glob('foo_*.py')[0][:-3])
myClass = foo.myClass
Since the original answer got deleted...
import glob
a = glob.glob('*.py') ## Returns all of the `python` files
b = a[0]
exec('from {} import myClass'.format(b[:-3]))
I'm using exec() (instead of __import__) as I actually want to run the import statement. Also, the import isn't discarded afterwards.
I see a lot of people doing
if __name__ == '__main__':
main()
where main() presumably has all the useful code. What if I don't want the script to be imported? It doesn't have useful functions/classes to import. Is it just as elegant to do
if __name__ != '__main__':
sys.exit()
print('this script shouldn\'t be imported')
when your code won't do anything for the outsider?
Unless the code simply won't run correctly when it is imported, I would strongly recommend against adding unnecessary safeguards. Don't treat others like children - let them decide. All you need to do is provide documentation about the correct usage.
In the case that someone should import module A instead of B because of some weird order of execution issue, you could raise an exception with a message directing the user to A. But this really isn't a common scenario.
Don't worry when your code is being imported, but worry if nobody wants to import it! :)
Indeed What for to protect it in such a way?
If one person has you script it can easily fix it and allow importing.
Best way is to let people decide how to import the code: use as a module or a script.
For teaching purposes I want an IPython notebook that displays (as output from a cell) the function source code, but I want to be able to reference this in multiple notebooks. Hence I would like to display the function code, in a similar way to using the %psource magic, but appropriately syntax highlighted.
This is a similar question to this question, but I want to be able to apply it to a single function within a file, rather than to the complete file at once.
Using the suggestion from the previous question I hacked a short code that works in simple cases:
def print_source(module, function):
"""For use inside an IPython notebook: given a module and a function, print the source code."""
from inspect import getmembers, isfunction, getsource
from pygments import highlight
from pygments.lexers import PythonLexer
from pygments.formatters import HtmlFormatter
from IPython.core.display import HTML
internal_module = __import__(module)
internal_functions = dict(getmembers(internal_module, isfunction))
return HTML(highlight(getsource(internal_functions[function]), PythonLexer(), HtmlFormatter(full=True)))
Two questions:
This gist suggests that showing the whole function could be done by defining appropriate cell magic. Is it possible to define an appropriate cell magic to just show a single function, as above?
Is there a way of doing this without importing the entire module, or a more robust way of doing this?
1) Magics are just simple function not difficult to define, you could have a look here Customizing IPython - Config.ipynb if I remember correctly. still I'm not sure it is worth definig a magic in your case.
2) Most of the time, no. You have to import the module as we need live code to know where it is defined.
In general, finding the code of a function is not always super easy. On python 3 you can always access the code object, but most of the time, as soon as you have things like decorated function, or dynamically generated function, it becomes difficult. I suppose you could also inspire from psource/pinfo2 and have them return info instead of paging it.