Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Deadite
Aug 30, 2003

A fat guy, a watermelon, and a stack of magazines?
Family.

Gobbeldygook posted:

I am a coding newbie working through Learn Python The Hard Way. For exercise 36 he says to make a text-based adventure game. I decided to add quicktime events, which requires timed input. I found a complicated, Windows-only method on reddit and it works fine, but I decided to try to make the seemingly simple crossplatform solution work just for it's own sake. Here is what I have:

code:
from threading import Timer

def dead():
    print("You are dead!")

def samurai():
    timeout = 5
    t = Timer(timeout, dead, [])
    t.start()
    print(f"You take one out and engage the other! You have {timeout} seconds per move\n")
    print("HIGH STAB\n1. DUCK\n2. JUMP\n3. PARRY\n4. STRIKE")
    answer = input()
    answer = int(answer)
    if answer == 1:
        t.cancel()
        t.start()
        print("HE\'S OPEN\n1. DUCK\n2. JUMP\n3. PARRY\n4. STRIKE")
        answer = input()
        answer = int(answer)
        if answer == 4:
            t.cancel()
            print("VICTORY!")
        else:
            t.cancel()
            dead()
    else:
        t.cancel()
        dead()
    t.cancel()

samurai()
The way I thought this would work is after the player put in a correct move I could cancel the timer and then start a new timer for the next move. After inputting "1" I get "RuntimeError: threads can only be started once".

Is there some easy way to do what I want or should I stick to my Windows-only method?

The easiest way to fix this would just be to reset t to a new Timer object, like

code:
if answer == 1:
        t.cancel()
        t = Timer(timeout, dead, []).start()
I don't know if that is the best way to fix it though

Adbot
ADBOT LOVES YOU

King Cocoa Butter
Mar 24, 2021

Don't be ashy.

Gobbeldygook posted:

I am a coding newbie working through Learn Python The Hard Way. For exercise 36 he says to make a text-based adventure game. I decided to add quicktime events, which requires timed input. I found a complicated, Windows-only method on reddit and it works fine, but I decided to try to make the seemingly simple crossplatform solution work just for it's own sake. Here is what I have:

code:
from threading import Timer

def dead():
    print("You are dead!")

def samurai():
    timeout = 5
    t = Timer(timeout, dead, [])
    t.start()
    print(f"You take one out and engage the other! You have {timeout} seconds per move\n")
    print("HIGH STAB\n1. DUCK\n2. JUMP\n3. PARRY\n4. STRIKE")
    answer = input()
    answer = int(answer)
    if answer == 1:
        t.cancel()
        t.start()
        print("HE\'S OPEN\n1. DUCK\n2. JUMP\n3. PARRY\n4. STRIKE")
        answer = input()
        answer = int(answer)
        if answer == 4:
            t.cancel()
            print("VICTORY!")
        else:
            t.cancel()
            dead()
    else:
        t.cancel()
        dead()
    t.cancel()

samurai()
The way I thought this would work is after the player put in a correct move I could cancel the timer and then start a new timer for the next move. After inputting "1" I get "RuntimeError: threads can only be started once".

Is there some easy way to do what I want or should I stick to my Windows-only method?

To elaborate on Deadite's answer, threading.Timer objects inherit from threading.Threads, which cannot be start()ed more than once. So you can create new objects as suggested above (and/or use the RepeatableTimer solution in that SO link) instead of cancel()ing them, or for extra credit, use time.time() and a loop to make your own timer.

NinpoEspiritoSanto
Oct 22, 2013




Please please learn from anything other than Learn Python the Hard Way. Author doesn't even understand python 3 properly.

Gobbeldygook
May 13, 2009
Hates Native American people and tries to justify their genocides.

Put this racist on ignore immediately!

Deadite posted:

The easiest way to fix this would just be to reset t to a new Timer object, like

code:
if answer == 1:
        t.cancel()
        t = Timer(timeout, dead, []).start()
I don't know if that is the best way to fix it though
So now that section looks like this:
code:
    if answer == 1:
        t.cancel()
        t = Timer(timeout, dead, []).start()
        print("HE\'S OPEN\n1. DUCK\n2. JUMP\n3. PARRY\n4. STRIKE")
        answer = input()
        answer = int(answer)
        if answer == 4:
            t.cancel()
            print("VICTORY!")
It fixes the runtimeerror but now:

quote:

You take one out and engage the other! You have 5 seconds per move

HIGH STAB
1. DUCK
2. JUMP
3. PARRY
4. STRIKE
1
HE'S OPEN
1. DUCK
2. JUMP
3. PARRY
4. STRIKE
4
Traceback (most recent call last):
File "C:\Users\gobb\coding\ex36-combat-rewrite.py", line 211, in <module>
samurai()
File "C:\Users\gobb\coding\ex36-combat-rewrite.py", line 201, in samurai
t.cancel()
AttributeError: 'NoneType' object has no attribute 'cancel'
You are dead!
The final "You are dead!" comes a few seconds after I input "4", so the t.cancel() is not cancelling the second timer. I've done some experiments and I'm sure the first timer is correctly ending, but the second timer does not cancel. Any idea why?

A bigger problem is that the timer going off and triggering the dead() function doesn't actually prevent the player from just ignoring the error, putting in the correct move, and continuing like nothing happened.

King Cocoa Butter posted:

To elaborate on Deadite's answer, threading.Timer objects inherit from threading.Threads, which cannot be start()ed more than once. So you can create new objects as suggested above (and/or use the RepeatableTimer solution in that SO link) instead of cancel()ing them, or for extra credit, use time.time() and a loop to make your own timer.
Thanks, I now better understand why my idea didn't work.

After some fumbling I figured out how to make my own timer with time.time(), that's neat. I did some further searching and found a simple module that does exactly what I want and then some via the time.time() method, so I'm just going to use his work.

NinpoEspiritoSanto posted:

Please please learn from anything other than Learn Python the Hard Way. Author doesn't even understand python 3 properly.
Thanks for the heads-up, I was unaware of the authors jihad against Python 3, I'll go through another python 3 introductory text (probably Think Python or an MIT OCW, as suggested in the OP) when I'm done.

death cob for cutie
Dec 30, 2006

dwarves won't delve no more
too much splatting down on Zot:4

NinpoEspiritoSanto posted:

Please please learn from anything other than Learn Python the Hard Way. Author doesn't even understand python 3 properly.

I know people had some opinions about Zed Shaw, mostly because he has a lot of opinions that he can't seem to keep his mouth shut about, but what about the book is improper re: python 3? I learned my basics from the Python 2 version and flipped through the third, and at the time nothing stood out to me.

nollij
Aug 30, 2006

Wait, wait, wait...

When did this happen?!?
Bit of a newbie to python and regressors... so I’m running nested loops with scikit-learn to iterate through parameters on training a Gradient Tree Boosted Regressor and saving the “high score”. Dataset is 6,000 samples with 25 features.

The loop has been running for 2 days. If I interrupt the kernel, will it dump the values for the current block or will it still save my current “high score” for the loop?

Also, yes, I know about overfitting but I don’t know enough to train a Regressor manually on a Dataset yet. The Decision Tree Regressor ran 5400 times and took about 20 minutes. There are 94500 iterations in the Gradient Tree Boosted Regressor nested loops. Does this sound like days or years here?

NinpoEspiritoSanto
Oct 22, 2013




Epsilon Plus posted:

I know people had some opinions about Zed Shaw, mostly because he has a lot of opinions that he can't seem to keep his mouth shut about, but what about the book is improper re: python 3? I learned my basics from the Python 2 version and flipped through the third, and at the time nothing stood out to me.

It's just not good learning material, concepts are often taught out of order, a lot is outdated or just not pythonic and it's all rote style. Think Python is far superior as a beginner's resource and actually explains programming concepts as well as how they apply with Python. I can dig up more specifics if you like when not phone posting but it's been a while since it was generally dropped as a recommended starting point and considered shite.

MrMoo
Sep 14, 2000

What's the latest simple API for generating a HTTP service with Swagger spec? Falsy looks pleasantly minimal but hasn't updated in 4 years.

CarForumPoster
Jun 26, 2013

⚡POWER⚡

MrMoo posted:

What's the latest simple API for generating a HTTP service with Swagger spec? Falsy looks pleasantly minimal but hasn't updated in 4 years.

FastAPI is the currently talked about quick to make python API and swagger UI is included by default. I havent used it but have been meaning to for a while.

Macichne Leainig
Jul 26, 2012

by VG

CarForumPoster posted:

FastAPI is the currently talked about quick to make python API and swagger UI is included by default. I havent used it but have been meaning to for a while.

This actually looks neat, although my only exposure to it is limited, and the API that my offshore peers put together with FastAPI is not very stable. It's not really fair to blame FastAPI itself at this point, might point fingers at the offshore team instead, but that's neither here nor there anyway.

NinpoEspiritoSanto
Oct 22, 2013




I've done stuff with FastAPI it's pretty good

CarForumPoster
Jun 26, 2013

⚡POWER⚡

NinpoEspiritoSanto posted:

I've done stuff with FastAPI it's pretty good

I deployed an unauthenticated hello world API to heroku with FastAI just now in about 10 minutes. Gonna try adding auth, if this works it might just be when I use for the backend I need to build.

CarForumPoster
Jun 26, 2013

⚡POWER⚡

CarForumPoster posted:

I deployed an unauthenticated hello world API to heroku with FastAI just now in about 10 minutes. Gonna try adding auth, if this works it might just be when I use for the backend I need to build.

I came back to it to see if it was easy enough to do API keys. There was a blog about it. And I got that deployed by basically copy pasting and changing the API code. This combined with coming up with some dependencies I could get smaller versions of means I can likely put my deep learning app's back end on Heroku, simply downloading the large model(s) from S3!

MrMoo
Sep 14, 2000

CarForumPoster posted:

FastAPI is the currently talked about quick to make python API and swagger UI is included by default. I havent used it but have been meaning to for a while.

Thanks, surprisingly easy, even with almost zero Python knowledge.

Trying to get Python do everything async is hilarious.

NinpoEspiritoSanto
Oct 22, 2013




Trio takes a lot of pain out of that for general python, but so does FastAPI here since you can easily perform async tasks staying within the framework's idioms.

Jose Cuervo
Aug 25, 2004
I have written a function in Python named load_clustering. I have used this function in a number of places in other code. I now realise that a more appropriate name for this function is load_classification. Is there a way to modify the name of the function so that from now on I can use it as load_clustering, but keep the old name as well so that the older code with the old name of load_clustering does not break?

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Jose Cuervo posted:

I have written a function in Python named load_clustering. I have used this function in a number of places in other code. I now realise that a more appropriate name for this function is load_classification. Is there a way to modify the name of the function so that from now on I can use it as load_clustering, but keep the old name as well so that the older code with the old name of load_clustering does not break?

Pycharm has refactoring options that I'd bet cover this use case by simply replacing that function where called.

Jose Cuervo
Aug 25, 2004

CarForumPoster posted:

Pycharm has refactoring options that I'd bet cover this use case by simply replacing that function where called.

I would normally do that but another person is using the code as well, and for the sake of argument assume I cannot get them to refactor the code which they are using.

OnceIWasAnOstrich
Jul 22, 2006

Jose Cuervo posted:

I have written a function in Python named load_clustering. I have used this function in a number of places in other code. I now realise that a more appropriate name for this function is load_classification. Is there a way to modify the name of the function so that from now on I can use it as load_clustering, but keep the old name as well so that the older code with the old name of load_clustering does not break?

Assuming this is exactly what you want, you can just do load_clustering = old_func_name and use/import the new name. Functions are just objects that you can create new references to like most other objects. I would recommend refactoring, which could be potentially as easy as a find/replace but is indeed made more easy/reliable with refactoring tools like PyCharm or other IDEs have.

Bad Munki
Nov 4, 2008

We're all mad here.


Submit a pull request to the other person’s code?

Macichne Leainig
Jul 26, 2012

by VG

Jose Cuervo posted:

I would normally do that but another person is using the code as well, and for the sake of argument assume I cannot get them to refactor the code which they are using.

Can you not just work with the other person to have like a cutoff day for the old function name?

Jose Cuervo
Aug 25, 2004
Okay, it seems like the right thing to do is refactoring and getting the other person to start using the new code. Will do. Thanks.

Wallet
Jun 19, 2006

OnceIWasAnOstrich posted:

Assuming this is exactly what you want, you can just do load_clustering = old_func_name and use/import the new name. Functions are just objects that you can create new references to like most other objects. I would recommend refactoring, which could be potentially as easy as a find/replace but is indeed made more easy/reliable with refactoring tools like PyCharm or other IDEs have.

In the case where for whatever reason it's difficult/impossible to get the existing calls refactored it's not super uncommon to leave the old function in place in some form (even if that's just basically calling the new function) and have it emit a deprecation warning for an appropriate amount of time.

Soylent Pudding
Jun 22, 2007

We've got people!


My program writes a bunch of output files I open using WITH. If the program crashes due to an exception or interrupt (Ctrl+c) I'd rather erase all the files than have partially written output. What's the bast way to handle these cases? Since my program creates a new output directory do I just delete the output directory in the signal and exception handlers then exit?

Data Graham
Dec 28, 2009

📈📊🍪😋



Making an assumption that the partially written output is not like, a security risk or something, my inclination would be to have the output directory be named with a temp-file prefix of some sort and then whenever you run the script it cleans up all pre-existing temp directories. Then if it successfully completes, it renames the folder to a "good" name.

NinpoEspiritoSanto
Oct 22, 2013




I'd have a clean up function in your exception handling. Nothing worse than a program that leaves random useless poo poo laying around because it crashed especially if the data is sizeable and someone else is wondering what it is 6 months later

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Soylent Pudding posted:

My program writes a bunch of output files I open using WITH. If the program crashes due to an exception or interrupt (Ctrl+c) I'd rather erase all the files than have partially written output. What's the bast way to handle these cases? Since my program creates a new output directory do I just delete the output directory in the signal and exception handlers then exit?

Yep, and python makes that pretty easy: https://docs.python.org/3/tutorial/errors.html#defining-clean-up-actions

Hollow Talk
Feb 2, 2014

Note that this always gets executed, so unless you move your correctly written files, it'll happily delete those without an exception as well.

Soylent Pudding
Jun 22, 2007

We've got people!


Do I have to go back and change everyone else's code from using "with" to "try-finally" for every file write or is there a similar final functionality I can use with the with syntax?

CarForumPoster
Jun 26, 2013

⚡POWER⚡

Soylent Pudding posted:

Do I have to go back and change everyone else's code from using "with" to "try-finally" for every file write or is there a similar final functionality I can use with the with syntax?

Yea, how many with statements we talkin? Is the code conducive to making a function then just passing that function your params?

Soylent Pudding
Jun 22, 2007

We've got people!


Maybe a dozen or so minimum. Without getting into too many details since it's a work thing we're taking a bunch of tiny helper diagnostic scripts people have written and writing a central controller to manage the whole library and deploy them as narrowly or widely as needed.


Could I do what I want with:
code:

def signal_handler(args):
     delete_temp_output_dir()
     sys.exit(0)

def main():
     signal.signal(signal.SIGNAL, signal_handler())

     try:
           call_scripts()
           rename_temp_output_dir()
     finally:
           delete_temp_output_dir()

DoctorTristan
Mar 11, 2006

I would look up into your lifeless eyes and wave, like this. Can you and your associates arrange that for me, Mr. Morden?
If you’re doing that you might as well write a new context manager that deletes the tempfile on completion. Phone posting so can’t provide a snippet, but could post one later if no one else obliges in the meantime…

QuarkJets
Sep 8, 2008

Yeah if you just want to guarantee that something gets done, even if an exception gets raised, that's already a core feature of context managers. So the simpler change would be to modify your context manager, not to rip out a dozen context blocks and replace them with try/finally blocks.

More generally, if you were about to write a bunch of near-identical try/except/finally blocks, I would argue that you should define a context manager instead

Soylent Pudding
Jun 22, 2007

We've got people!


QuarkJets posted:

Yeah if you just want to guarantee that something gets done, even if an exception gets raised, that's already a core feature of context managers. So the simpler change would be to modify your context manager, not to rip out a dozen context blocks and replace them with try/finally blocks.

More generally, if you were about to write a bunch of near-identical try/except/finally blocks, I would argue that you should define a context manager instead

I guess my homework assignment is learning about the context manager.

12 rats tied together
Sep 7, 2006

the context manager is pretty easy and is a great python feature, you basically just define __enter__ and __exit__ methods on your class. __enter__ should return the thing that you want assigned as the result of your "as", __exit__ happens when your program leaves the scope of your "with". your __exit__ needs to have 4 params because the python runtime will pass those params in an exit block, they're for handling return codes and stuff like that

temp file access is gnarly which is probably why nobody posted a code sample. here's a really lovely one:

Python code:
import os
import subprocess  

class TempFile():
    def __init__(self, path):
        self.path=path

    def __enter__(self):
        # opened in 'w' mode to create if it doesn't exist already
        open(self.path, 'w')
        # opened again in 'r+b' mode so we can read/write it
        return open(self.path, 'r+b')

    def __exit__(self, exc_type, exc_value, traceback):
        os.remove(self.path)

with TempFile(path='./tmp') as tf:
    tf.write('xyz')
    tf.seek(0)
    # output returns the file contents as a list of lines, in this case, one element: ['xyz']
    print(tf.readlines())

    # output shows that the file './tmp' exists at the moment
    print(subprocess.call('ls'))

# output shows that the file './tmp' no longer exists
print(subprocess.call('ls'))

Soylent Pudding
Jun 22, 2007

We've got people!


Thanks! This is definitely a part of python I know almost nothing about. My CS degree focused on C++ and I've spent the past few years working in IT not as a developer.

12 rats tied together
Sep 7, 2006

Sure thing, keep in mind that your OS might have a convention for temp files as well, for example /tmp on a linux/unix system is often a tmpfs which resides in virtual memory and doesn't survive reboots.

e:

OnceIWasAnOstrich posted:

You could also use the built-in tempfile TemporaryDirectory which comes pre-built as a context manager and move the files out of the directory once they are successfully written. This also has the advantage of automatically choosing a platform-dependent location by default.

this is badass and yeah you should totally use this instead of writing your own thing. python standard library is pretty good

12 rats tied together fucked around with this message at 20:54 on Aug 2, 2021

OnceIWasAnOstrich
Jul 22, 2006

You could also use the built-in tempfile TemporaryDirectory which comes pre-built as a context manager and move the files out of the directory once they are successfully written. This also has the advantage of automatically choosing a platform-dependent location by default.

You can also do this on a file-by-file basis with TemporaryFile context managers but the directory seemed more appropriate for the original request. As mentioned, this is probably going to be better and handle edge cases more effectively than anyone is this thread could manage on their first try.

OnceIWasAnOstrich fucked around with this message at 20:58 on Aug 2, 2021

QuarkJets
Sep 8, 2008

Soylent Pudding posted:

Thanks! This is definitely a part of python I know almost nothing about. My CS degree focused on C++ and I've spent the past few years working in IT not as a developer.

Just know that __exit__ is roughly equivalent to finally (i believe), it always gets called even if an exception is raised. That's the real beauty of a context manager, it lets you encapsulate your exit behavior and leaves behind a nice and concise statement that is reusable

Adbot
ADBOT LOVES YOU

D34THROW
Jan 29, 2012

RETAIL RETAIL LISTEN TO ME BITCH ABOUT RETAIL
:rant:
Already kicking myself. I've got 4 kids and sometimes I want to randomly pick one for something, or randomize the order they do things. I typically use a d4 for this...but I just thought "hey, I'm learning Python, why not build an app for it"? Android development on Windows looks like fun! :suicide:

All seriousness though i adore a challenge so...any advice is more than welcome.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply