Python question on parse routines with dicts, while loops, and assignments - python

I have some code from a much-maligned Python resource, if you ask SO, but I am trying to divine Python’s parse routine from it, regardless its didactic merits.
def princess_lives_here():
#<some messages and conditionals to keep you going in the text-based game>
#<one of the conditionals end in a `return 'death'`, another function in ROOMS>
ROOMS = {
'death': death,
'princess_lives_here': princess_lives_here,
}
def runner (map, start):
next = start
while True:
room = map[next]
print "\n--------"
next = room()
runner(ROOMS, 'princess_lives_here')
What I am not sure about is how princess_lives_here is ever run in the while loop. I can only assume that it is run is the last line, but what looks like an assignment to me must be an execution of room(), i.e. princess_lives_here. Why, when and how is this execution performed?
My second question is how, when, and why the while loop is run again, when the parsing routines hits return 'death'.
I’ve created a gist with the entire code, in case you want the greater picture. It just takes up a lot of lines of code: https://gist.github.com/848228.

After looking at the original code will analyze it for you:
1) The program enters at the point:
runner(ROOMS, 'princess_lives_here')
2) runner function gets a map (a list of available rooms where we can go) and a start point at the map. So, the previous call uses the map defined in the ROOMS dictionary and sets us in the princess_live_here room.
3) The runner loop, gets the actual room dictionary value, so, we get a reference for a function called princess_live_here that is defined at top of the file, prints some output and calls that function using the reference.
4) At princess_lives_here we can input some text, that text will decide what to do next, returning the next room we will go. For example, if we write: "make her eat it", the function will return the key for the 'gold_koi_pond' room, and the loop will then setup that room as the actual room for us, and get again the dictionary value for that room and call it.
So, answering you more focused way:
a) The execution is that I've described above this lines
b) When any function returns 'death' the execution is the same as above, but the death function will print a random quote and exit the program.
Just that.

First thing to mention, is that next is a built-in function in Python and as soon as you assign it to anything else you are loosing it's reference for futures accesses. Therefore:
>>> next
<built-in function next>
>>> next = 'a'
>>> next
'a'
>>>
It's considered a bad practice to override built-in functions. As soon as you assign next to start (first line of runner function) the reference to next built-in is lost in the scope of that function.
More specifically on the questions you posted:
1) Think of functions as 'objects' that can be assigned to variables and that by postfixing () you make a call to them. It's also similar to the concept of pointer to a function in C. In your design, the pointers to functions reside in the dictionary ROOMS, so that when you access as:
room = ROOMS["princess_lives_here"]
room will point to the function princess_lives_here and room() will perform a call to that function. If this function returns a string that is a key on the ROOM dictionary then the next iteration of the loop will do exactly the same.
2) Looking at the code you posted it. if "death" is returned then next will hold that string value, which will be the lookup key for the dictionary ROOM (1st line of the loop), which will make room to hold a pointer to the function death(2nd line of the loop). And the last line of the loop will perform a call to the function that is pointed by room, which is death in this case. Since this function performs exit then the program will terminate. No more iterations will happen.

Related

What happens when you invoke a function that contains yield?

I read here the following example:
>>> def double_inputs():
... while True: # Line 1
... x = yield # Line 2
... yield x * 2 # Line 3
...
>>> gen = double_inputs()
>>> next(gen) # Run up to the first yield
>>> gen.send(10) # goes into 'x' variable
If I understand the above correctly, it seems to imply that Python actually waits until next(gen) to "run up to" to Line 2 in the body of the function. Put another way, the interpreter would not start executing the body of the function until we call next.
Is that actually correct?
To my knowledge, Python does not do AOT compilation, and it doesn't "look ahead" much except for parsing the code and making sure it's valid Python. Is this correct?
If the above are true, how would Python know when I invoke double_inputs() that it needs to wait until I call next(gen) before it even enters the loop while True?
Correct. Calling double_inputs never executes any of the code; it simply returns a generator object. The presence of the yield expression in the body, discovered when the def statement is parsed, changes the semantics of the def statement to create a generator object rather than a function object.
The function contains yield is a generator.
When you call gen = double_inputs(), you get a generator instance as the result. You need to consume this generator by calling next.
So for your first question, it is true. It runs lines 1, 2, 3 when you first call next.
For your second question, I don't exactly get your point. When you define the function, Python knows what you are defining, it doesn't need to look ahead when running it.
For your third question, the key is yield key word.
Generator-function is de iure a function, but de facto it is an iterator, i.e. a class (with implemented __next__(), __iter()__, and some other methods.)
          In other words, it is a class disguised as a function.
It means, that “calling” this function is in reality making an instance of this class, and explains, why the “called function” does initially nothing. This is the answer to your 3rd question.
The answer to your 1st question is surprisingly no.
Instances always wait for calling its methods, and the __next__() method (indirectly launched by calling the next() build-in function) is not the only method of generators. Other method is the .send(), and you may use gen.send(None) instead of your next(gen).
The answer to your 2nd question is no. Python interpreter by no mean "look ahead" and there are no exceptions, including your
... except for parsing the code and making sure it's valid Python.
Or the answer to this question is yes, if you mean “parsing only up to the next command”. ;-)

Running function code only when NOT assigning output to variable?

I am looking for a way in python to stop certain parts of the code inside a function but only when the output of the function is assigned to a variable. If the the function is run without any assignment then it should run all the inside of it.
Something like this:
def function():
print('a')
return ('a')
function()
A=function()
The first time that I call function() it should display a on the screen, while the second time nothing should print and only store value returned into A.
I have not tried anything since I am kind of new to Python, but I was imagining it would be something like the if __name__=='__main__': way of checking if a script is being used as a module or run directly.
I don't think such a behavior could be achieved in python, because within the scope of the function call, there is no indication what your will do with the returned value.
You will have to give an argument to the function that tells it to skip/stop with a default value to ease the call.
def call_and_skip(skip_instructions=False):
if not skip_instructions:
call_stuff_or_not()
call_everytime()
call_and_skip()
# will not skip inside instruction
a_variable = call_and_skip(skip_instructions=True)
# will skip inside instructions
As already mentionned in comments, what you're asking for is not technically possible - a function has (and cannot have) any knowledge of what the calling code will do with the return value.
For a simple case like your example snippet, the obvious solution is to just remove the print call from within the function and leave it out to the caller, ie:
def fun():
return 'a'
print(fun())
Now I assume your real code is a bit more complex than this so such a simple solution would not work. If that's the case, the solution is to split the original function into many distinct one and let the caller choose which part it wants to call. If you have a complex state (local variables) that need to be shared between the different parts, you can wrap the whole thing into a class, turning the sub functions into methods and storing those variables as instance attributes.

How do I preserve the elements of a dictionary with each successive function call?

To clarify, i'm reading from a file and sending each line to a function(1) where it's relevant elements are put into a list. That list is then sent to another function(2) and added to a dictionary, with one element of that list being a key, and the other(s) put inside another list, being the value. So, basically {key:(value(,value)).
Problem is, whenever I send the list from (1) to (2), the newly created dictionary is overwritten. I'm new to Python, but i'm pretty sure I can add multiple keys and values to one dictionary right? So, is there a way to save the elements of the dictionary each time (2) is called? So, if it's called once, it has tokens(a) in the dictionary. When it's called again, it still has tokens(a), and now tokens(b) is added, and so forth.
If you need code I can include it.
MCVE:
def file_stuff(file name):
#opens and reads file using with x open as thing....then
for line in thing:
function1(line)
def function1(line):
#Breaks down line using regex; variable name var for this example
#list the relevant components of the line will go into
element = list()
for x in var:
list.append(x)
function2(element)
def function2(element):
#Another list is made along with a dictionary
webster = dict()
values = list()
for x in range(len(element)):
#inserts into dictionary.....the problem being, however, that I need this dictionary to "remember" what was already stored inside
In your current code, webster is a local variable in function2 that gets bound to a dictionary. However, you never return or do anything else with the dictionary that would allow code outside that function to see it, so when the function ends, there are no further references to the dictionary and it will be garbage collected.
If you want each call to function2 to use the same dictionary, you need to change the function so that it accesses the dictionary differently. Exactly what way is best will depend on the larger design of your program.
One option would be to make webster a global variable, which function2 can modify in place. This is very easy to do, but it has some pretty severe limitations, since a module has just the one global namespace. Working with multiple files that should have their data put into multiple different dictionaries would be very tough.
It would look something like this:
webster = {}
def function2(element):
...
webster[some_key] = some_value
Another option would be to make the dictionary an argument to the function, so that the calling code is responsible for creating and holding a reference to it in between calls. This is probably a better approach than using a global variable, but it's harder for me to demonstrate since it's not really clear to me where the dictionary should live in your example (maybe in function1, or maybe it needs to be passed all the way through from file_stuff).
It might look something like:
def caller():
the_dict = {}
for item in some_sequence():
function2(item, the_dict)
def function2(item, webster)
...
webster[some_key] = some_value
A final option would be to have function2 still be in charge of creating the dictionary, but for it to return the dictionary to its caller, who could do something with it (such as merging its contents with the dictionaries from previous calls). I'm not even going to attempt to demonstrate this one, since the merging process would depend a lot on what exactly you're putting in your dictionary. (A related option would be to return some other non-dictionary value (or a tuple of values) which could then be inserted in a dictionary by the calling code. This might be easier than dealing with an intermediate dictionary in some situations.)

Python 3.3 - Game - Hint System

I want to make it so it prints different hints dependent on where the player is in the game. I tried it by setting the value of 'Hint' every time the player went somewhere. Obviously I came across a flaw (as I'm here). The value of Hint = 1 was first in one def and I couldn't manage to summon it when writing the Help/Hint def. My pathetic example:
def Room_Choice():
Hint = 1
(60 lines down)
def Hint():
Choice = input("What would you like?\n")
if Choice == ("Hint"):
if Room_Choice(Hint = 1):
print_normal("blah blah blah\n")
else:
print_normal("HINT-ERROR!\n")
Help_Short()
And obviously as the game developed more and more values of hint would be added.
As you can see I'm relatively new to Python and need help.
You are trying to reach a value that exists in a function scope, and you're doing it wrong (as you're here).
Imagine scopes as boxes of one-way mirrors : when you're inside one, you can see what's in the box and what's outside of the box. But you can't see what's in a box you are not in.
Here, Hint exists within the box of Room_Choice, but not in the box of H... oh wait.
You've called your function Hint too ! If you want to reach Hint in a function called Hint with no Hint defined inside the function, you'll probably get the function. Let's call the function DoHint()
So you can't see Hint from within DoHint, because it's in another box. You have to put it somewhere (over the rainboooow... sorry for that) you can see it.
You might want to put it at the module level (not within a def), or make it an object's attribute (but you'll have to know bits of Oriented Object Programming to understand that).
This is really basic programming skills, I can't really explain further without knowing what you're trying to do and showing you how I would do it, but I hope that helped.
Just one more thing on this line : if Room_Choice(Hint = 1):, here you're trying to check if the result of the Room_Choice function with a value of 1 for the Hint parameter is True. I don't know what you wanted to do, but the Room_Choice function doesn't show it can handle any parameters (you should get an error on that), and will not return a boolean value (it will implicitly return None, which is evaluated as a logical False).

Is it pointless to receive a parameter/argument and do nothing with it?

I'm learning python from a textbook. This code is for the game Tic-Tac-Toe.
The full source code for the problem:
http://pastebin.com/Tf4KQpnk
The following function confuses me:
def human_move(board, human):
""" Get human move."""
legal = legal_moves(board)
move = None
while move not in legal:
move = ask_number("Where will you move? (0 - 8): ", 0, NUM_SQUARES)
if move not in legal: print "\nThat square is already taken. Choose another.\n"
print "Fine..."
return move
I do not know why the function receives 'human' parameter. It appears to do nothing with it.
def human_move(board, human):
How would I know to send 'human' to this function if I were to write this game from scratch? Because I can't see why it is sent to this function if it isn't used or returned.
The answer: it depends. In your example it seems useless to me, but I haven't checked it in depth.
If you create a function to be used only from your code, it is in fact useless.
def calculate_money(bank_name, my_dog_name):
return Bank(bank_name).money
money = calculate_money('Deutsche bank', 'Ralph')
But if you are working with some kind of API/Contract, the callbacks you specify might accept arguments that are not needed for a certain implementation, but for some others, are necessary.
For instance, imagine that the following function is used in some kind of framework, and you want the framework to show a pop up when the operation is finished. It could look something like this:
def my_cool_callback(names, accounts, context):
# do something blablab
context.show_message('operation finished')
But what if you don't really need the context object in your callback? you have to speficy it anyway for the signature to match... You can't call it pointless because that parameter is used sometimes.
EDIT
Another situation in which it could be useful, would be to loop through a list of functions that have almost the same signature. In that case could be ok also to have extra arguments as "garbage placeholders". Let's say all your functions need 3 arguments in general, but one needs only 2.

Categories