Things Not To Do7:31 with Kenneth Love
No set of rules is complete without a list of anti-patterns and gotchas.
nonlocal let you work with variables from a higher scope. You should have a really good reason before using either of these!
We covered a lot of rules in the last video. 0:00 Things like keeping functions limited and not causing side effects. 0:02 But how do we actually do those things? 0:06 Let's go to WorkSpaces and look at some things not to do. 0:08 So to illustrate some of the things that are bad ideas, 0:11 things we shouldn't really do when we use Python, I've got a file here called 0:15 bad examples.py, and we're gonna walk through what each of these things are. 0:20 So up at the top, we have this list that's a very important list. 0:25 It needs to stay exactly that way it is. 0:30 Maybe these are the order that players signed up, or any number of things. 0:32 So it needs to stay in the order of five, two, three, one whenever I use it, 0:38 in different places, but you may want to do stuff with it. 0:43 And then we have a variable called name that's just my name. 0:46 So we have this function here called def mutate, and 0:50 it takes very important lists and it sorts it. 0:53 So let's do, right here, let's print 0:56 very_important_list, and then let's call mutate. 1:00 And then let's again print very_important_list. 1:07 All right, so then we can run this with bad_example.py. 1:12 And you can see that, since inside this function, 1:17 we called sort on the list, it sorted the list even out here. 1:22 So ideally, we'd get the same thing here and here. 1:28 Both of those print calls would give us 5, 2, 3, 1, but instead, 1:33 since we called mutate, we sorted the list in memory, it's sorted for good 1:37 now as far as the program is concerned, and we get two different outputs. 1:43 So, you don't want to call methods on mutable types 1:47 unless you know exactly what you're doing and why, because you get this. 1:52 It changes that list outside of the scope. 1:55 All right, so that's a bad one. 1:58 We won't do that anymore. 2:01 On our next function here we're using global. 2:03 And so what global does, there is another keyword similar to global called nonlocal 2:06 that I'll put in the teacher's notes and recommend that you look up. 2:11 What global does though is it says, hey, go out to the global scope, 2:14 go as far out as you need to go and see if you can find a variable with this name. 2:18 And if you do, give it to me, I'm gonna use it. 2:23 So, normally, let's ignore this line. 2:27 Let's comment out that line. 2:30 Okay, so, if we're just looking at this function, all we're doing in here is we're 2:32 setting a name, and we're setting it to the string James, okay? 2:36 But, when we use global and we use name it 2:41 comes out to this global scope and says oh hey there's a variable here called name. 2:45 Let's reference that one and then here we've set it to James. 2:49 So again let's do a similar kind of experiment we're gonna print name and 2:52 then we're gonna call global.use. 2:57 And then we're gonna print name again. 3:00 Now ideally we would get Kenneth both times 3:02 but We get Kenneth and then we get James. 3:05 And the reason is because we've overridden that global name variable. 3:09 We've got back up to this top scope and 3:14 said hey, we're gonna change that variable up there. 3:16 So don't do that. 3:19 That's not good or predictable. 3:21 There are occasionally times when you're gonna wanna use global. 3:23 But those are very few and very far between. 3:27 So now these next two we don't really need to run them. 3:30 We're just gonna talk about these. 3:33 I mentioned that we want to avoid functions that are too long, so 3:34 let's look at this. 3:37 We have this long_func here, it imports random, it gets some random 3:38 numbers between 5 and 250, or rather shuffles the range 5 to 250 randomly. 3:43 And then we run through, what do we have? 3:49 We have an index and a num coming out of enumerate of all those numbers. 3:51 If the number is divisible by three, or isn't evenly divisible by three. 3:55 So, if this comes back as a truthy value, then we set the number to the fifth power. 4:02 If it's not evenly divisible by seven, then we set the number to the tenth power, 4:09 otherwise I always set the number squared. 4:16 And then we total all those up, and then we print out the total and 4:19 then we're returning the list of shuffled and now randomly mutated numbers. 4:22 I wrote this function and I just had to stop and read it for 4:29 a second to tell you what was happening in it. 4:33 So we don't want functions like this, where there's just so much stuff going on, 4:35 and you have to constantly think about what's happening. 4:39 And now you may be saying but Kenneth I can put in comments, 4:42 I can put in a doc string and I can explain what's going on. 4:45 And then everybody will know and yeah that's true you can but 4:48 if you have to explain what's happening in a function, what, not why, 4:53 explaining the reason why the function was written is a great thing to do. 4:57 But if you have to explain what the function does 5:01 then you've probably written that function wrong, you should probably simplify this. 5:05 This would be really good if we were to say like, 5:08 maybe the function takes in the range of numbers, the list, right? 5:12 Maybe it takes in that list and then works on them. 5:16 Maybe it just returns that shuffled list or 5:19 it returns, instead of returning the shuffled list because then you 5:23 are repeating what the Python already does, maybe it returns the mutated list. 5:25 This part. 5:30 And it doesn't print or total or anything like that. 5:32 Because why do we need to total it? 5:34 The total seems completely useless. 5:35 So, things to think about when you're designing functions, 5:38 when you're designing your software. 5:41 And then for the last one, lot_of_inputs. 5:43 We mentioned having functions that take too many inputs, 5:47 they take a whole bunch of stuff. 5:50 Now in this case, 5:51 if you look through you'll see that I've taken inputs that I'm not using. 5:53 It's kind of an idea of like, well, we might need that some day so let's do it. 5:56 That's generally a bad idea because it means you're usually putting way more 6:00 thought into the software than actually needs to be there. 6:03 And that might sound like a silly thing, but 6:08 it means that you're spending all this time on details that don't actually 6:11 matter, instead of writing the code that you need. 6:14 So try not to do that. 6:17 Try to do things in a smart and 6:20 simple way to where you know exactly what the code's gonna do. 6:22 So in this one we've got seven inputs coming in, 6:26 only four of them actually get used. 6:29 And we return this and again this is when I would say it's too long, 6:31 it's too complicated of a function too. 6:35 Cuz inside here we make these two named tuples which act kind of like classes 6:37 and then we return objects that are of those classes and 6:42 it's a lot of work for one function. 6:47 So we're gonna avoid all of these design mistakes, 6:50 all of these usage mistakes when we write our code. 6:53 Mutable types, like lists and 6:56 dictionaries, are things that we can deal with. 6:58 Python gives us some handy tools like slices and some functions that we'll cover 7:00 later in this course, that make it pretty easy to leave those things alone. 7:04 Global is also pretty simple to avoid. 7:08 Just don't use it. 7:11 The last two things, writing long functions, or 7:12 writing functions with inflated scopes are things you get better at not doing 7:14 the more you pay attention to your code. 7:18 You'll find, as you get more experience and practice, 7:20 that it's second nature to keep things tight. 7:23 In our next video, we'll get to the tools that we're actually going to 7:25 use in the course, and the data that we'll use those tools on. 7:28
You need to sign up for Treehouse in order to download course files.Sign up