I'm up to Exercise 41 in Learn Python the Hard Way, and I'm having a really hard time wrapping my brain around the fact that the entire thing hinges on a function running just because it's been assigned as a value to a variable. I wrote up a little script to confirm that this is how it works, and it does:
def pants():
print "Put on some pants!"
def shorts():
print "And don't forget your underwear!"
zap = pants()
thing = shorts()
With the results being:
Put on some pants!
And don't forget your underwear!
So obviously this happens, but I can't understand why the language works that way -- what the logic is behind the language that makes this a valuable way of operating. I think it'd be helpful for me moving forward to understand why this is, rather than just "that's the way it works."
For clarity: I'm asking (I guess) why the function is running, when all I'm doing is assigning it as a value for something. The print statements are just there so I can see that the function is indeed running.
It's the fact that I'm not ever actually running
pants()
shorts()
that is confusing me.
To create a tortured analogy, if me-baking-cookies-at-home were "cookies()", and I were to make cookies on Saturdays, I might eventually believe that
Saturday = cookies()
but just thinking "hey, Saturday is cookie day" is not the same as actually baking cookies... so why does just saying
Saturday = cookies()
actually bake the cookies, rather than just setting up Saturday with the variable "cookies()" for some later use?
When you use the parentheses () the function gets called. If you want to assign the function to the variable to reuse it you should remove there parentheses.
Example:
def pants():
print "Put on some pants!"
def shorts():
print "And don't forget your underwear!"
zap = pants
thing = shorts
And then when you want to call those functions:
zap()
thing()
So obviously this happens, but I can't understand why the language works that way -- what the logic is behind the language that makes this a valuable way of operating. I think it'd be helpful for me moving forward to understand why this is, rather than just "that's the way it works."
The language needs some way to distinguish between the function and the act of calling the function. That is what the parentheses provide.
f = foo
Now f is bound to the function itself. The function foo could be executed by f().
f = foo()
This calls the function foo and binds the return value to f.
Note that whether or not you bind the return value to a name is irrelevant. Simply writing
foo()
will also execute the function but the return value will simply be ignored.
Although it may seem like your functions don't return anything, they do in fact. Quoting the Python.org documentation:
The return statement returns with a value from a function. return without an expression argument returns None. Falling off the end of a function also returns None.
So your functions really look like this:
def pants():
print "Put on some pants!"
return None
def shorts():
print "And don't forget your underwear!"
return None
Your assignments assign to zap whatever pants returns (i.e. the value of pants()), and to thing whatever shorts returns. In your case, both are None, but of course the functions must be run in order to figure this out(*). Afterall, it could be that pants returns 42 during leap years, and that shorts returns 'Foobar' whenever some random number generator "rolls" a 6.
(*) Digression: That the functions "must be run" should not be considered universally true. In a pure setting, and leaving aside the specifics of Python (of which I know very little), a compiler might realize that both functions are identically None, and cause no calls to be made when the program is run. But a function that prints something (or inspects whether the current year is a leap year, or rolls a die) won't be pure.
zap = pants() will bind the return value of the function to the variable, so of course the function is run if you bind it to a variable.
def foo():
return 1
var = foo()
print var
will print 1.
I hope this helps.
Edit: If you expect the value of the variable to be "put on some pants", you are indeed confusing print and return, as people pointed out in the comments.
When the interpreter sees a function name followed by () it knows that it's supposed to execute that function.
What you're doing there is saying "assign the result of these functions to these variables".
But since you are not returning any values from those functions, you're not seeing anything in the variables.
However because you have a print statement in there, you are seeing the interpreter execute those functions as it attempts to assign the variable to results of that function.
Your functions are called because of the parenthesis after the name:
zap = pants()
This calls the function pants and puts the result in zap. If you had done this instead:
zap = pants
then zap would now refer to the pants function itself.
And if you just wrote
pants()
then the pants function would also get called, but the result (which is None) would never have been put in a variable.
From your question what I think you want zap will have the value "Put on some pants!" and thing will have the value "And don't forget your underwear!". If that is your problem let's discuss it. Otherwise you do not need to read further as I just discussed about all that.
Let's make it some fun. When you define a function, you are like creating a machine that does what you want it to do. Now let's think of a machine that when you give some food in it, it chops them and ... does nothing! I mean I made that machine to chop foods and nothing else! You won't get your chopped food back, but indeed it chopped your food as you made it for.
Now, as you want your chopped food back, you create another machine that takes your food, chops them and return them to you. Fruitful machine, isn't it? ;-)
They are all true for functions in programming or math (though I don't know any void function in math! :P). When you are creating the function, you have to tell it whether it just does some work or it does some work and return the result. The way to tell a function is the return statement. In your functions, you have just told to do something. And that is print "......" so does the functions. You call the with () at end and the does their work, they prints it. But as I said if you don't tell it to return a result, it won't. And because it is not returning any result, nothing will be assigned with the variable (don't confuse him with None). When you wrote those lines (if in interpreter) or run the script, you will see those lines printed but your zap and thing has no values.
So how to fix it? Tell them to return the lines to the variables. To tell the functions do that, replace the print statements with return statements. And never mind to experiment what you know, to know about what you know about your knowledge is true :-)
Hope it helps :-)
Related
def enumerator(fruits):
for index, fruit in enumerate(fruits):
print(f"Fruit: {fruit}, under the index: {index}.")
just_a_variable = enumerator(["apple", "banana", "lemon"]) # Im just assigning function call
# to the variable "just_a_variable"
# and boom, when I run the program the function is called. Makes no sense (it shouldn't work this way, does it?)
I assume this is happening because there is a print statement in the function but it still doesn't make sense. if I change the print statement to "return" it suddenly doesn't compile, that is what I was expecting from just using print. I'm I missing something here?
In general if you add parenthesis after a function (like one of the two examples below), it is called.
function_name(arguments)
variable = function_name(arguments)
If you just want a variable to point to a function:
variable = function
Then the following two statements will become identical:
variable(arguments)
function(arguments)
Having said so, this seems a bit useless to me. With you function defined the way it currently is, there isn't a way I know to "assign" it to a variable and pass arguments at the same time.
This does change the structure of your code, but you can perhaps use yield instead of return.
The line just_a_variable = enumerator(["apple", "banana", "lemon"]) is calling function enumerator. Technically, that is what the parenthesis after enumerator do.
Perhaps you noticed that simply running the file is running that line (and calling enumerator). As a scripting language, this is how Python works (in contrast to Java or other compiled languages).
I fell in doubt why below two code work correctly and what is the difference with or without paranthesis?
And I see some answered question about first part.
Firts part
def hello():
pass
hello# first
hello()#second
Then I compile following two examples,again it works but I get different result for second part.
Second part
df["method"].value_counts()#first
df["method"].value_counts# second
My Questions
1-)Why are the results different?
2-)After df["method] ".value_counts" Are the expressions with parentheses and expressions without parentheses different things? Like method or function.
hello is a function itself. Actually, it is a pointer to bytes (wow!) representing underlying algorithm, an essence of your function. So you don't invoke function in such a way, you reference it. For example, myFunc = hello is perfectly valid Python code and you can pass both hello directly and myFunc as arguments to other functions. Same applies to lambdas, x = lambda (): print('hi') is also valid code.
() after some function make it run, i.e. you invoke it, enforce encoded algorithm to return some result. If you don't use () to invoke your functions, nothing will ever happen, they won't run, they wont use your CPU to compute something, your program will be dead no matter how good it's code is.
Well, functions are also variables, think of them as executable variables.
def hello():
pass
hello # first
hello() # second
So basically the first version is reading the variable, and the second version is executing the variable.
When Python reads those lines it sees hello and it's like "Oh yeah, I know hello, it's a function" but that's all it's going to do.
Then it reads hello() and it's like "Oh you want me to execute it? Sure, here it goes".
If you change hello's definition to this one you'll see the difference more clearly.
def hello():
print("I am executing a function")
pass
The first version is going to say "Oh yeah, I know hello, that's a function".
The second version is going to print "I am executing a function" because of the parens.
hello is a referece to a value of type function. hello() is Python syntax for invoking a value's __call__ method, equivalent here to hello.__call__(). The parentheses are a request to actually call the function bound to the name hello.
Lets say I have the function:
def function(a)
c = a+b
print(c)
Is it advisable to use the print statement in the function to display output rather than placing a return statement at the end and using the print(function(a))?
Also what implications would there be if I used both a print statement and a return statement in a function to display the same output? Lets imagine I need to show the answer for c and then use the value of c somewhere else. Does this break any coding conventions?
So the highlight of the question isn't the difference between print and return, but rather if it is considered a good style to use both in the same function and if it has a possible impact on a program. For example in:
def function(a)
c = a+b
print(c)
return c
value = function
print(value)
Would the result be two c's? Assume c = 5; therefore, would the output be(?):
5
5
print and return solve two completely different problems. They appear to do the same thing when running trivial examples interactively, but they are completely different.
If you indeed just want to print a result, use print. If you need the result for further calculation, use return. It's relatively rare to use both, except during a debugging phase where the print statements help see what's going on if you don't use a debugger.
As a rule of thumb I think it's good to avoid adding print statement in functions, unless the explicit purpose of the function is to print something out.
In all other cases, a function should return a value. The function (or person) that calls the function can then decide to print it, write it to a file, pass it to another function, etc.
So the highlight of the question isnt the difference between print and
return but rather if it is considered good style to use both in the
same function and its possible impact on a program.
It's not good style, it's not bad style. There is no significant impact on the program other than the fact you end up printing a lot of stuff that may not need to be printed.
If you need the function to both print and return a value, it's perfectly acceptable. In general, this sort of thing is rarely done in programming. It goes back to the concept of what the function is designed to do. If it's designed to print, there's usually no point in returning a value, and if it's designed to return a value, there's usually no point in printing since the caller can print it if it wants.
Well return and print are entirely two different processes.
Whereas print will display information to the user or through the console; and return is used for collecting data from a method that fulfills a certain purpose (to use later on throughout your program).
And to answer your question, I believe it would return the two values; since one prints the c variable itself, and the other returns the value c to present as well? Correct me if I'm wrong.
I want to write a Python generator function that never actually yields anything. Basically it's a "do-nothing" drop-in that can be used by other code which expects to call a generator (but doesn't always need results from it). So far I have this:
def empty_generator():
# ... do some stuff, but don't yield anything
if False:
yield
Now, this works OK, but I'm wondering if there's a more expressive way to say the same thing, that is, declare a function to be a generator even if it never yields any value. The trick I've employed above is to show Python a yield statement inside my function, even though it is unreachable.
Another way is
def empty_generator():
return
yield
Not really "more expressive", but shorter. :)
Note that iter([]) or simply [] will do as well.
An even shorter solution:
def empty_generator():
yield from []
For maximum readability and maintainability, I would prioritize a construct which goes at the top of the function. So either
your original if False: yield construct, but hoisted to the very first line, or
a separate decorator which adds generator behavior to a non-generator callable.
(That's assuming you didn't just need a callable which did something and then returned an empty iterable/iterator. If so then you could just use a regular function and return ()/return iter(()) at the end.)
Imagine the reader of your code sees:
def name_fitting_what_the_function_does():
# We need this function to be an empty generator:
if False: yield
# that crucial stuff that this function exists to do
Having this at the top immediately cues in every reader of this function to this detail, which affects the whole function - affects the expectations and interpretations of this function's behavior and usage.
How long is your function body? More than a couple lines? Then as a reader, I will feel righteous fury and condemnation towards the author if I don't get a cue that this function is a generator until the very end, because I will probably have spent significant mental cost weaving a model in my head based on the assumption that this is a regular function - the first yield in a generator should ideally be immediately visible, when you don't even know to look for it.
Also, in a function longer than a few lines, a construct at the very beginning of the function is more trustworthy - I can trust that anyone who has looked at a function has probably seen its first line every time they looked at it. That means a higher chance that if that line was mistaken or broken, someone would have spotted it. That means I can be less vigilant for the possibility that this whole thing is actually broken but being used in a way that makes the breakage non-obvious.
If you're working with people who are sufficiently fluently familiar with the workings of Python, you could even leave off that comment, because to someone who immediately remembers that yield is what makes Python turn a function into a generator, it is obvious that this is the effect, and probably the intent since there is no other reason for correct code to have a non-executed yield.
Alternatively, you could go the decorator route:
#generator_that_yields_nothing
def name_fitting_what_the_function_does():
# that crucial stuff for which this exists
def generator_that_yields_nothing(wrapped):
#functools.wraps(wrapped)
def wrapper_generator():
if False: yield
wrapped()
return wrapper_generator
In a function, I need to perform some logic that requires me to call a function inside a function. What I did with this, like:
def dfs(problem):
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
In the function, dfs, I am using search(root), is this is the correct way to do it?
I am getting an error: local variable 'search' referenced before assignment
There are many mysterious bug-looking aspects in your code. The wrong order of definition (assuming you do need the search function to be a nested one) and the syntax error from the empty while loop have already been observed, but there are more...:
def dfs(problem):
stack.push(bache)
search(root)
what's bache, what's stack, what's root? If they're all global variables, then you're overusing globals -- and apparently nowhere ever using the argument problem (?!).
while stack.isEmpty() != 0:
what's this weird-looking method isEmpty? IOW, what type is stack (clearly not a Python list, and that's weird enough, since they do make excellent LIFO stacks;-)...? And what's ever going to make it empty...?
def search(vertex):
closed.add(vertex)
...don't tell me: closed is yet another global? Presumably a set? (I remember from a few of your Qs back that you absolutely wanted to have a closed dict, not set, even though I suggested that as a possibility...
for index in sars:
...and what's sars?!
stack.push(index)
return stack
what a weird "loop" -- one that executes exactly once, altering a global variable, and then immediately returns that global variable (?) without doing any of the other steps through the loop. Even if this is exactly what you mean (push the first item of sars, period) I don't recommend hiding it in a pseudo-loop -- it seriously looks like a mystery bug just waiting to happen;-).
You need to de-indent your search function. The way you have it set up right now you are defining your search function as a part of the completion of your dfs call. Also, encapsulation in a class would help.
Thats the wrong order. Try this:
def dfs(problem):
def search(vertex):
closed.add(vertex)
for index in sars:
stack.push(index)
return stack
stack.push(bache)
search(root)
while stack.isEmpty() != 0:
Either define search before you call it, or define it outside of dfs.
you have to define the function before using it
root doesn't seem to be available in your scope - make sure it's reachable
You don't have body to your for your while loop. That is probably causing problems parsing the code. I would also suggest putting the local function definition before it is used, so it is easier to follow.