How to use time.sleep() within a function correctly? - python

Long story short i am making an rpg game (text based) in python and need a little help. I am using the time library to give a delay between certain ASCII banners popping up in the console. However, i dont want to have to write out 'time.sleep()' or copy and paste it every time i want to use it. Therefore, i made a function which I would use to shorten the time it would take me to right out 'time.sleep()':
def wait(time):
time.sleep(time)
wait(1)
Whilst in theory i thought this would work (im new to python, i have much to learn yet), it gives me this error:
time.sleep(time)
AttributeError: 'int' object has no attribute 'sleep'
I was wondering if anyone could help/point me in the right direction on how to go about this problem. Thanks in advance!

You are using the same name for the module and the function parameter, so the parameter (a local variable) is shadowing the module (a global variable). Change the parameter:
def wait(how_long):
time.sleep(how_long)

You could use a different name for your parameter, so it doesn't hide the namespace within your function:
def wait(period):
time.sleep(period)
Or you could eliminate your function altogether by importing sleep under a different name:
from time import sleep as wait

Related

How to invoke a function that has a parameter(s) without using parenthesis in Python

I'm building a data visualization app in Python using Tkinter for the GUI and data science libraries Matplotlib, Seaborn, Pandas and NumPy for the backend.
I have the following line of code where button["command"] is the command for a Tkinter Button which is assigned to a function self.create_analytics_dashboard(button_plots) that creates a new Tkinter frame when the button is pressed. The button plots argument is an object responsible for displaying the right plots based on the button pressed.
button["command"] = self.create_analytics_dashboard(button_plots)
There are 3 pertinent Tkinter frames to this problem:
main_dashboard
plots_dashboard
analytics_dashboard
The first 2 frames simply contain buttons that navigate to the next frame and the anaylytics_dashboard frame has buttons which displays the actual visualizations.
The expected order of these frames is as listed above however, due to the line where I assign the button["command"] aforementioned, the program skips the plots_dashboard and goes from the main_dashboard directly to the analytics_dashboard.
There are no error messages however, if I remove the parenthesis and the parameter inside it (button_plots) as shown in the line below the program will display the frames in the right order without skipping the plots_dashboard frame:
button["command"] = self.create_analytics_dashboard
Obviously, I have tried Googling it but all the results just seem to talk about the difference between invoking functions with and without parenthesis or the purposes of each. This article helps explain the difference quite succinctly:
When we call a function with parentheses, the function gets execute and returns the result to the callable.
In another case, when we call a function without parentheses, a function reference is sent to the callable rather than executing the function itself.
So, since the function works as intended when I don't use parenthesis i.e. send a function reference to the callable rather than executing the function itself, I tried using a partial function from the functools library to see if it would work:
from functools import partial
...
button_command = partial(self.create_analytics_dashboard)
button["command"] = button_command(button_plots)
Unfortunately, nothing changed. The plots_dashboard frame was still skipped as before. I need a way to pass button_plots as an argument so it can be used in the self.create_analytics_dashboard function without using parenthesis since this will just execute the function rather than sending a function reference to the callable.
If there is another way of passing a variable from one function in a class to another function in the same class in Python then that could work as well. I simply need the button_plots variable to be available in the self.create_analytics_dashboard function one way or another.
Apologies for the long post but this has been bothering me for a long time so I tried to give as much as detail as possible. If anything in the question does not make sense please let me know. Any help is much appreciated.
Thanks
To use functools.partial you must include the arguments when you create the partial function:
button_command = partial(self.create_analytics_dashboard, button_plots)
button["command"] = button_command
Or, more concisely:
button["command"] = partial(self.create_analytics_dashboard, button_plots)

putting inner python function at the bottom of the code

How can I put an inner python function at the bottom of the code, and call it from the beginning?
For example, VBA dosent care where the phisical inner function code is.
Rexx ( which is also interpreter) also does not care.
How can I do it in Python?
It is much easier to understand the code when the functions are at the bottom.
thanks
You could not do that.
Python runs your code from top to bottom, so it first needs to declare your functions to access them later. You can not first access, later declare, because you would tring to access non exsistent values.
In compiled code, it may works. But in script languages, like python, it does not. As far as I know.
You can do like this:
def main():
print(f(3))
def f(x):
return x * x
if __name__ == "__main__":
main()
Or do you talk about nested functions?
BTW: using the construct in the bottom of my example is anyway good practice to execute the main code only if the module is called as a script. And if it isn't, code shouldn't be extensively executed anyhow before the module is imported (and functions called from outside).

Python nameError help when importing from another file

I have a function in maya that imports in other functions and creates a shelf with buttons for specific functions. I have a function that has a scriptJob command that works fine. if I import that file in manually and not through the shelf button, but gives a NameError when using the shelf script to run it.
This is an example of the script
myShelf.py file:
import loopingFunction
loopingFunction.runThis()
loopingFunction.py file:
import maya.cmds as mc
def setSettings():
#have some settings set before running this
runThis()
def runThis():
print "yay this ran"
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',runThis"])
if I run this through the shelf function, I get a runThis nameError is not defined and if I try modifying the scriptJob command to loopingFunction.runThis, I get a nameError loopingFunction is not defined(not sure if using loopingFunction.runThis is even correct, to be honest)
Not sure how I can get around this without having to manually import in the function rather than through the shelf file.
Using string references for callback functions like this often leads to scope problems. (More on that, and why not to use strings, here)
If you pass the function directly to the callback as an object, instead of using a string, it should work correctly as along as you have actually imported the code.
in this case you want an evalDeferred -- do you actually need it? -- so it helps to add a little function around the actual code so that the scriptjob creation actually happens later -- otherwise it will get evaluated before the deferral is scheduled.
def runThis():
print "callback ran"
def do_scriptjob():
cmds.scriptJob(ro=True, ac=('someMesh.outMesh', runThis)
cmds.evalDeferred(do_scriptjob)
In both runThis and do_scriptjob I did not add the parens -- we are letting the evalDeferred and the scriptJob have the function objects to call when they are ready. Using the parens would pass the results of the functions which is not what you want here.
Incidentally it looks like you're trying to create a new copy of the scriptJob inside the scriptJob itself. It'd be better to just drop the runOnce flag and leave the scriptJob lying around -- if something in runThis actually affected the someMesh.outMesh attribute, your maya will go into an infinite loop. I did not change the structure in my example, but I would not recommend writing this kind of self-replicating code if you can possibly avoid it.
You have a problem of nested/maya scope variables
mc.scriptJob(ro=True,ac=["'someMesh.outMesh',runThis"]
This line is a maya command string that is evaluated in the main maya scope (like a global)
As your function have a namespace with the import : 'loopingFunction', you need to enforce it in the string command.
import loopingFunction
loopingFunction.runThis()
You should write
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',loopingFunction.runThis"])
If you want something more general, you can do :
def runThis(ns=''):
print "yay this ran"
if ns != '':
ns += '.'
evalDeferred(mc.scriptJob(ro=True,ac=["'someMesh.outMesh',{}runThis".format(ns)])
and then run in shelf :
import loopingFunction
loopingFunction.runThis('loopingFunction')
like this you can write any formof namepsaces :
import loopingFunction as loopF
loopF.runThis('loopF')

Maya: Defer a script until after VRay is registered?

I'm trying to delay a part of my pipeline tool (which runs during the startup of Maya) to run after VRay has been registered.
I'm currently delaying the initialization of the tool in a userSetup.py like so:
def run_my_tool():
import my_tool
reload(my_tool)
mc.evalDeferred("run_my_tool()")
I've tried using evalDeferred within the tool to delay the execution of the render_settings script, but it keeps running before VRay has been registered. Any thoughts on how to create a listener for the VRay register event, or what event that is? Thanks!
EDIT:
Made a new topic to figure out how to correctly use theodox's condition/scriptJob commands suggestion here.
Uiron over at tech-artists.com showed me how to do this properly. Here's a link to the thread
Here's the post by uiron:
"don't pass the python code as string unless you have to. Wherever a python callback is accepted (that's not everywhere in Maya's api, but mostly everywhere), try one of these:
# notice that we're passing a function, not function call
mc.scriptJob(runOnce=True, e=["idle", myObject.myMethod], permanent=True)
mc.scriptJob(runOnce=True, e=["idle", myGlobalFunction], permanent=True)
# when in doubt, wrap into temporary function; remember that in Python you can
# declare functions anywhere in the code, even inside other functions
open_file_path = '...'
def idle_handler(*args):
# here's where you solve the 'how to pass the argument into the handler' problem -
# use variable from outer scope
file_manip_open_fn(open_file_path)
mc.scriptJob(runOnce=True, e=["idle", idle_handler], permanent=True)
"

Call a function from main script in an imported file

Before I begin, I know there are many questions that sound a lot like this one, but my question is a little different... So here it is...
As the title may of suggested, I am trying to call a function defined in my main.py script in an imported module. However, this situation is a bit different than that of a circular import situation. I have been doing a lot with pygame recently, and decided that I was gonna make a module that contains classes for buttons, text, sounds, and so on. But I want this file to be generic so it can be used with any game or application I make. Buttons usually have draw functions and stuff like that, so I can easily pass those variables into the functions without problem. The problem comes when I get to the part where I want to check if the button is clicked, and if it is do something. I want to have it set up so that I can pass in a string argument for a command, and use the eval() command on it (python 2.7). However, it throws the error of the function not being defined. I know why this is, but I want to see if there is anything I can do to get around this issue to keep the module as "generic" as possible. Below is a basic set of code to help explain what I want to do.
module1.py
class Button(object):
def __init__(self,x=0,y=0,image=None,command=""):
self.x = x
self.y = y
self.image = image
self.command = command
"""
Image this part filled with draw commands and stuff...
These functions work perfectly fine
"""
#Now here is the issue - local is mouse position
def checkClick(self, local):
#If statments here to determine if mouse over button and
#if mouse is clicked... The part below fails
eval(self.command)
main.py
import module1
import pygame
def quitgame():
pygame.quit()
quit()
local = pygame.mouse.get_pos()
b = module1.Button(command="quitgame")
#At this point lets assume that the mouse is overtop the button and the
#following function in the button will run
b.checkClick(local)
The error, as I said before states that the function I try to call is not defined. I have found a workaround for this, so I don't want answers that tell me how I can change this so it does not take a command as input. I would like however, to make it so I can input a command as an argument. Maybe I am not inputing a command the way I should, but I would like to do it like this, especially because the tkinter module allows you to enter a command as input/a variable. Maybe there is not a way to do this like I wish, but I really want to keep this code as reusable as possible with no changing required between games, and I would rather not have to put this code into my games/applications every time I make them (like I said before the code example I gave was just an example, my actual button code is much larger than what I did above). Like I said before as well, I know that there are many questions that are just like this one, but they have not helped me at all with this issue. The others suggested using scripts that are imported as well which contain addition variables and such, but I would rather not do this. Also, I have a workaround that completely gets rid of the issue, but it is not nearly as neat or easy as this would be.
As always, any help would be appreciated and thanks ahead of time for your answers in case I don't get back to you right away.
I want to have it set up so that I can pass in a string argument for a command, and use the eval() command on it (python 2.7).
No, no, no. Pass it a function:
# In main.py
b = module1.Button(command=quitgame)
# In module1.py
def checkClick(self, local):
...
self.command()
eval is almost never the right tool for any job.
If you don't want to define a function just to pass it as a command parameter, you can use a lambda for short (single-expression) functions:
b = module1.Button(command=lambda: do_whatever(some, arguments))

Categories

Resources