Semantics and ambiguity of "returning" a value? - python-3.x

I was reading up on questions from a python quiz. Here is the following code and its respective question:
class Player(object):
def __init__(self, name, health):
self._name = name
self._health = health
def get_health(self):
"""Return the players health."""
## LINE ##
What is the required code for ## LINE ## so that the method satisfies the comment?
(a) print(self.health)
(b) return self.health
(c) print(self._health)
(d) return self._health
(e) More than one of the above is correct.
So, I'm wondering, is this question ambiguous?
If I state that a specific function's purpose is to "return the value of x", could that not be interpreted as both literally employing the return command to give x's value and using the print command to display the value.
Both give the same answer at face value in the interpreter.
Of course, things are different if you attempt to manipulate it indirectly:
get_health() * 5 yields a normal output if using return
get_health() * 5 yields an error if using print
So should I always treat 'return something' as actually using the return command?
I suppose print and return would both be viable only if the function's purpose said something like "Display the value in the python interpreter".

The correct answer is simply d): return self._health.
You almost answered your own question. Return in programming parlance means use of (the) return (Python/C/... statement, or an implicit return in other languages, etc).
The point here is that that the comment is meant for programmers, not users.
A print statement would imply something to the user running your program ("return output visible to the user"), but the user will not see or know about that comment.
And, as you already pointed out, the use of returning an actual value allows constructs like get_health() * 5.
Going one small step further, I would expect a printing function to be called print_health(); but that's up to the logic of the programming standard & style that is being used.

Related

How can I get a list of variable names from a lark-parser Tree?

I am using python 3.8.5 and lark-parser 0.11.2. I have a question about Visitors.
I have a grammar for my needs and Lark is working great. I have a case where,
under some conditions, I want to evaluate a returned parse tree and scan it to
get a, possibly empty, list of variable names appearing in the tree.
A sample expression is:
count + num_items
The parse tree from the expression is:
Tree('add', [Tree('variable', [Token('VARIABLE', 'count')]), Tree('variable', [Token('VARIABLE', 'num_items')])])
I figured that I would write a Visitor class that would scann the tree for variables and store them in an internal list:
from lark import Visitor, v_args
#v_args(inline=True)
class FindVariables(Visitor):
def __init__(self):
super().__init__()
self.variable_list = []
def variable(self, var):
try:
self.variable_list.append(var)
except Exception as e:
raise
I am trying to use it as:
fv = FindVariables()
fv2 = fv.visit(parse_result)
for var in fv.variable_list:
...
The issue I have is that when fv = FindVariables() is executed I get a
TypeError exception:
f() missing 1 required positional argument: 'self'
If I change the call above to:
fv = FindVariables().visit(parse_result)
the statement runs but fv does not "see" variable_list.
I am probably misusing the Visitor class. Is there a best/better way to approach this?
Well, I am answering my question but I am not sure that it is the answer.
I changed Visitor to Transformer in the code block in the question and it just worked.
I am glad that I have a solution but it feels like Visitor should have been the right tool here. Still happy to find out if I am misusing the lib here and if there is a better way.

How to return a variable from a python function with a single parameter

I have the following function:
def test(crew):
crew1 = crew_data['CrewEquipType1']
crew2 = crew_data['CrewEquipType2']
crew3 = crew_data['CrewEquipType3']
return
test('crew1')
I would like to be able to use any one of the 3 variables as an argument and return the output accordingly to use as a reference later in my code. FYI, each of the variables above is a Pandas series from a DataFrame.
I can create functions without a parameter, but for reason I can't quite get the concept of how to use parameters effectively such as that above, instead I find myself writing individual functions rather then writing a single one and adding a parameter.
If someone could provide a solution to the above that would be greatly appreciated.
Assumption: You problem seems to be that you want to return the corresponding variable crew1, crew2 or crew3 based on your input to the function test.
Some test cases based on my understanding of your problem
test('crew1') should return crew_data['CrewEquipType1']
test('crew2') should return crew_data['CrewEquipType2']
test('crew3') should return crew_data['CrewEquipType3']
To accomplish this you can implement a function like this
def test(crew):
if crew=='crew1':
return crew_data['CrewEquipType1']
elif crew=='crew2':
return crew_data['CrewEquipType2']
elif crew=='crew3':
return crew_data['CrewEquipType3']
...
... # add as many cases you would like
...
else:
# You could handle incorrect value for `crew` parameter here
Hope this helps!
Drop a comment if not

How to modify the signature of a function dynamically

I am writing a framework in Python. When a user declares a function, they do:
def foo(row, fetch=stuff, query=otherStuff)
def bar(row, query=stuff)
def bar2(row)
When the backend sees query= value, it executes the function with the query argument depending on value. This way the function has access to the result of something done by the backend in its scope.
Currently I build my arguments each time by checking whether query, fetch and the other items are None, and launching it with a set of args that exactly matches what the user asked for. Otherwise I got the "got an unexpected keyword argument" error. This is the code in the backend:
#fetch and query is something computed by the backend
if fetch= None and query==None:
userfunction(row)
elif fetch==None:
userunction (row, query=query)
elif query == None:
userfunction (row, fetch=fetch)
else:
userfunction (row,fetch=fetch,query=query)
This is not good; for each additional "service" the backend offers, I need to write all the combinations with the previous ones.
Instead of that I would like to primarily take the function and manually add a named parameter, before executing it, removing all the unnecessary code that does these checks. Then the user would just use the stuff it really wanted.
I don't want the user to have to modify the function by adding stuff it doesn't want (nor do I want them to specify a kwarg every time).
So I would like an example of this if this is doable, a function addNamedVar(name, function) that adds the variable name to the function function.
I want to do that that way because the users functions are called a lot of times, meaning that it would trigger me to, for example, create a dict of the named var of the function (with inspect) and then using **dict. I would really like to just modify the function once to avoid any kind of overhead.
This is indeed doable in AST and that's what I am gonna do because this solution will suit better for my use case . However you could do what I asked more simply by having a function cloning approach like the code snippet I show. Note that this code return the same functions with different defaults values. You can use this code as example to do whatever you want.
This works for python3
def copyTransform(f, name, **args):
signature=inspect.signature(f)
params= list(signature.parameters)
numberOfParam= len(params)
numberOfDefault= len(f.__defaults__)
listTuple= list(f.__defaults__)
for key,val in args.items():
toChangeIndex = params.index(key, numberOfDefault)
if toChangeIndex:
listTuple[toChangeIndex- numberOfDefault]=val
newTuple= tuple(listTuple)
oldCode=f.__code__
newCode= types.CodeType(
oldCode.co_argcount, # integer
oldCode.co_kwonlyargcount, # integer
oldCode.co_nlocals, # integer
oldCode.co_stacksize, # integer
oldCode.co_flags, # integer
oldCode.co_code, # bytes
oldCode.co_consts, # tuple
oldCode.co_names, # tuple
oldCode.co_varnames, # tuple
oldCode.co_filename, # string
name, # string
oldCode.co_firstlineno, # integer
oldCode.co_lnotab, # bytes
oldCode.co_freevars, # tuple
oldCode.co_cellvars # tuple
)
newFunction=types.FunctionType(newCode, f.__globals__, name, newTuple, f.__closure__)
newFunction.__qualname__=name #also needed for serialization
You need to do that weird stuff with the names if you want to Pickle your clone function.

Tkinter Validation variables not necessary? if I try to remove any the program stalls [duplicate]

I have a tkinter GUI with an entry box I want to allow only numbers. Can someone explain to me what each command / line of code in validation does. I don't understand the vcmd variable and all the '%i' '%s' stuff. Thanks :)
UPDATE:
I have a different application to use this vcmd command with and dont understand it entirely. Here is my validation code:
def validate(self, action, index, value_if_allowed, prior_value, text, validation_type, trigger_type, widget_name):
if not int(action):
return True
elif text in '0123456789.-+':
try:
float(value_if_allowed)
return True
except ValueError:
return False
else:
return False
I dont get why in this code i need all of these:
action, index, value_if_allowed, prior_value, text, validation_type, trigger_type, widget_name
Why do i need all of these specific to my validation code for it to function correctly and what use are they?
The documentation you provided made sense but some of those '%s', '%i' stuff seemed unnecessary for my specific code yet it only works with all of them included like so:
vcmd = (self.master.register(self.validate), '%d', '%i', '%P', '%s', '%S', '%v', '%V', '%W')
I also want to know what self.master.register does please, i still cant figure that one out.
If you do not need any of the special arguments, you don't need to call register. For example, the following code will correctly call do_validation without any arguments:
import tkinter as tk
def do_validation():
value = entry.get()
if value == "" or value.isnumeric():
return True
return False
root = tk.Tk()
entry = tk.Entry(root, validate='key', validatecommand=do_validation)
entry.pack(fill="x", padx=20, pady=20)
root.mainloop()
However, in the above case the validation will always be one character behind. This is because validation happens before the character is inserted into the entry widget (ie: the first time it is called, entry.get() will return an empty string). The whole point of validation is to prevent illegal characters, so it makes sense to call the command before the character is inserted rather than after.
This is why the special arguments are useful -- they provide sufficient context in order to decide whether the character or characters are legal before they are inserted into the widget.
How register is useful
Tkinter is a wrapper around a Tcl interpreter, because tk (the core technology behind tkinter) is implemented in Tcl. Tcl is a programming language just like python.
In a Tcl program, you would use the validation features like this:
proc do_validation(new_value) {
return $new_value == "" || [string is integer $new_value]
}
entry .entry -validate key --validatecommand [list do_validation %P]
When Tcl detects a change, it performs substitution on the arguments, and then calls the defined procedure with the substituted arguments. For example, if you type "A", %P is converted to "A" and the function is called with "A" as the only argument.
In the case of Tkinter, there is no direct corollary for defining the function with arguments to be substituted at runtime.
Unfortunately, the validation feature wasn't implemented very well in the tkinter wrapper, so to properly use the validation we have to use a small workaround in order to get these special arguments passed to our function.
What register does is to create a new Tcl command that calls your python command. It also creates a new python command that is a reference to this new Tcl command. You can use this reference exactly like any other python command.
A simple example
In the simplest case, all you need is what the string would look like if the edit was to be allowed. You can then decide whether the edit is something that will result in valid input, or if it will result in invalid input. If the edit won't result in valid input, you can reject the edit before it actually happens.
The special argument that represents the value if the edit is allowed is %P 1. We can modify the function we are registering to accept this argument, and we can add this argument when we do the registering:
def do_validation(new_value):
return new_value == "" or new_value.isnumeric()
...
vcmd = (root.register(do_validation), '%P')
entry = tk.Entry(..., validatecommand=vcmd)
With that, when the underlying Tcl code detects a change it will call the new Tcl command which was created, passing in one argument corresponding to the special %P substitution.
1All of the mechanics of the validation are described thoroughly in the tcl documentation here: http://tcl.tk/man/tcl8.5/TkCmd/entry.htm#M7

NameError: name 'value' is not defined

(background first: I am NEW to programming and currently in my very first "intro to programming class" in my college. This is our second assignment dealing with Functions. So far functions have been a pain in the ass for me because they don't really make any sense. ex: you can use miles_gas(gas) but then don't use "miles_gas" anywhere else, but the program still runs??, anyways)
Okay, I've looked EVERYWHERE online for this and can't find an answer. Everything is using "Exceptions" and "try" and all that advanced stuff. I'm NEW so I have no idea what exceptions are, or try, nor do I care to use them considering my teacher hasn't assigned anything like that yet.
My project is to make a program that gives you the assessment value, and the property tax upon entering your property price. Here is the code I came up with (following the video from my class, as well as in the book)
ASSESSMENT_VALUE = .60
TAX = 0.64
def main():
price = float(input('Enter the property value: '))
show_value(value)
show_tax(tax)
def show_value():
value = price * ASSESSMENT_VALUE
print('Your properties assessment value is $', \
format(value, ',.2f'), \
sep='')
def show_tax(value,TAX):
tax = value * TAX
print('Your property tax will be $', \
format(tax, ',.2f'), \
sep='')
main()
Upon running it, I get it to ask "blah blah enter price:" so I enter price then I get a huge red error saying
Traceback (most recent call last):
File "C:/Users/Gret/Desktop/chapter3/exercise6.py", line 41, in <module>
main()
File "C:/Users/Gret/Desktop/chapter3/exercise6.py", line 24, in main
show_value(value)
NameError: name 'value' is not defined
But I DID define 'value'... so why is it giving me an error??
Python is lexically scoped. A variable defined in a function isn't visible outside the function. You need to return values from functions and assign them to variables in the scopes where you want to use the values. In your case, value is local to show_value.
When you define a function, it needs parameters to take in. You pass those parameters in the brackets of the function, and when you define your function, you name those parameters for the function. I'll show you an example momentarily.
Basically what's happened is you've passed the function a parameter when you call it, but in your definition you don't have one there, so it doesn't know what to do with it.
Change this line:
def show_value():
To this line:
def show_value(price):
And show_value to show_value(price)
For example:
In this type of error:
def addition(a,b):
c = a + b
return c
addition() # you're calling the function,
# but not telling it the values of a and b
With your error:
def addition():
c = a + b
return c
addition(1,2) # you're giving it values, but it
# has no idea to give those to a and b
The thing about functions, is that those variable only exist in the function, and also the name of the parameters doesn't matter, only the order. I understand that's frustrating, but if you carry on programming with a more open mind about it, I guarantee you'll appreciate it. If you want to keep those values, you just need to return them at the end. You can return multiple variables by writing return c, a, b and writing the call like this sum, number1, number2 = addition(1,2)
Another problem is that I could call my addition function like this:
b = 1
a = 2
addition(b,a)
and now inside the function, a = 1 and b = 2, because it's not about the variable names, it's about the order I passed them to the function in.
You also don't need to pass TAX into show_tax because TAX is already a global variable. It was defined outside a function so it can be used anywhere. Additionally, you don't want to pass tax to show_tax, you want to pass value to it. But because show_value hasn't returned value, you've lost it. So return value in show value to a variable like so value = show_value(price).

Resources