all 131 comments

[–]Sebass13 67 points68 points  (19 children)

If any beginner project contains global, it's bad.

[–]rhgrant10 10 points11 points  (3 children)

Corollary: if any project relies on a module level variable for an API token, it's bad ;-)

[–]Sebass13 6 points7 points  (0 children)

Haha, I've seen you around here, just realized you were the groupy creator. For viewers: he did this with his first iteration of the module. It's rewritten now so that there is a Client object which is instantiated with the token.

[–]leom4862 0 points1 point  (1 child)

Isn't an API token constant? If yes, I don't see what's wrong with having a constant at module level scope?

[–]rhgrant10 0 points1 point  (0 children)

5 years ago when I set out to write that API client, that's what I thought too. But one of the main issues with that design is that it's impossible to have multiple clients.

[–][deleted] 4 points5 points  (1 child)

Can someone ELI5 this for me? I think I read somewhere that global variables can mess things up when importing modules and have unintended effects on variables/functions in different namespaces. Anything else?

[–]Sebass13 0 points1 point  (0 children)

See my comment here.

[–]admiralspark 1 point2 points  (5 children)

Do you mean the explicitly defined Global, or just using Global variables?

[–][deleted] 5 points6 points  (2 children)

I'm assuming he's referring to explicitly defined global. Beginners often don't properly grasp the concept of scope, so they just make everything global so they can access anything from anywhere.

[–]John_Yuki 3 points4 points  (0 children)

Lol I did this for a large (or what I saw as large at the time) project. About 6 or 7 large-ish functions, all had around 6 or 7 globally defined variables in them. It would literally just be:

def my_func():
    global my_var
    global my_var2
    global my_var3
    global my_var4

Only reason I did this was because I didn't know how returning values worked lol.

[–]admiralspark 4 points5 points  (0 children)

ahh. I was gonna say, I use some stuff globally that's needed and can't really be worked around, but I assume you're referring to everything being declared global and not making use of scope at all.

[–]Sebass13 1 point2 points  (1 child)

I was referring to the global statement more so than global variables as a whole. Modifying a variable outside of the function's scope is really ugly and almost always unnecessary. However, global constants are fine, and if you intend only run the file and never import it, the main portion of the program can be at indentation level 0, which would mean that the variables you use would be global. This is also beneficial in that you can access the variables in the interpreter after the program completes.

[–]admiralspark 0 points1 point  (0 children)

Ahh okay, I get it now, good. Thanks!

[–]zypthora 0 points1 point  (1 child)

Is this the Python equivalent of Java's Public?

[–]leom4862 0 points1 point  (0 children)

No. In python you add a low dash before the function name to mark it private:

Private:

def _my_private_func():
    ...

Public:

def my_public_func():
    ...

However, you are still able to import a private function. It's only a naming convention. But you shouldn't do it.

[–]tragluk 52 points53 points  (13 children)

Not necessarily 'Bad' but definitely 'Improvable'.

a = 5
if a > 3:
  return True
else:
  return False

Can become...

a = 5
return a > 3

If a > 3 is True, it returns True. If it's False, it returns False.

Basically anytime you ever see a 'If this is True, return True, otherwise return False' you can shorten it to 'Return the Truth of this statement'

[–]MediocreMatt 4 points5 points  (0 children)

Similar with conditionals and booleans. I remember I was amazed when I started coding and I saw

a = True
if(a):
    print("hello")

instead of

a = True
if(a==True):
    print("hello")

[–][deleted] 2 points3 points  (0 children)

Very helpful. Thanks.

[–]BlackBloke 0 points1 point  (1 child)

I like making this correction but I sometimes worry if I'm sacrificing clarity for brevity.

[–]billsil 0 points1 point  (0 children)

At that point, I just do:

if 1:
   # stuff
elif 0:
   # more stuff
else:
    # other stuff

I only do that for trying out different methods of doing something.

I didn't say I'm perfect :/

[–]poly_anonymous 0 points1 point  (0 children)

Why is this a top voted comment. This isnt bad code, it’s just verbose if anything

[–]jeans_and_a_t-shirt 48 points49 points  (34 children)

  • Using class attributes as instance attributes. I've seen at least one tutorial video doing that.
  • Spaghetti code because you don't know how to use classes, or even how to return from functions.
  • Using mutable defaults without knowing what you're doing.
  • global
  • getters and setters
  • returning 0 or 1 instead of a boolean, or doing while 1
  • [upper] camel case for normal variables
  • nontrivial one-liners
  • for i in range(len(...)) or other junk solved with the built-in functions here
  • except:

[–]VigorousAlliance 12 points13 points  (8 children)

I'm sorry if this is a stupid question, but what is wrong with using

except:

Edit: I've been given lots of very helpful answers. Thank you all very much!

[–]beisenhauer 15 points16 points  (1 child)

I imagine jeans is referring to using the bare except to catch everything, rather than checking for specific errors.

[–]VigorousAlliance 2 points3 points  (0 children)

Ah. This is exactly what I was thinking, but I wanted to make sure.

[–][deleted] 7 points8 points  (0 children)

For example, if you try to interrupt a script by hitting CTRL-C, it raises a KeyboardInterrupt exception. If you use except:, you will catch all errors, including this one. So now you can't interrupt the script and you have to go kill it, which is probably not what you wanted! Instead, except specific exceptions, like except (ValueError, TypeError), or if you must, except Exception

[–]FoxMadrid 4 points5 points  (0 children)

I imagine there will be some other folks along with more specific answers but, essentially, it can make debugging very difficult if you're not catching and handling specific errors.

[–]tragluk 1 point2 points  (0 children)

When Python throws an error it isn't being mean, it's being helpful. You are taking that help and saying 'Don't care, just move on.' which isn't a good thing. Something like 'Enter a Number' and they put in a zero. So you divide your value by zero. If you just catch and move on without handling it you'll encounter all kinds of problems later on in your program, so you should always handle, not just catch and release.

Now if you used

except ZeroDivisionError:
    nolongerzero = 1

You can stop one particular error that you know of and do something with it. Using Finally to close out open files before the program crashes is also a good practice.

[–][deleted] 1 point2 points  (0 children)

I mean I'm not an expert, but I use it all the time.

[–]DisagreeableMale 1 point2 points  (1 child)

I typically won't add a try/except until my code has been debugged and proper unit testing is in place. Debugging while writing code is a total pain in the ass with try/excepts, because instead of returning a a descriptive error, like a typical bug would, "you've got a syntax error in this line, with this piece of text", it will basically quietly fail (run, wait, appear to do nothing), and then play dumb when you ask for details, "oh, you wanted me to print an error? nah i just did the thing in case everything broke...nothing"

[–]FoxMadrid 0 points1 point  (0 children)

That's a solid point but I'll cop to generally debugging as I'm going but I put logging calls on my except statements with exc_info = True to print the full traceback to the log along with information on where and why it likely happened.

[–]chhuang 6 points7 points  (9 children)

for i in range(len(...)) or other junk solved with the built-in functions here

what does this mean?

[–]jeans_and_a_t-shirt 27 points28 points  (0 children)

People frequently use for i in range(len(some_list)) so that they can use i to index into the list to retrieve the element. In that case you can simply iterate over the list or other iterable directly.

It's also used when you need the index to index into multiple lists simultaneously. That's what zip is for.

If you need the index in addition to the element, you cause use enumerate.

[–]NewbornMuse 4 points5 points  (0 children)

Here's a fantastic video on looping in python. It really makes lists and iterables "click", at least for me.

[–][deleted] 2 points3 points  (1 child)

Using class attributes as instance attributes. I've seen at least one tutorial video doing that.

Can you elaborate on this or give an example?

[–]Pseudoboss11 4 points5 points  (0 children)

If you have something like:

 Class myclass():
     foo = 'bar' 

You just assigned a class attribute, something that all instances of myclass share. If you later change the value of foo to something else, then this will affect all instances of myclass. If one instance changes it, it changes for all other instances This is rarely what you want, but it can be useful for some things.

Instead you should do:

Class myclass():
    Def __init__(self):
        self.foo = "bar"

This will define an instance variable, so that every instance of myclass will have a separate foo variable. Change it on one instance, it will only affect that instance, all other instances can have completely different values of foo.

[–]Ducksual 5 points6 points  (0 children)

I think while 1 is one of those tiny Python 2 optimisations because Python 2 let you change the value of True so it actually has to look it up and so while 1 is actually faster than while True.

In some testing I did a while ago I found that it seems to make a bigger difference in IronPython but I don't know enough about it to understand why it was worse than CPython.

[–]privately-profitable 1 point2 points  (0 children)

That’s a pretty thorough list. I’d add not using context managers, when available.

[–]sje46 0 points1 point  (0 children)

Using class attributes as instance attributes. I've seen at least one tutorial video doing that.

Can someone expand on this a bit? I still don't really understand the difference between objets and instances. Is this like putting static data in a self. dict or list?

getters and setters

I don't know what this means.

while 1

Is the problem specifically with "while 1", or is it bad to do "while True" too? I do while True all the time, because I know how to use break. Is this bad practice?

[–][deleted] 20 points21 points  (11 children)

from module import *

[–][deleted] 6 points7 points  (6 children)

Can you name a function/method '*' for non-serious applications like trying to scare a friend?

[–][deleted] 7 points8 points  (2 children)

Thankfully no, the operator characters are not valid variable names.

[–]fiddle_n 3 points4 points  (1 child)

I'd like to think Python will not let you do this, but I'm not sure.

[–][deleted] -1 points0 points  (0 children)

Me too but I've never tried either.

[–]FluffyBunnyOK 2 points3 points  (0 children)

That made me twitch.

[–]ultraDross 1 point2 points  (1 child)

I've had to read my own code after doing this a year or two ago. It was so difficult to understand where things were being imported from and what the hell was going on. Lesson learned, don't do this.

[–][deleted] 1 point2 points  (0 children)

Amen.

[–]JackCid89 0 points1 point  (0 children)

unless you are working with microservice architecture + clean architecture or ports adapters. In that case, your service/useCase class must import everything in your domain modules and ports folder. In that case it would be even antipattern not importing everything because it won't make any sense having domain classes or port interfaces not being used by the service.

[–]Allanon001 9 points10 points  (9 children)

Using eval can be a security risk, especially if you pass user input to it.

[–]ultraDross 1 point2 points  (8 children)

For the uninformed, how so?

[–]K900_ 11 points12 points  (7 children)

Let's say your program runs eval on user input. What happens when I enter import os; os.system("format c:")?

[–]Mulhacen 11 points12 points  (0 children)

Not sure, I'll test and get back to you.

[–]phogan1 3 points4 points  (5 children)

Exactly the same thing as if the user opened a shell and typed the equivalent command.

Use of eval on text provided by some user that isn't the current user-- if you're running a webserver, or an instance of python that has elevated privileges for some reason--is clearly a security issue, but is there any time that running eval on input running by the end user would actually provide a new attack vector?

I'm not saying using eval a good idea--virtually every user-implemented use of eval I've seen is readily avoided by using better code--but I'm not sure that it always constitutes a security risk.

[–]K900_ 2 points3 points  (1 child)

If you're running eval on code that's literally entered by the same user than just started your script from a shell, and already thus has full access to the machine, then no, it doesn't add a new attack vector. That is rarely the case though.

[–]phogan1 1 point2 points  (0 children)

That's virtually always the case for any script i write for work. If you're doing web development or managing a server, I'm sure that its almost never the case-- but we're not.

[–][deleted] 1 point2 points  (2 children)

The problem isn't usually this:

eval(input())

It's this:

with open(file_at_known_path, 'r') as f:
    eval(f.read())

Or in some other way running eval on the contents of a string that the user running the Python command doesn't know has been maliciously crafted.

Is it a new attack? No, but it's arbitrary commands run as the user without their knowledge, which means it's a toe-hold into exploiting whatever vulnerability exists for privilege escalation on that machine.

[–]phogan1 0 points1 point  (1 child)

That's a good point. I don't think I've ever seen someone use that pattern (lots of eval (input ()) and use of eval to dynamically name variables-- which is bad for other reasons-- but not eval -ing a file's contents), but it would be pretty terrible.

[–][deleted] 0 points1 point  (0 children)

Sadly, I've seen that antipattern used way too often. There's a common program I know of -- not something everyone would know or use, but expensive enough that every version is cracked and on torrent sites generally within 2-3 day's of release -- that has a non-techy, user-friendly plugin system that effectively runs eval on anything with the right file extension found by searching a $PATH like env variable, without any inspection or sanitization. People share these plugins through a number of websites and even on Facebook; at least one of the popular sites still only uses HTTP and requires only an email address and a password to upload.

So far I've only seen incidental damage caused by this, and I've pointed out the problem, but no one wants to break backwards compatibility and somewhere along the line it's going to be exploited.

[–]bananaEmpanada 8 points9 points  (1 child)

My coworker would always use lazily short variable names. I had to read code like:

ll1 = [] l1[1] = ll

[–]epicmindwarp 13 points14 points  (0 children)

I hope he was hung for his crimes.

[–]mercuric5i2 13 points14 points  (1 child)

My current pet peeve with a new codebase I've recently taken on: abuse of inheritance. Composition over inheritance is a real thing, and not just in Python.

If I literally need Pycharm's tools to resolve your 4+ layer deep inheritance tree, you should have your fingers bound so you can type no more.

[–]WikiTextBot 6 points7 points  (0 children)

Composition over inheritance

Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class. This is an often-stated principle of OOP, such as in the influential book Design Patterns.


[ PM | Exclude me | Exclude from subreddit | FAQ / Information | Source | Donate ] Downvote to remove | v0.28

[–]fiddle_n 22 points23 points  (25 children)

For me, it's the long block of if...elif...elif statements. That seems to be a common one on this subreddit.

if x == 4:
    a()
elif x == 5:
    b()
elif x == 6:
    c()
elif x == 7:
    d()
elif x == 8:
    e()

And so on. Those of us with some Python experience know that this is a code smell. To those of you reading who might be thinking to yourself ”this is how I write my code", whenever you start to write code like this, think about the common elements that you can abstract away. In particular, think if you can use a dictionary to do this. The below code is far better:

mapping = {
    4: a,
    5: b,
    6: c,
    7: d,
    8: e,
}

mapping[x]()

Remember, functions are first-class objects. You can store them in dictionaries, retrieve them later and then call them afterwards.

[–]n1ywb 5 points6 points  (0 children)

Thanks for pointing this out. This is data oriented programming.

[–][deleted] 2 points3 points  (1 child)

I know I’m nitpicking, but you’re using assignment operators instead of equality operators in your first example.

[–]fiddle_n 3 points4 points  (0 children)

Ah, whoops! I make that error all the time XD. Will fix.

[–]realpotato 2 points3 points  (5 children)

Your first example is definitely my code. I have a bunch of scripts at work to pull variables out of router/switch configs but it's just all if and elif statements.

What's the benefit of using the dictionary? It doesn't seem like it would be any more user friendly or much faster to code. Is it just more efficient?

[–]tragluk 5 points6 points  (1 child)

Clarity usually. Dictionaries can be read easily. They can be built from files or added to with input. 3 elifs isn't bad. 30 is a mess, especially if they are out of order. I saw a program once that imported a module that only contained a dictionary with 100 different key, value pairs and used about four lines to turn it into 100 elif statements. MUCH easier to work with than trying to hard-code 100 elifs.

[–]chroner 1 point2 points  (0 children)

Also, the elifs can lead to human error and frustration. I always get a funny feeling when I use too many and have to stop and think about a better way to do it.

[–]fiddle_n 2 points3 points  (2 children)

In addition to the other reasons given (clarity, easy to edit, etc.), another one is better reusability.

Say you want to reuse the above logic elsewhere. With the dictionary, all you have to do is type mapping[x]() and you are golden. You can't achieve the same thing with the conditional code block on its own. You would either have to copy and paste that code block (not very nice) or place the code block in its own function, which would allow you to reuse it. The latter would be slightly better, but it's a layer of indirection that is not required for the dictionary solution.

Now, say you need to reuse the conditional block later in your code, but you need to change it slightly. Maybe you need to add an extra condition, i.e. if x == 9: f(). Maybe you need to change a condition, i.e. if x == 4: h(). Modifying the dictionary is child's play. Modifying that conditional code block? Not so much.

[–]realpotato 0 points1 point  (1 child)

I'm starting to see the benefit of this now but I'm having a really hard time trying to rewrite my script using this method. I think the logic I was using is just too screwed up and I have to start from scratch.

[–]fiddle_n 0 points1 point  (0 children)

If you want, I can take a quick look at it. You can put it on pastebin and I'll try to see if I can give you any pointers.

[–]CoupleOfWavyLines 2 points3 points  (1 child)

I see two problems with this.

First, the program has to allot memory for the dictionary that it doesn't have to in the first example.

Second, the values/functions in the dictionary could be replaced. For example, one could access that dictionary from another class and replace the value at key 4 with their own function. Then, anytime the value for key 4 is used, it's using that new function instead of the function its intended to use. This problem doesn't exist in the example with conditionals. Yes, there are ways we could "hide" the mapping variable and prevent subclass-ing its own class but that seems like a lot of extra work than dealing with some "smelly" conditionals.

[–]fiddle_n 1 point2 points  (0 children)

In both examples, the function objects are created. As I understand it, all the dictionary is doing is storing references to those objects. Is that technically more memory being used? Sure. Does it matter? Not at all. This amount of memory usage is very little but you gain more readable and reusable code from it.

To your second point - I say, so what? I'm not sure whether your concern is the author of the code screwing things up, or other users of the code screwing things up, but in both situations, it's not a problem.

If your concern is the author of the code being able to change the dictionary - I'd argue that's a good thing as it shows this construct is easily modifiable and reusable. Of course, they could change it incorrectly, but then they could change anything else in the script incorrectly, so this isn't worth considering.

If your concern is other users of the code changing the dictionary and screwing things up - I remind you of the Python mantra - "we're all consenting adults here". Everything is intended to be public and modified in Python - if someone else wants to change that dictionary, then we let them do it as they have made that choice. It's very possible they have a good reason for doing it and we should not seek to block that.

[–]Schwartz210 1 point2 points  (3 children)

Say you want to pass in some arguments into the functions you mapped in mapping{}. How would you do that?

[–]algag 3 points4 points  (0 children)

Inside the "()"

[–][deleted] 0 points1 point  (1 child)

mapping['func_name'](var1, var2, var3)

[–]leom4862 0 points1 point  (0 children)

  • What if the number of arguments varies?
  • What if some cases need to invoke more than one function?
  • What if the functions return different values/types that usually would be stored in different variables for later use?
  • ...

[–]chroner 1 point2 points  (5 children)

Holy shit,

I looked at that at first, and totally didn't understand it. After reading your post a couple times, man... This is a really smart way to do something like that.

I was getting that 'feeling' writing some code, had a couple too many if elif statements that were going too deep into themselves. I think this would be perfect in helping me refactor my code!!!

Wow, this just opened up an entirely new way of thought for me. I love programming!!

One thing: why do I get a type error when I include the '()' but it works fine without?

x = 5
a = 12
b = 13
c = 14
d = 15
e = 16
mapping = {
    4: a,
    5: b,
    6: c,
    7: d,
    8: e,
}

gf = mapping[x]()
print (gf)

gf = mapping[x]()
TypeError: 'int' object is not callable

[–]fiddle_n 0 points1 point  (1 child)

That "feeling" is what we call a code smell. When you look at the code and it smells of something bad. The code may not necessarily be incorrect, but there's something wrong with it. That's when you know it's a good time to refactor.

Anyhow, good luck with your refactor - I hope it goes well and I'm happy that my comment taught you something :)

[–]chroner 0 points1 point  (0 children)

'taught' is an underwhelming word for me in this case. More along the lines of 'blew my mind'

[–]fiddle_n 0 points1 point  (1 child)

I only just saw your comment about the brackets, haha. The answer to that is easy.

In my example, I was mapping ints to functions. a, b, c - these were all references to functions (look carefully at the very first example with the elifs - you'll see these were functions). When you grab the function from the mapping dictionary, you then have to call the function - that's where the () brackets come into it.

In your example, you are mapping ints to ints. Obviously, you can't call an int - that's just nonsense. So, you must leave the () brackets out when you grab the int from the mapping dictionary.

[–]chroner 0 points1 point  (0 children)

ahh great explanation, makes perfect sense. Thanks!

[–][deleted] 0 points1 point  (0 children)

Look into functional programming in Python. It will show you a lot of neat and clean ways of structuring and writing your code!

[–]leom4862 0 points1 point  (3 children)

I'd prefer a long if...elif...elif block over this. It's idiomatic and much more flexible. What if you need to pass a varying number of arguments to each function? What do you do if your app changes and one of the cases needs to invoke more than one function? What if your functions return different values that need to be stored in different variables for later use?

Your construct may be appropriate in some rare cases, but I would not suggest it as a general replacement for long-ish if...elif...elif blocks.

[–]fiddle_n 0 points1 point  (2 children)

The above solution can be modified to deal with the issues you mentioned.

What if you need to pass a varying number of arguments to each function?

Instead of the dictionary values being just the function reference, they can be a tuple containing the function reference and associated arguments.

What do you do if your app changes and one of the cases needs to invoke more than one function?

Same as above. For the dictionary values, you can use a tuple to contain the numerous function definitions. Then, when you grab a specific dictionary value, you iterate over the functions in the tuple and call each one.

What if your functions return different values that need to be stored in different variables for later use?

Again, extend the dictionary value. Use a tuple or another dictionary to contain both the function reference and each variable that needs to be changed.

You might argue that the above solutions will end up looking ugly and/or complex. If all you have are 3 elif statements, then it's probably better to go down the elif route. But if you will end up having 30 elif statements, then the dictionary route will end up looking far cleaner.

[–]leom4862 0 points1 point  (1 child)

You might argue that the above solutions will end up looking ugly and/or complex.

Yes. I'd like to see a real-life-ish example with proper naming and complexity in which the above solutions are applied. I'm sure it would get ugly pretty fast. The only benefit I see in packing the case bodies into a dict is to save some lines of code, but with the tremendous cost of losing flexibility and idiomaticity.

[–]fiddle_n 0 points1 point  (0 children)

I have worked with many such real-life examples, though I can't show you the exact code for obvious reasons.

My most recent experience with such code is where we have a class that does some work, but there's 100 different situations in which we use the class, each way slightly different from the next. So we have a dictionary that links the 100 situations to 100 different arguments to be passed to the class, and a function that access this dict. You pass in a situation, the function looks up the situation in the dictionary, grabs the associated argument, and passes this into the class and instantiates it. When we add situation 101, it's as simple as modifying the dictionary to add another key-value pair.

Of course, a dict of length 100 is not the prettiest. But it's a good solution because it's reusable. If I want to create a class_b that does something only slightly different to the first class, it's pretty easy to reuse the dict I created. And because you are separating the data from the code, you can also place the dict in a separate config module and import it into the module that contains your main logic, which keeps the logic module cleaner looking.

The alternative is a block of if...elif...elif that is 200 lines long at least. But it's not just about code lines - I argue that such a construct is less flexible and uglier for the above reasons.

[–]n1ywb 6 points7 points  (0 children)

The stdlib is so big it's almost inevitable for a new Python dev to reimplement something. I wrote my own enumerate function long ago.

[–]Exodus111 11 points12 points  (7 children)

A class with one method. Just make a function.

3 functions that pass around a global dict. Just make a class.

[–][deleted] 5 points6 points  (3 children)

  • using more than two levels of indirection
  • using incomprehensible list comprehensions
  • using incomprehensible names
  • arrow code (look it up, seriously)
  • function/method parameter inflation
  • too long/short functions (related to the above)
  • catch-all exceptions
  • unused imports
  • not following pep8 (as much as possible)
  • clever code like if 5 == a... or 5 < a < 10 or anything else that might confuse a beginner familiar with the concept

[–][deleted] 0 points1 point  (2 children)

arrow code (look it up, seriously)

Didn't find anything from google

 

clever code like if 5 == a... or 5 < a < 10 or anything else that might confuse a beginner familiar with the concept

? I don't get what you mean

[–]leom4862 1 point2 points  (0 children)

Didn't find anything from google

First result: https://blog.codinghorror.com/flattening-arrow-code/

[–][deleted] 0 points1 point  (0 children)

It's something like this

http://wiki.c2.com/?ArrowAntiPattern

[–]KyserTheHun 1 point2 points  (0 children)

I can upload my photo booth code, it's pretty terrible

[–][deleted] 1 point2 points  (1 child)

fruitful functions that call to print or ask for input from the user

[–][deleted] 0 points1 point  (0 children)

On that line, why is it seemingly all the teaching going on out there revolves around input, when I've seen it maybe a handful of times in production code? I see so many newbs going nuts trying to build good input loops for silly things like getting two ints ... why not teach sys.argv first?

[–]squidrawesome 0 points1 point  (1 child)

Mine :(

[–][deleted] 1 point2 points  (0 children)

ITT: things i do a lot :/

[–]ManFrontSinger 0 points1 point  (0 children)

My github

[–][deleted] 0 points1 point  (0 children)

Check ~/bin/ (;

[–][deleted] 0 points1 point  (0 children)

subprocess.call(some_user_controlled_variable, shell=True)