Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Refactor Your Code

00:00 I’ve got a chance to make my point about mutable lists and we have a working program that even fixes a little bug that was in there that you may or may not have encountered because maybe you’ll just always create one poem and you would’ve never run into it.

00:14 But in this lesson, you are going to look at one of the most important and somewhat final steps of when you’re writing a program, which is think about what you did and refactor to make it more coherent and simpler, more understandable and better readable.

00:33 So I was playing around with different ways of picking out these random words from a collection, but if you’re actually going to write this program, it would be probably best to just stick with one.

00:44 Exploring these different ways of doing it gave me a chance to try out a couple of ways and find one that works maybe the best and that I want to commit to.

00:52 And in this case, I would say that using random.sample() seems like the best approach. It’s straightforward, it’s very flexible. I can pick different amounts.

01:04 They’re always going to be unique and I just need to change the argument to k. So this seems really nice. I don’t need to shuffle, I don’t need to pop, I don’t need to remove anything.

01:13 And this actually also takes care of the issue with mutability of lists because random.sample() just picks out of the list. It doesn’t actually mutate it.

01:23 So in this step I want to go ahead and refactor all of my random word picking to use random.sample(). Let’s go ahead and do that right away. I want to do random.sample().

01:35 Also for adjectives, I need to pick out of the adjectives list, which sits at index two. And I want to get three random adjectives. I’m going to change k to three.

01:48 I’ll copy that again so I can reuse it. Then I can get rid of this shuffling. For example, up here, I can get rid of the whole for loop.

01:58 I’m picking out from words at index one and I want to get three verbs. You can see like I can refactor all of this code that I have here to one line each.

02:10 All the steps are similar.

02:14 I don’t even need all these code comments anymore at this point. I feel like I can completely get rid of them because the code is quite self-explanatory. I’m using the random module, I’m using the sample() function, and it tells me how many I’m picking out by just looking at the k parameter over there.

02:34 All right. I will stick with doing adverb random.choice() instead of random.sample() because I know I just need one. So that’s also like more descriptive here that I’m only going to pick one and I don’t need to deal with the nested list afterwards.

02:48 One more thing this allows me to do, because I’m not mutating the lists anymore. I can also get rid of needing to deep copy the words to pull. I can just delete that, don’t have to worry about it and get rid of an additional import that I’m not using anymore.

03:06 As you can see, like this made the code quite a bit shorter. So now the logic is down to one block that is picking the random words and then another block deciding which article to use.

03:18 And then finally, I’m just assembling the poem. So I have like these three steps. Let’s give the first one also a comment just for consistency here. Randomly pick the words to use

03:32 and I want to decide whether to use "A" or "An" as the article. And then I want to create the poem.

03:39 And by refactoring the part about picking the words to use, we cut down a lot of lines of code. We made everything work similarly except like one time we use choice() instead of sample(), but it makes it more straightforward to keep an overview of what you’re doing in here.

03:54 Less code to read is also easier to maintain, less imports. It’s going to make your script faster. No need to do that deep copy. It’s also going to make the script faster.

04:05 Let’s make sure that it still works by running the code

04:09 and creating all the ten poems. And you can see, you’re not running into an error here. One last thing I want to do is to make these poems a little easier to read.

04:22 I’m going to add a new line at the beginning and one at the end. That’s just going to be part of the poetic structure of this construct here. Let me run that again and you can see it’s a bit easier to read.

04:36 Now we have some spacing in between the different poems.

04:40 All right, this looks better. And this is, in a way, you could think of it as an unnecessary step because the poem generator was working before. We didn’t change anything about the output, but you change some things about the internals, which makes it easier to read faster and less complex.

04:59 All of these things are super important for writing code. I like to have this last step of looking at the code again, figuring out what did you learn in the process of writing it, and then apply the best thing that you’ve found.

05:13 There may be other ways of doing it that are even better, but in your process, you found out one way that works the best, and then you just want to apply that one consistently and clean up your code to have a nice script that you can also imagine maintaining into the future.

05:29 Thanks for joining me also in this refactoring trip at the end. In the next lesson, let’s talk about a couple of takeaways and then wrap up this course.

Avatar image for doink

doink on June 2, 2024

Thank you Martin for guidance.

This is my solution:

"""
{article} {adj1} {noun1}
{article} {adj1} {noun1} {verb1} {prep1} the {adj2} {noun2}
{adverb1}, the {noun1} {verb2}
the {noun2} {verb3} {prep2} the {adj3} {noun3}
"""

from random import randint
import re

#Defining the nouns, verbs, adjectives, prepositions and adverb to use

nouns = ["badger", "horse", "aardvark", "mouse", "gorilla", "elephant", "eagle", "sparrow"]
verbs = ["hugs", "bounces", "meows", "hauls", "whispers", "flutters", "gallops", "shimmers"]
adjectives = ["furry", "incredulous", "fragrant", "exuberant", "glistening", "melancholic", "serene"]
prepositions = ["against", "after", "into", "beneath", "upon", "for", "in", "like", "over", "within"]
adverbs = ["curiously", "extravagantly", "graciously", "reluctantly", "meticulously", "vigorously"]

#Selecting three nouns, three verbs, three adjectives, two prepositions, one adverb.
#I use list comprehension to generate a list, generate an index by using randint to get one word
#and use pop to avoid word repetition in the next iteration of the for loop.
#In the same line I unpacking the generated list.

noun1, noun2, noun3 = [nouns.pop(randint(0, len(nouns)-1)) for _ in range(3)]
verb1, verb2, verb3 = [verbs.pop(randint(0, len(verbs)-1)) for _ in range(3)]
adj1, adj2, adj3 = [adjectives.pop(randint(0, len(adjectives)-1)) for _ in range(3)]
prep1, prep2 = [prepositions.pop(randint(0, len(prepositions)-1)) for _ in range(2)]
adverb1 = adverbs.pop(randint(0, len(adverbs)-1))

#I use the regex module to determine if adj1 starts with a vowel, if true, {article} will be "An", "A" otherwise.

if re.match("^[aeiou]", adj1):
    article = 'An'
else:
    article = 'A'

#Print the poem according to the rules.

print(f"{article} {adj1} {noun1}\
      \n{article} {adj1} {noun1} {verb1} {prep1} the {adj2} {noun2}\
      \n{adverb1}, the {noun1} {verb2}\
      \nthe {noun2} {verb3} {prep2} the {adj3} {noun3}")

Become a Member to join the conversation.