total noob here confused all to hell about something in "Learn Python the Hard Way." Apologies if this has been covered; I searched and could only find posts about not getting the desired results from the code.
My question relates to the interaction of two functions in exercise 25:
def break_words(stuff):
words = stuff.split(' ')
return words
and
def sort_sentence(sentence):
words = break_words(sentence)
return sort_words(words)
So, near the end of the exercise Zed has you run this in the terminal:
>>> sorted_words = ex25.sort_sentence(sentence)
>>> sorted_words
['All', 'come', ’good’, ’things’, ’those’, ’to’, ’wait.’, ’who’]
Now I assume the argument in 'sort_sentence' comes from the following, entered in the terminal at the start of the exercise:
>>> sentence = "All good things come to those who wait."
But although we now know the above is the argument for 'sort_sentence,' 'sort_sentence' can't complete without running 'break_words', with 'sentence' again as its argument. Here's where I get confused: The argument for 'break_words' is labeled 'stuff.' Does this matter? Can 'sentence' just be passed into 'break_words' from 'sorted_words' no matter what the argument for 'break_words' is labeled?
So assuming what I assumed - that the argument label doesn't matter - 'break_words' ought to run with 'sentence' as its argument and return 'words', which is the output of the function 'stuff.split' contained therein. This is where I get really confused - what does the 'words' returned from 'break_words' have to do with the variable 'words' defined as a part of 'sort_sentence'? I simply can't figure out how these functions work together. Thank you in advance for your help!
How Python functions more or less work is the following:
def function_name(parameter_name_used_locally_within_function_name):
#do stuff with parameter_name_used_locally_within_function_name
some_new_value = parameter_name_used_locally_within_function_name
return some_new_value
Notice how the parameter is only with in the scope of the function function_name. As that variable will only be used in that function and not outside of it. When we return a variable from a function, we can assign it to another variable calling the function:
my_variable = function_name("hello")
my_variable now has "hello" as it's value since we called the function, passing in the value "hello". Notice I didn't call the function with a specify variable name? We don't care what the parameter name is, all we know is it takes one input for the function. That parameter name is only used in the function. Notice how we receive the value of some_new_value with out knowing the name of that variable when we called the function?
Let me give you a more broad example of what's going on. Functions can be thought of a task you give someone to do. Lets say the function or task is to as them to cook something for us. The chef or task needs ingredients to cook with (that's our input), and we wish to get food back (our output return). Lets say I want an omelette, I know I have to give the chef eggs to make me one, I don't care how he makes it or what he does to it as long as I get my output/omelette back. He can call the eggs what he wants, he can break the eggs how he wants he can fry it in the pan how he likes, but as long as I get my omelette, I'm happy.
Back to our programming world, the function would be something like:
def cook_me_something(ingredients):
#I don't know how the chef makes things for us nor do I care
if ingredients == "eggs":
food = "omelette"
elif ingredients == "water":
food = "boiled water"
return food
We call it like this:
my_food_to_eat = cook_me_something("eggs")
Notice I gave him "eggs" and I got some "omelette" back. I didn't say the eggs are the ingredients nor did I know what he called the food that he gave me. He just return food that contain omelettes
Now let's talk about chaining functions together.
So we got the basic down about me giving something to the chef and he giving me food back based on what I gave him. So what if we gave him something that he needs to process before cooking it with. Let's say what if he doesn't know how to grind coffee beans. But his co-chef-worker knows how too. He would pass the beans to that person to grind the coffee beans down and then cook with the return process.
def cook_me_something(ingredients):
#I don't know how the chef makes things for us nor do I care
if ingredients == "eggs":
food = "omelette"
elif ingredients == "water":
food = "boiled water"
elif ingredients == "coffee beans"
co_worker_finished_product = help_me_co_worker(ingredients)
#makes coffee with the co_worker_finished_product which would be coffee grindings
food = "coffee"
return food
#we have to define that function of the co worker helping:
help_me_co_worker(chef_passed_ingredients):
if chef_passed_ingredients == "coffee beans"
ingredients = "coffee grinding"
return ingredients
Noticed how the co worker has a local variable ingredients? it's different from what the chef has, since the chef has his own ingredients and the co worker has his own. Notice how the chef didn't care what the co worker called his ingredients or how he handle the items. Chef gave something to the co worker and expected the finished product.
That's more or less how it's work. As long as functions get's their input, they will do work and maybe give an output. We don't care what they call their variables inside their functions cause it's their own items.
So let's go back to your example:
def break_words(stuff):
words = stuff.split(' ')
return words
def sort_sentence(sentence):
words = break_words(sentence)
return sort_words(words)
>>> sentence = "All good things come to those who wait."
>>> sorted_words = ex25.sort_sentence(sentence)
>>> sorted_words
['All', 'come', ’good’, ’things’, ’those’, ’to’, ’wait.’, ’who’]
Let's see if we can break it down for you to understand.
You called sorted_words = ex25.sort_sentence(sentence) and set sorted_words to the output of the function sort_sentence() which is ['All', 'come', ’good’, ’things’, ’those’, ’to’, ’wait.’, ’who’]. You passed in the input sentence
sort_sentence(sentence) get's executed. You passed in the string is now called sentence inside the variable. Note that you could have called the function like this and it will still work:
sorted_words = ex25.sort_sentence("All good things come to those who wait.")
And the function sort_sentence() will still call that string sentence. The function basically said what ever my input is, I'm calling it sentence. You can pass me your object named sentence, which I'm going to rename it to sentence while I'm working with it.
Next on the stack is:
words = break_words(sentence)
which is now calling the function break_words with that the function sort_sentence called it's input as sentence. So if you follow the trace it's basically doing:
words = break_words("All good things come to those who wait.")
Next on the stack is:
words = stuff.split(' ')
return words
Note that the function call it's input as stuff. So it took the sort_sentence's input that sort_sentence called sentence and function break_words is now calling it stuff.
It splits the "sentence" up into words and stores it in a list and returns the list "words"
Notice how the function sort_sentence is storing the output of break_words in the variable words. Notice how the function break_words is returning a variable named words? They are the same in this case but it doesn't matter if one called it differently. sort_sentence can store the output as foo and it still work. We are talking about different scope of variables. Outside of the function break_words the variable words can be anything, and break_words would not care. But inside break_words that variable is the output of the function.
Under my house my rules? Outside of my house you can do what ever you want type of thing.
Same deal with sort_sentence return variable, and how we store what we got back from it. It doesn't matter how we store it or what we call it.
If you wanted you can rename it as:
def break_words(stuff):
break_words_words = stuff.split(' ')
return break_words_words
def sort_sentence(sentence):
words = break_words(sentence)
return sort_words(words) #not sure where this function sort_words is coming from.
#return words would work normally.
>>> sentence = "All good things come to those who wait."
>>> sorted_words = ex25.sort_sentence(sentence)
>>> sorted_words
['All', 'come', ’good’, ’things’, ’those’, ’to’, ’wait.’, ’who’]
You just have to think of local variables, and parameters as like just naming things to work with. Like our example with the chef, Chef might called the eggs, ingredients, but I called it what ever I wanted and just passed it "eggs". It's all about the scope of things, think of functions as a house, while you are in the house, you can name what ever objects you want in the house, and outside of the house those same names could be different things but inside the house, they are what you want them to be. And when you throw something out, you naming that item has nothing to do with the outside world, since the outside world will name it something else. Might name it the same thing tho...
If I just rambled too much, ask questions I will try to clear it up for you.
Edited
Coming back from lunch I thought of variable as containers, They hold the values but you don't care what other people's containers are named. You only care about yours and when someone gives you something you put it in a container and name it something you care about that will help you know what inside it. When you give away an item, you don't give the container, cause you need it to store other things..
that the argument label doesn't matter
It matters in the sense that it's used "locally" within the function definition. Basically think of it as another local variable you define in the function definition but the values of the arguments are given to the function.
Keeping this in mind, your next question is easy to answer:
what does the 'words' returned from 'break_words' have to do with the
variable 'words' defined as a part of 'sort_sentence'?
Nothing. As stated previously, words is a local variable of sort_sentence and so is basically trashed when you leave the function ("falls out of scope" is the lingo). Of course, you can use words as the name of variables elsewhere, such as in another function definition, and that's what's happening here.
Related
I'm starting to learn Python and I find it really interesting. I am trying to create my own module and I ran into a bump. The code goes like this:
def break_words(sentence):
words = sentence.split(' ')
return words
def sort_words (words):
sort_word=sorted(words)
return sort_word
The second function has argument words fed in by the first, and I think it should work since it has been returned, but on running filename.sort_words(words) in Python, it gives an error message of NameError:global name 'words' is not defined. And it's requiring me to define words like words=filename.break_words(sentence) before it runs the second function.
What's wrong with my code?
You should try to explain yourself better in future, it's very confusing to read and probably the reason nobody replied.
This is what I think you want to know:
import filename
words = filename.break_words('some sentence goes here')
print filename.sort_words(words)
Have you tried that?
edit:
Variables in Python are always defined in scopes, so defining one variable in a function means that it is not defined anywhere outside the function.
'return' simply returns the value of that variable to the caller.
I'm super new to this and I'm trying to puzzle my way through is code and I'm stuck, I don't know how the program is referencing the lists I've copied/created. At the end it makes a new list called 'words'. I don't understand how 'words' is getting my previous lists inside of it.
'''
Making silly Sentences Game
'''
name = ['Bob', 'Rachel', 'Don']
verb = ['slaps', 'steals', 'jumps over']
noun = ['jello', 'car', 'U-571']
from random import randint
def pick (words):
num_words = len(words)
num_picked = randint(0, num_words -1)
word_picked = words[num_picked] **#THIS BIT HERE!!! How does it know what 'words' is?**
return word_picked
print (pick(name),pick(verb), 'a', pick(noun))
This is my first post so, I'm almost certain it's in the wrong place. Please be gentle.
This has to do with scope.
The line word_picked = words[num_picked] can "see" words because it is in the scope of the function pick(), which takes a single arguments words. So when you call pick(name), within the scope of pick(), words is now pointing to name.
It knows what words is because you told it.
When you did def pick(words) you defined a function which takes one argument, words. This means that whatever you pass as that argument will be available as words inside the function.
Now, when you called pick(name), you passed in the value name as the argument. So the value that was known as name is passed into the function, which receives it as words.
I am very new to programming in Python and I just had a question as to why when I call a function it doesn't work. I see the TypeError about die_roll needing two arguments but why isn't that covered by self.result when added to the parenthesis?
import random
def die_roll(self, result):
self.result = random.randint(1, 10)
print "Roll the dice, Dennis. "
print "You have rolled a %s!" % self.result
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
print (" Welcome... ")
print (" TO THE WORST GAME IN THE WORLD!!!!!!!!!!! ")
print (" REALLY, IT IS QUITE BAD. YOU'LL SEE...... ")
print ("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n")
name = raw_input('Welcome to this awful adventure. Please enter your name to get started: \n')
print "\n%s? I don't like that name. \n" % (name)
name1 = raw_input('Try again: \n')
print "\n%s?! Really? That's the best you can do? You know what - just forget it. You will be called Dennis. \n" % (name1)
print "I happen to like Dennis. It's a good name. Regal. It's nice to meet you.... Dennis. \n"
print "You begin your adventure peering into a long, gloomy cave. You move by rolling a 10-sided dice.\n"
print "You will encounter random enemies along the way. If your combined rolls equal 100, you win!\n"
die_roll()
You are defining your function as
def die_roll(self, result):
This tells python interpreter that die_roll , needs two arguments self and result.
I am guessing you copied this method from within some other class, because self is the normal naming convention for the first parameter to a method in a class, in the later case, self (first parameter) refers to 'this' (from c++ or java) .
From the function body, it seems like you do not need any parameters, maybe you can try -
def die_roll():
result = random.randint(1, 10)
print "Roll the dice, Dennis. "
print "You have rolled a %s!" % result
Hmm. I'm not sure where your main misunderstanding is, but there are several in your question.
You're not following the flow of the program and where the error comes from:
def die_roll(self, result):
/stuff here/
/stuff/
print "You will encounter random enemies along the way. If your combined rolls equal 100, you win!\n"
die_roll() <--- here is where the TypeError about die_roll needing two arguments is triggered
why isn't that covered by self.result when added to the parenthesis?, you ask? Because the error is saying that the parentheses when you call die_roll() aren't following the pattern you set when you made def die_roll(...). You can't avoid that error by doing something at the place where the function is defined. They always need to match in both places - all places. If def die_roll says it needs two parameters, then when you call it you need to give it two parameters.
Another misunderstanding is that you are using def die_roll(self, result) and then self.result - as if the comma and the dot operators are somehow related, or that you need to use these arguments as a way to get or return a result. (They aren't, you don't).
Another is that you are using the words self and result as if Python understands them. They aren't keywords, they have no special meaning in Python.
self has no special meaning in Python, however, it is the standard name people give for one particular variable which is ... unfortunately related to object orientation, something else that can be quite a slippery concept to pickup from scratch.
Your title question Why don't functions need a self argument? can be answered in many ways, all basically unhelpful to you right now. blah blah Classes define objects, they contain things which look exactly like functions but are called methods. Methods need a way to reference the object they are 'in', so the first argument to a method is always the object it is in, and the Python engine supplies the first argument so method calls always look like they don't match up because the definition has one more argument than the call. self is a convention that Python programmers have adopted for naming the variable that receives the object reference, although it's not a special name inherently. But that's all unrelated background, setting up...
Functions don't need self because they aren't 'in' objects, so they have no need for a way to reference the object they are 'in', because they aren't in one.
Yeah that's not very helpful, sorry. The most helpful thing I can say is, write more code, use the interactive interpreter more, explore more, and things will become much clearer.
From Learn Python the Hard Way:
Python sees you mentioned mystuff and looks up that variable. It might have to look backwards to see if you created with =, look and see if it is a function argument, or maybe it's a global variable. Either way it has to find the mystuff first.
Once it finds mystuff it then hits the . (period) operator and starts
to look at variables that are a part of mystuff. Since mystuff is a
list, it knows that mystuff has a bunch of functions.
It then hits append and compares the name "append" to all the ones
that mystuff says it owns. If append is in there (it is) then it grabs
that to use. Next Python sees the ( (parenthesis) and realizes, "Oh
hey, this should be a function." At this point it calls (aka runs,
executes) the function just like normally, but instead it calls the
function with an extra argument.
That extra argument is ... mystuff! I know, weird right? But that's
how Python works so it's best to just remember it and assume that's
alright. What happens then, at the end of all this is a function call
that looks like: append(mystuff, 'hello') instead of what you read
which is mystuff.append('hello').
Where does he get "mystuff" from? And I'm still unsure about how that period operator thing works (sorry I'm new at this please bear with me), later on we get this:
ten_things = "Apples Oranges Crows Telephone Light Sugar"
print "Wait there's not 10 things in that list, let's fix that."
stuff = ten_things.split(' ')
I don't see how that string becomes a list after the last line, does the .split automatically turn it into one or what? What is the name of that period "split" or "append" thing he's doing? One of the main things screwing me up in programming is that I don't know what a lot of things are actually called. I know functions, variables, etc but some stuff like that .split just confuse me.
Help?
stuff = ten_things.split(' ') doesn't change the value of ten_things. Instead, it creates a new variable named stuff and saves the list created by ten_things.split(' ') to it. The space passed as an argument to the split method here is significant. What it is saying is that Python should take the string ten_things and split it up, using splits argument as a delimiter.
Example:
"This is a string".split(' ') == ["This", "is", "a", "string"]
or
"This|is|a|string".split('|') == ["This", "is", "a", "string"]
Regarding “Where does he get "mystuff" from?”, mystuff is an object of some kind, and there are methods or functions among the object's attribute values (or among the attribute values of its class). The dot (period) is a qualifier operator; for example, mystuff.append qualifies or identifies the relevant append function to be the one associated with object mystuff. Object methods typically have an implicit argument (often called self) as the first argument, and that argument is made equal to the object the method belongs to. In this case, that's mystuff.
As mentioned in a previous answer, split splits a string and returns a list. For more information, also see tutorialspoint regarding split:
The method split() returns a list of all the words in the string, using str as the separator (splits on all whitespace if left unspecified), optionally limiting the number of splits to num. ... Following is the syntax for split() method: str.split(str="", num=string.count(str)).
I need help with parameteres. Do both of these function definitions do the exact same thing for print_twice?
def print_twice(lol):
print lol
print lol
def print_twice(michael):
print michael
print michael
If yes, then I'm guessing the word used for the parameter doesn't matter, correct?
The word we use for the parameter does matter. It is important that the word you use:
is meaningful and clearly explains what the argument is for,
does not override some variable name from the external scope.
Importance of meaningful arguments' names
The name you use for argument is important, because the names of the arguments, their default values and the function name are the things developers using your function first see, even without the need to look into function documentation (eg. by using help(your_function)). Just use IDLE to define your function and then try to use it - when writing it, the IDLE will show you possible arguments.
So please, give them meaningful names that will make using your function easier and will not require looking into the documentation.
Overriding variables from outer scopes
When it comes to the second point, just look at this example:
def show_elements(elements):
"""Shows elements of the passed argument
"""
for element in elements:
print element
which works ok, but if you replace elements with eg. list, you will override list within this specific scope:
def show_elements(list):
"""Shows elements of the passed argument
"""
for element in list:
print element
and then if you would like to use list eg. for building a list, or converting from other type into list, then you will have problems. list is a builtin and you should not override it. Similar is true also about the other variables from the scopes surrounding the function.
Historically, when Python was resolving variable names by first looking into local scope, then global and builtin scopes, skipping all nonlocal ones (eg. scope from the function in which our function was defined), enclosing scope's variables were passed that way:
def funca():
local_val1 = 'some value1'
local_val2 = 'some value2'
def funcb(local_val1=local_val1):
# local_val1 is accessible here, even though local_val2 is not
...
...
But since the above is no longer true, you will need to take surrounding scopes into account, thus using non-conflicting name is important.
Yes they do. The name of a parameter is irrelevant, although good programming practices mandate that the name should be clear and self-explanatory
That's correct, the name of the parameter doesn't matter.
yes that is correct its just a variable name ...
That is correct. The word used for the parameter in the function definition is only a name, and does not refer to anything external.
Programming is supposed to be logical. So, let's think logically. If you write "a" on a paper twice, you get "a" two times. Same with "b." So you're doing the same function with letters. But what if you reassigned a value to a, each time a went through the function. I mean, what if a was a number, then IMO the closest you could get is something like this:
def func1(a, b):
a = input("Enter a number: ")
b = input("Enter another number: ")
b *= b
a *= a
print func1(a)
print func1(a)
print func1(b)
print func1(b)
Now, when I try to compile this specific code online, I get an error but I think something like this will work for the sake of trying to do what you're doing if done correctly? It's a good experiment, and I would imagine some usage in it.