I'm new to Python and I'm not sure what's the best place to put my user-defined exceptions, and where to catch them.
For example, I have a program which starts a game, when the game is stopped, an user-defined exception is raised (StopGame). I should catch this exception from outside the game since the game is throwing this exception. Though, the exception is specific to the game so the definition of the exception should be in the game module (or maybe the game package?).
Here is the simple layout of the program:
Program structure:
__main__.py
game/
__init__.py
game.py
__main__.py
import game
def main():
g = game.Game()
try:
g.start()
except game.StopGame:
print '\nbye bye!'
if __name__ == '__main__':
main()
game/__init__.py
from game import Game
from game import StopGame
game/game.py
class Game:
def start(self):
try:
a = raw_input('do you want to play?\n')
print 'cool'
except (KeyboardInterrupt, EOFError):
raise StopGame
if a == 'no':
raise StopGame
else:
print 'cool'
class StopGame(Exception):
pass
This code works fine like this, I'm just not sure this is the way to go. What I find somewhat disappointing is that I should import every exception in game/_init_.py using this setup. Otherwise I should catch the exception like:
except game.game.StopGame
Which looks a bit nasty. I think it's better to be able to reach all the attributes in the module 'game' from the variable 'game' in _main_.py. Then I know you can put this in game/_init_.py:
from game import *
Which will import all classes from game/game.py, but I heard that using * for importing is a bad practice.
So, my question is, what is the best way to do this? Maybe my whole setup is wrong, if so, I would like to hear what's the correct setup.
Thanks a lot in advance!
BTW: If you might wonder why I have a game module inside a game package: the idea is that the package will contain a lot of more modules that are related to the game, game/game.py is just the initiator of the whole game, maybe I should put that code into game/_init_.py?
How is it done elsewhere?
I think that the best way to answer your issue is to look at an actual Python package and see how it's built. I'll take the example of the excellent python-requests package.
This module is about making HTTP requests. Yours is about playing a game.
Basic HTTP requests functionality is imported in the requests/__init__.py file, but is defined elsewhere. That's what you're doing, but the 'elsewhere' could have a better name. Maybe game/core.py could be a good fit.
Exceptions are defined in the requests/exceptions.py file. It's usually appropriate for a relatively-small package to have all the exceptions in one place.
Note that the exceptions are imported into requests/__init__.py too! This makes them easier to import in other packages that might need to catch them!
Last, no from module import * is used. It's not going to take so much time to actually add exactly what's needed, so you should avoid *.
What can you do in your case?
Avoid having a game/game.py file, call it game/core.py or something
For a small package, put your exceptions in a game/exceptions.py file
In game/__init__.py, import what's usually needed from your package: the main classes and the exceptions.
Related
I have kind of a tricky question, so that it is difficult to even describe it.
Suppose I have this script, which we will call master:
#in master.py
import slave as slv
def import_func():
import time
slv.method(import_func)
I want to make sure method in slave.py, which looks like this:
#in slave.py
def method(import_func):
import_func()
time.sleep(10)
actually runs like I imported the time package. Currently it does not work, I believe because the import stays exists only in the scope of import_func().
Keep in mind that the rules of the game are:
I cannot import anything in slave.py outside method
I need to pass the imports which method needs through import_func() in master.py
the procedure must work for a variable number of imports inside method. In other words, method cannot know how many imports it will receive but needs to work nonetheless.
the procedure needs to work for any import possible. So options like pyforest are not suitable.
I know it can theoretically be done through importlib, but I would prefer a more straightforward idea, because if we have a lot of imports with different 'as' labels it would become extremely tedious and convoluted with importlib.
I know it is kind of a quirky question but I'd really like to know if it is possible. Thanks
What you can do is this in the master file:
#in master.py
import slave as slv
def import_func():
import time
return time
slv.method(import_func)
Now use time return value in the slave file:
#in slave.py
def method(import_func):
time = import_func()
time.sleep(10)
Why would you have to do this? It's because of the application's stack. When import_func() is called on slave.py, it imports the library on the stack. However, when the function terminates, all stack data is released from memory. So the library would get released and collected by the garbage collector.
By returning time from import_func(), you guarantee it continues existing in memory once the function terminates executing.
Now, to import more modules? Simple. Return a list with multiples modules inside. Or maybe a Dictionary for simple access. That's one way of doing it.
[Edit] Using a dictionary and importlib to pass multiple imports to slave.py:
master.py:
import test2 as slv
import importlib
def master_import(packname, imports={}):
imports[packname] = importlib.import_module(packname)
def import_func():
imports = {}
master_import('time', imports)
return imports
slv.method(import_func)
slave.py:
#in slave.py
def method(import_func):
imports = import_func()
imports['time'].sleep(10)
This way, you can literally import any modules you want on master.py side, using master_import() function, and pass them to slave script.
Check this answer on how to use importlib.
suppose I have a file my_plugin.py
var1 = 1
def my_function():
print("something")
and in my main program I import this plugin
import my_plugin
Is there a way to silently disable this plugin with something like a return statement?
for example I could "mask" the behavior of my_function like this:
def my_function():
return
print("something")
I am wondering if I can do this for the module as a way to turn it on and off depending on what I am trying to do with the overall project. So something like:
return # this is invalid, but something that says stop running this module
# but continue on with the rest of the python program
var1 = 1
def my_function():
print("something")
I suppose I could just comment everything out and that would work... but I was wondering if something a little more concise exists
--- The purpose:
The thinking behind this is I have a large-ish code-base that is extensible by plugins. There is a plugins directory so the main program looks in the directory and runs all the modules that are in there. The use case was just to put a little kill switch inside plugins that are causing problems as an alternative to deleting or moving the file temporarily
You can just conditionally import the module:
if thing == otherthing:
import module
This is entire valid syntax in python. With this you can set a flag on a variable at the start of your project that will import modules based on what you need in that project.
I have imported a user created file into my main code but an error in imported file is being displayed before. How can I suppress that error and display it only when the function is called
Importing file and its function :
import userValidation
NameString = input("Enter your name : ")
I have called user_validation function later in the code :
user_validation(names)
user_validation() has some error which I know and is being displayed just after the code start running.
I want to suppress the error till the time user_validation is called.How can i do that.
Use exception handling appropriately.
try:
#code with exception
except:
#handle it here
In the except part you may use pass to just move on if no action is required or use raise to handle it in the calling function.
Your terminology is a bit confusing, and in particular you aren't telling us the nature of the error (syntax, function definition, etc).
When you do:
import userValidation
The code in that module is run - up to the if __name__ =='__main__': block. Normally that code will contain other imports and a set of function and class definitions. That if block is supposed to contain variable definitions and function calls that will be used in a stand alone script call.
With proper separation, the only things that will be run during the import are the function and class definitions. The functions don't have to run correctly, they just have to have a valid syntax.
You should be able to wrap the import in a try/except block
try:
import userValidation
except ImportError: # or other error type
userValidation = None
Typically this structure is used to import modules that might not be present on the system. I'm not sure what errors you get if there is a syntax or other error in the imported file. But keep in mind that if there is an error, that module (or any of its functions) will not be available for latter use.
If this answer isn't enough, you need to describe the errors, maybe even give us a working (or not) example.
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.
Python won't allow me to import classes into eachother. I know there is no "package" solution in Python, so I'm not sure how this could be done. Take a look at my files' codes:
file Main.py:
from Tile import tile
tile.assign()
class main:
x = 0
#staticmethod
def assign():
tile.x = 20
file Tile.py:
from Main import main
main.assign()
class tile:
x = 0
#staticmethod
def assign():
main.x = 20
I get the error "class tile can not be imported".
If file A imports file B, and file B imports file A, they would keep importing each other indefinitely until the program crashed.
You need to rethink your logic in a way that doesn't require this circular dependency. For example, a 3rd file could import both files and perform both assignments.
You have your import backwards and the from needs to have the name of the module
from Tile import tile
Python begins executing Main.py. It sees the import, and so goes to execute Tile.py. Note that it has not yet executed the class statement!
So Python begins executing Tile.py. It sees an import from Main, and it already has that module in memory, so it doesn't re-execute the code in Main.py (even worse things would go wrong if it did). It tries to pull out a variable main from the Main module, but the class statement binding main hasn't executed yet (we're still in the process of executing the import statement, advice that line). So you get the error about there not being a clsss main in module Main (or Tile, if you started from there).
You could avoid that by importing the modules rather than importing classes out of the modules, and using qualified names, but then you'd fall one line down when Main.main doesn't work. Your code makes no sense I'm a dynamic language; you can't have both the definition of class main wait until after tile.assign has been called and the definition of class tile wait until after main.assign has been called.
If you really need this circular dependency (it's often, but not always a sign that something has gone wrong at the design stage), then you need to separate out "scaffolding" like defining classes and functions and variables from "execution", where you actually call classes and functions or use variables. Then your circular imports of the "scaffolding" will work even though none of the modules will be properly initialized while the importing is going on, and by the time you get to starting the "execution" everything will work.