Python: return outside function error - python

for x in non_neutral.collect():
tweet = str(x[2])
sid = x[1]
status = x[0]
text = word_tokenize(tweet)
text1 = list(text)
tweet = x[2].split()
pronoun = intersect(second_pronoun,tweet)
perojective = intersect(less_offensive,tweet)
if pronoun:
pronoun_index = tweet.index(pronoun[0])
pero_index = tweet.index(perojective[0])
if pero_index <= pronoun_index+3:
status = 1
return Row(status=status,tid=sid,tweet = str(tweet))
else:
status = 0
return Row(status=status,tid=sid,tweet = str(tweet))
For this particular snippet of code I am constantly getting this error and I don't understand why
File "<ipython-input-5-0484b7e6e4fa>", line 15
return Row(status=status,tid=sid,tweet = str(tweet))
SyntaxError: 'return' outside function
I have tried writing the code again but still getting the same error.

your program doesn't actually contain a function. Return statements must be contained within a function, you haven't defined any in this case.
Try something more like the following (note that this doesn't include all of your code it is just an example):
def Foo():
#Here is where you put all of your code
#Since it is now in a function a value can be returned from it
if pronoun:
pronoun_index = tweet.index(pronoun[0])
pero_index = tweet.index(perojective[0])
if pero_index <= pronoun_index+3:
status = 1
return Row(status=status,tid=sid,tweet = str(tweet))
else:
status = 0
return Row(status=status,tid=sid,tweet = str(tweet))
Foo()
So long as you put your code in a function it will work. The syntax for a basic function definition in python is: def Foo(Bar): Where Foo is the name of the function and Bar is any parameters you may need, each separated by a comma.

I don't see the keyword def in your code snippet, which would indicate the beginning of a function definition. Is the snippet taken from the body of a function?
Here is a working sample of return in a for loop:
from random import shuffle
def loop_return():
values = [0,1]
shuffle(values)
for i in values:
if i == 0:
return 'Zero first.'
if i == 1:
return 'One first.'

You don't actually have a function, so you can't return anything. You could fix it by making the code a procedure.

Related

How to know the name of a classs loade like parameter on other class - Pyhton [duplicate]

This question already has answers here:
Getting the name of a variable as a string
(32 answers)
Closed 4 months ago.
Is it possible to get the original variable name of a variable passed to a function? E.g.
foobar = "foo"
def func(var):
print var.origname
So that:
func(foobar)
Returns:
>>foobar
EDIT:
All I was trying to do was make a function like:
def log(soup):
f = open(varname+'.html', 'w')
print >>f, soup.prettify()
f.close()
.. and have the function generate the filename from the name of the variable passed to it.
I suppose if it's not possible I'll just have to pass the variable and the variable's name as a string each time.
EDIT: To make it clear, I don't recommend using this AT ALL, it will break, it's a mess, it won't help you in any way, but it's doable for entertainment/education purposes.
You can hack around with the inspect module, I don't recommend that, but you can do it...
import inspect
def foo(a, f, b):
frame = inspect.currentframe()
frame = inspect.getouterframes(frame)[1]
string = inspect.getframeinfo(frame[0]).code_context[0].strip()
args = string[string.find('(') + 1:-1].split(',')
names = []
for i in args:
if i.find('=') != -1:
names.append(i.split('=')[1].strip())
else:
names.append(i)
print names
def main():
e = 1
c = 2
foo(e, 1000, b = c)
main()
Output:
['e', '1000', 'c']
To add to Michael Mrozek's answer, you can extract the exact parameters versus the full code by:
import re
import traceback
def func(var):
stack = traceback.extract_stack()
filename, lineno, function_name, code = stack[-2]
vars_name = re.compile(r'\((.*?)\).*$').search(code).groups()[0]
print vars_name
return
foobar = "foo"
func(foobar)
# PRINTS: foobar
Looks like Ivo beat me to inspect, but here's another implementation:
import inspect
def varName(var):
lcls = inspect.stack()[2][0].f_locals
for name in lcls:
if id(var) == id(lcls[name]):
return name
return None
def foo(x=None):
lcl='not me'
return varName(x)
def bar():
lcl = 'hi'
return foo(lcl)
bar()
# 'lcl'
Of course, it can be fooled:
def baz():
lcl = 'hi'
x='hi'
return foo(lcl)
baz()
# 'x'
Moral: don't do it.
Another way you can try if you know what the calling code will look like is to use traceback:
def func(var):
stack = traceback.extract_stack()
filename, lineno, function_name, code = stack[-2]
code will contain the line of code that was used to call func (in your example, it would be the string func(foobar)). You can parse that to pull out the argument
You can't. It's evaluated before being passed to the function. All you can do is pass it as a string.
#Ivo Wetzel's answer works in the case of function call are made in one line, like
e = 1 + 7
c = 3
foo(e, 100, b=c)
In case that function call is not in one line, like:
e = 1 + 7
c = 3
foo(e,
1000,
b = c)
below code works:
import inspect, ast
def foo(a, f, b):
frame = inspect.currentframe()
frame = inspect.getouterframes(frame)[1]
string = inspect.findsource(frame[0])[0]
nodes = ast.parse(''.join(string))
i_expr = -1
for (i, node) in enumerate(nodes.body):
if hasattr(node, 'value') and isinstance(node.value, ast.Call)
and hasattr(node.value.func, 'id') and node.value.func.id == 'foo' # Here goes name of the function:
i_expr = i
break
i_expr_next = min(i_expr + 1, len(nodes.body)-1)
lineno_start = nodes.body[i_expr].lineno
lineno_end = nodes.body[i_expr_next].lineno if i_expr_next != i_expr else len(string)
str_func_call = ''.join([i.strip() for i in string[lineno_start - 1: lineno_end]])
params = str_func_call[str_func_call.find('(') + 1:-1].split(',')
print(params)
You will get:
[u'e', u'1000', u'b = c']
But still, this might break.
You can use python-varname package
from varname import nameof
s = 'Hey!'
print (nameof(s))
Output:
s
Package below:
https://github.com/pwwang/python-varname
For posterity, here's some code I wrote for this task, in general I think there is a missing module in Python to give everyone nice and robust inspection of the caller environment. Similar to what rlang eval framework provides for R.
import re, inspect, ast
#Convoluted frame stack walk and source scrape to get what the calling statement to a function looked like.
#Specifically return the name of the variable passed as parameter found at position pos in the parameter list.
def _caller_param_name(pos):
#The parameter name to return
param = None
#Get the frame object for this function call
thisframe = inspect.currentframe()
try:
#Get the parent calling frames details
frames = inspect.getouterframes(thisframe)
#Function this function was just called from that we wish to find the calling parameter name for
function = frames[1][3]
#Get all the details of where the calling statement was
frame,filename,line_number,function_name,source,source_index = frames[2]
#Read in the source file in the parent calling frame upto where the call was made
with open(filename) as source_file:
head=[source_file.next() for x in xrange(line_number)]
source_file.close()
#Build all lines of the calling statement, this deals with when a function is called with parameters listed on each line
lines = []
#Compile a regex for matching the start of the function being called
regex = re.compile(r'\.?\s*%s\s*\(' % (function))
#Work backwards from the parent calling frame line number until we see the start of the calling statement (usually the same line!!!)
for line in reversed(head):
lines.append(line.strip())
if re.search(regex, line):
break
#Put the lines we have groked back into sourcefile order rather than reverse order
lines.reverse()
#Join all the lines that were part of the calling statement
call = "".join(lines)
#Grab the parameter list from the calling statement for the function we were called from
match = re.search('\.?\s*%s\s*\((.*)\)' % (function), call)
paramlist = match.group(1)
#If the function was called with no parameters raise an exception
if paramlist == "":
raise LookupError("Function called with no parameters.")
#Use the Python abstract syntax tree parser to create a parsed form of the function parameter list 'Name' nodes are variable names
parameter = ast.parse(paramlist).body[0].value
#If there were multiple parameters get the positional requested
if type(parameter).__name__ == 'Tuple':
#If we asked for a parameter outside of what was passed complain
if pos >= len(parameter.elts):
raise LookupError("The function call did not have a parameter at postion %s" % pos)
parameter = parameter.elts[pos]
#If there was only a single parameter and another was requested raise an exception
elif pos != 0:
raise LookupError("There was only a single calling parameter found. Parameter indices start at 0.")
#If the parameter was the name of a variable we can use it otherwise pass back None
if type(parameter).__name__ == 'Name':
param = parameter.id
finally:
#Remove the frame reference to prevent cyclic references screwing the garbage collector
del thisframe
#Return the parameter name we found
return param
If you want a Key Value Pair relationship, maybe using a Dictionary would be better?
...or if you're trying to create some auto-documentation from your code, perhaps something like Doxygen (http://www.doxygen.nl/) could do the job for you?
I wondered how IceCream solves this problem. So I looked into the source code and came up with the following (slightly simplified) solution. It might not be 100% bullet-proof (e.g. I dropped get_text_with_indentation and I assume exactly one function argument), but it works well for different test cases. It does not need to parse source code itself, so it should be more robust and simpler than previous solutions.
#!/usr/bin/env python3
import inspect
from executing import Source
def func(var):
callFrame = inspect.currentframe().f_back
callNode = Source.executing(callFrame).node
source = Source.for_frame(callFrame)
expression = source.asttokens().get_text(callNode.args[0])
print(expression, '=', var)
i = 1
f = 2.0
dct = {'key': 'value'}
obj = type('', (), {'value': 42})
func(i)
func(f)
func(s)
func(dct['key'])
func(obj.value)
Output:
i = 1
f = 2.0
s = string
dct['key'] = value
obj.value = 42
Update: If you want to move the "magic" into a separate function, you simply have to go one frame further back with an additional f_back.
def get_name_of_argument():
callFrame = inspect.currentframe().f_back.f_back
callNode = Source.executing(callFrame).node
source = Source.for_frame(callFrame)
return source.asttokens().get_text(callNode.args[0])
def func(var):
print(get_name_of_argument(), '=', var)
If you want to get the caller params as in #Matt Oates answer answer without using the source file (ie from Jupyter Notebook), this code (combined from #Aeon answer) will do the trick (at least in some simple cases):
def get_caller_params():
# get the frame object for this function call
thisframe = inspect.currentframe()
# get the parent calling frames details
frames = inspect.getouterframes(thisframe)
# frame 0 is the frame of this function
# frame 1 is the frame of the caller function (the one we want to inspect)
# frame 2 is the frame of the code that calls the caller
caller_function_name = frames[1][3]
code_that_calls_caller = inspect.findsource(frames[2][0])[0]
# parse code to get nodes of abstract syntact tree of the call
nodes = ast.parse(''.join(code_that_calls_caller))
# find the node that calls the function
i_expr = -1
for (i, node) in enumerate(nodes.body):
if _node_is_our_function_call(node, caller_function_name):
i_expr = i
break
# line with the call start
idx_start = nodes.body[i_expr].lineno - 1
# line with the end of the call
if i_expr < len(nodes.body) - 1:
# next expression marks the end of the call
idx_end = nodes.body[i_expr + 1].lineno - 1
else:
# end of the source marks the end of the call
idx_end = len(code_that_calls_caller)
call_lines = code_that_calls_caller[idx_start:idx_end]
str_func_call = ''.join([line.strip() for line in call_lines])
str_call_params = str_func_call[str_func_call.find('(') + 1:-1]
params = [p.strip() for p in str_call_params.split(',')]
return params
def _node_is_our_function_call(node, our_function_name):
node_is_call = hasattr(node, 'value') and isinstance(node.value, ast.Call)
if not node_is_call:
return False
function_name_correct = hasattr(node.value.func, 'id') and node.value.func.id == our_function_name
return function_name_correct
You can then run it as this:
def test(*par_values):
par_names = get_caller_params()
for name, val in zip(par_names, par_values):
print(name, val)
a = 1
b = 2
string = 'text'
test(a, b,
string
)
to get the desired output:
a 1
b 2
string text
Since you can have multiple variables with the same content, instead of passing the variable (content), it might be safer (and will be simpler) to pass it's name in a string and get the variable content from the locals dictionary in the callers stack frame. :
def displayvar(name):
import sys
return name+" = "+repr(sys._getframe(1).f_locals[name])
If it just so happens that the variable is a callable (function), it will have a __name__ property.
E.g. a wrapper to log the execution time of a function:
def time_it(func, *args, **kwargs):
start = perf_counter()
result = func(*args, **kwargs)
duration = perf_counter() - start
print(f'{func.__name__} ran in {duration * 1000}ms')
return result

Making own function

I am trying to create a basic function in Python. Below you can see my code:
# Create function
def return_value_fun(type_1,type_2):
if type_1 < 0:
return 0
else:
return type_1-type_2
# Testing function
return_value_fun(100,100)
This function working well. Now I want to put an additional argument tb into the function you can see below:
# Create function
def return_value_fun(type_1,type_2,tb):
if type_1 < 0:
return tb = 0
else:
return tb = type_1-type_2
# Testing function
return_value_fun(100,100)
Additional arguments make this function to not work. So can anybody help me how to solve this?
I'm unclear as to what you're trying to do, but if you want to store the returned value inside a variable, it can be done like this:
# Create function
def return_value_fun(type_1,type_2):
if type_1 < 0:
return 0
else:
return type_1-type_2
# Testing function
tb = return_value_fun(100,100)
Answer is :
# Create function
def return_value_fun(type_1,type_2):
if type_1 < 0:
tb = 0
else:
tb=type_1-type_2
return tb

function within f-string is returning the function outside the string, and returning None inside the string

I'm new to python and trying to do an f-string as follows:
next_patient = East_Room.get_highest_priority()
print(f"The next patient is {next_patient.display_symptoms()} please")
Where East_Room is an instance of a Class and get_highest_priority is a method within the class to display a patient with the highest integer for the 'severity' attribute as follows:
def get_highest_priority(self):
tmp_priority_patient = None
current_size = self.SLL_waiting_list.size()
counter = 1
while counter <= current_size:
tmp_node = self.SLL_waiting_list.get_node(counter)
tmp_patient = tmp_node.get_obj()
if tmp_priority_patient == None:
tmp_priority_patient = tmp_patient
else:
if tmp_patient.severity > tmp_priority_patient.severity:
tmp_priority_patient = tmp_patient
counter = counter + 1
return tmp_priority_patient
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}:{self.symptoms}")
This is the output:
Conor : Naseau
The next patient is None please
I know that this method works as it works perfectly if I call it without the f-string. thanks for you help!
display_symptoms only prints information but doesn't return anything.
In Python, function that don't return anything return None, hence the output you got: "The next patient is None please"
If you also want the function to return this string, you have to explicitly return it:
def display_symptoms(self):
print(f"{self.firstname} {self.lastname}: {self.symptoms}")
return f"{self.firstname} {self.lastname}: {self.symptoms}"
An even better way to do it would be to make it a property:
#property
def display_symptoms(self):
return f"{self.firstname} {self.lastname}: {self.symptoms}"

Write a spider in scrapy, but why 'yield item' not work in a nested for loop?

I have a spider writting in scrapy, but yiled item not executed in for loop, see code below.
def parse_paragraph(self, div_list, category_name, group_name):
for div in div_list:
duilian_text_list = div.xpath('./text()').extract()
duilian_text_list = strip_list(duilian_text_list)
if len(duilian_text_list) == 0:
continue
elif len(duilian_text_list) == 1:
duilian_text = duilian_text_list[0]
self.parse_duilian(duilian_text, category_name, group_name)
elif len(duilian_text_list) == 2 and not is_single_line(duilian_text_list[0]):
duilian_text = ''.join(duilian_text_list)
self.parse_duilian(duilian_text, category_name, group_name)
else:
for duilian_text in duilian_text_list:
duilian_item = DuilianItem()
duilian_item['id'] = str(uuid.uuid4()).replace('-', '')
duilian_item['category_id'] = getCategoryName(category_name)
duilian_item['group_name'] = group_name
duilian = parse_duilian(duilian_text)
if duilian != '|':
duilian_item['name'] = duilian
duilian_item['desc'] = ''
duilian_item['author'] = ''
duilian_item['shuti'] = ''
duilian_item['word_count'] = len(duilian_item['name']) // 2
duilian_item['image_url'] = ''
print('-------I am here--------')
yield duilian_item
when i call this function, i got nothing in output window, it seems the line yiled duilian_item not work, and it even prevent other code to execute(the print line above it).
When i comment out the last line yiled duilian_item, everything works, and i got -------I am here-------- in the output window, what's wrong here?
put it in a simple way, the following code print nothing, but if I comment out yiled 1, it print the list, so yield in python not work in a for loop?
def strange_yield():
list = [1, 2, 3]
for i in list:
print(i)
yield 1
strange_yield()
When you use yield in your python function, the function becomes a Generator Function. The correct way to deal with it following your strange_yield function is:
my_yield = strange_yield()
my_yield is now an instance of the Generator Function strange_yield. Generator Functions can be iterated over or can be pulled the next value by using the next() function:
print(next(my_yield))
or
for yield_value in my_yield:
print(yield_value)

Get value of last expression in `exec` call

Let's say I have some python code in a string
code = """
a = 42
a
"""
and I exec that string of code:
result = exec(code)
Then result will always be None. Is there any way at all to get the value of the last expression evaluated? In this case, that would be 5, since a was the last expression.
EDIT: Here's another example of the functionality I'm asking about. Let's say we have the python code (stored in the variable code)
a = 100
sqrt(a)
Then how can I execute the code in such a way as to give me the result 10 - that is, sqrt(a)?
EDIT EDIT: A further example: the code I wish to exec is
function_a()
function_b()
function_c()
Is there any way I can define some kind of magic_exec function so that
magic_exec(code)
will provide me with the value of function_c()?
The request is certainly valid because I need such a function as well during the creation of a Python-based environment. I solved the problem with the following code that utilizes the Python ast mechanism:
def my_exec(script, globals=None, locals=None):
'''Execute a script and return the value of the last expression'''
stmts = list(ast.iter_child_nodes(ast.parse(script)))
if not stmts:
return None
if isinstance(stmts[-1], ast.Expr):
# the last one is an expression and we will try to return the results
# so we first execute the previous statements
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
# then we eval the last one
return eval(compile(ast.Expression(body=stmts[-1].value), filename="<ast>", mode="eval"), globals, locals)
else:
# otherwise we just execute the entire code
return exec(script, globals, locals)
The code should be pretty self-explanatory, basically it
separate the script into multiple statements
if the last one is an expression, execute the first part as statements, and the last part as expression.
Otherwise execute the entire script as statements.
This doesn't get you the last evaluated value, but gets the whole list of local variables.
>>> loc = {}
>>> exec(code, {}, loc)
>>> loc
{'a': 42}
exec('a = 4')
print a % prints 4
>>> code = """
... a = 42
... b = 53"""
>>> exec(code)
>>> a
42
>>> b
53
Or if you're saying you don't know the last thing is b for instance, then you can have this:
code = """
a = 4
b = 12
abc_d=13
"""
t = re.findall(r'''.*?([A-Za-z0-9_]+)\s*?=.*?$''', code)
assert(len(t)==1)
print t[0] % prints 13
To be honest I can't say I'm very happy with this. It feels very hacky and I haven't tested it all that heavily. On the other hand I'm quite pleased with it. Was quite fun to do. Anyway, hope this helps you or at least comes close to what you want. locals() gives a dict so the output list order does not match the input order for the items that failed the first eval. If you don't want ';' as delimiters then you can change it to '\n'.
import math
def magic_exec(_command):
_command = _command.split(';')
_result = None
_before = list(locals()) # Get list of current local variables
for _code in _command:
_code = _code.strip() # .strip() prevent IndentationError
try:
if eval(_code) != None: # For functions with no return
_result = eval(_code)
except (NameError, SyntaxError):
try:
_before = list(locals())
exec(_code)
except NameError as e: # For undefined variables in _command
print("An Error Occurred with line ' {0} ' as was skipped: {1}".format(_code, e))
del _code # delete temp var _code
# Get new list of locals that didn't exist at the start
_after = [val for val in list(locals()) if val not in _before]
if _after:
return eval(_after[0])
else:
return _result
#Dummy class and functions
class Class1(object):
def __init__(self, x):
self._x = x
def get_val(self):
return self._x
def __repr__(self):
return type(self).__name__
def func1(x):
return x + x
def func2(x):
print(x*x)
if __name__ == '__main__':
code = \
"""
a = 42; a; v; y = 2; b = func1(5); s = 'Hello'; func2(10); c = 25; l = []; l.append('Value');
t = math.sqrt(c); pass; 20*10; print('TEST'); math.sqrt(c); d = Class1('World'); d.get_val();
def func3(x): return x ** 2; s = func3(15)
"""
values = magic_exec(code)
print(values)
I would like to add to user2283347's excellent answer that it works only up to Python 3.7. In Python 3.8 the signature of ast.Module.__init__ has changed. It now requires a second argument which in our case can be an empty list.
Details: ast.Module(body=stmts[:-1]) in
if len(stmts) > 1:
exec(compile(ast.Module(body=stmts[:-1]), filename="<ast>", mode="exec"), globals, locals)
has to be changed to
ast.Module(stmts[:-1], []) if you use Python 3.8 or above (note the second argument []). Otherwise the following TypeError will be raised:
TypeError: required field "type_ignores" missing from Module
Unfortunately this change is not very well documented. I found the solution after extensive Googling here: "IPython broken on 3.8-dev" .

Categories

Resources