Currently stuck with this syntax error, error is posted below the code.
#property
def data_rows(self):
for d in rlgenevautils.to_csv_dict(self.data_file):
trade_dt = rlcore.str2dt(d['EventDate'])
settle_dt = rlcore.str2dt(d['ActualSettleDate'])
yield (str(d['_UDF_SGCP_ID_'])
,str(d['_UDF_Execution_ID_'])
,str(d['_UDF_PB_ID_'])
,str(d['_UDF_Fund_Admin_ID_'])
,str(d['_Portfolio_NameSort_'])
,str(d['_Strategy_Code_'])
,str(d['_LocationAccount_NameSort_'])
,str(d['_Broker_NameSort_'])
,str(d['_Investment_Code_'])
,trade_dt.isoformat(' ')
,settle_dt.isoformat(' ')
,rlcore.str2float(d['ABSQuantityForCalcCurrentFace'])
,max(rlcore.str2float(d['ABSQuantityForCalcCurrentFace']),rlcore.str2float(d['OriginalFace']))
,rlcore.str2float(d['ABSQuantityForCalcCurrentFace'])/max(rlcore.str2float(d['ABSQuantityForCalcCurrentFace']),rlcore.str2float(d['OriginalFace']))
,rlcore.str2float(d['Price'])
,rlcore.str2float(d['ABSAccruedInterestForCalcCurrentFace'])
,if str(d['_Investment_InvestmentGroup_']) == "AssetBacked":
rlcore.str2float(d['ABSQuantityForCalcCurrentFace']) * rlcore.str2float(d['Price']) / 100
else:
rlcore.str2float(d['NetCashAmount'])
,rlcore.str2float(d['ABSAccruedInterestForCalcCurrentFace']) + rlcore.str2float(d['txtNetCashPreAccrued'])
)
Traceback (most recent call last):
File ".\sg\rec_and_liquidity\geneva_trade.py", line 64
,if str(d['_Investment_InvestmentGroup_']) == "AssetBacked":
^
Code above, unable to figure out what my syntax error is on the if statement. Error message will be pasted as comment shortly
You can't include an if statement inside an expression like that. If you want to include it in an expression, you need to use a conditional expression:
(rlcore.str2float(d['ABSQuantityForCalcCurrentFace']) * rlcore.str2float(d['Price']) / 100) if str(d['_Investment_InvestmentGroup_']) == "AssetBacked" elserlcore.str2float(d['NetCashAmount'])
However, this is not very readable. It would be better to move your if statement to before the yield, assign the result to a variable, and use that variable in the yield.
'if' is a statement, and creating tuple this way you can use only expressions.
Change your code like follows:
if condition:
something
else:
something2
to
something if condition else something2
The problem is that you can't put a statement in the middle of an expression.
For simple cases, there is an if expression that, being an expression, can be used in the middle of an expression. In your case:
(rlcore.str2float(d['ABSQuantityForCalcCurrentFace']) * rlcore.str2float(d['Price']) / 100
if str(d['_Investment_InvestmentGroup_']) == "AssetBacked"
else rlcore.str2float(d['NetCashAmount']))
For more complicated cases, move the if statement upward and store a temporary value in a variable, then use that variable in the expression (exactly as you're already doing for, each, trade_dt):
if str(d['_Investment_InvestmentGroup_']) == "AssetBacked":
priceval = rlcore.str2float(d['ABSQuantityForCalcCurrentFace']) * rlcore.str2float(d['Price']) / 100
else:
priceval = rlcore.str2float(d['NetCashAmount'])
… then just use priceval in the yield.
However, no matter how you solve this, your code is a huge unreadable mess. You have at least three different conversion methods you're using repeatedly; if you discover that you're formatting dates or strings or whatever wrong, you'll need to change that in dozens of places. You'd probably do better off with a mapping of column names to either types, or converters, and then just generate the values by dynamically looking up each converter. For example:
_COLUMNS = {'_UDF_SGCP_ID_': str,
'_UDF_Execution_ID_': str,
# ...
'EventDate': datetime.datetime,
# ...
}
_CONVERTERS = {str: str,
datetime.datetime: lambda val: rlcore.str2dt(val).isoformat(),
# ...}
def _converted(d, col):
val = d[col]
converter = _CONVERTERS[_COLUMNS[col]]
return converter(val)
And now you can just do this:
yield(_converted(d, col) for col in (
'_UDF_SGCP_ID_',
'_UDF_Execution_ID_',
# ...
)
Related
I have a function I'm using to test in an if/then.
The issue is that I'm executing the function BOTH in the if conditional, and then again after the if statement because the function returns two items.
This just seems wasteful and I'm trying to think of ways to improve this. Here's a really basic version of what I'm trying to avoid: "True" is returned to allow the condition to pass, but then then "coolstuff()" is executed again to get more information from the function.
"coolstuff()" could possibly return false, so I can't use the returned string "stuff" as the test.
def coolstuff():
return True, "stuff"
if coolstuff()[0]:
coolthing = coolstuff()[1]
print coolthing
There's gotta be a better way to do this, no? My brain is melting a little as I try to hash it out.
I basically want to do something like this (invalid) syntax:
def coolstuff():
return True, "stuff"
if a, b == coolstuff() and a:
print b
Just collect both results into variables
a, b = fn()
if a:
# work with b
def coolstuff():
if valid:
return "stuff"
return None
data = coolstuff()
if data:
print(data)
Call the function and capture the entire returned value:
x = coolstuff()
Now you have access to both parts of the returned value, in x[0] and x[1].
Store it:
state, coolvar = coolstuff()
if state:
do_whatever(coolvar)
If in newer Python, you could use the dreaded walrus (but I prefer ti7's approach of just assigning in a separate line):
if (x := coolstuff())[0]:
print(x[1])
This is a little difficult to explain, so let's hope I'm expressing the problem coherently:
Say I have this list:
my_list = ["a string", 45, 0.5]
The critical point to understand in order to see where the question comes from is that my_list is generated by another function; I don't know ahead of time anything about my_list, specifically its length and the datatype of any of its members.
Next, say that every time <my_list> is generated, there is a number of predetermined operations I want to perform on it. For example, I want to:
my_text = my_list[1]+"hello"
some_var = my_list[10]
mini_list = my_list[0].split('s')[1]
my_sum = my_list[7]+2
etc. The important point here is that it's a large number of operations.
Obviously, some of these operations would succeed with any given my_list and some would fail and, importantly, those which fail will do so with an unpredictable Error type; but I need to run all of them on every generation of my_list.
One obvious solution would be to use try/except on each of these operations:
try:
my_text = my_list[1]+"hello"
except:
my_text = "None"
try:
some_var = my_list[10]
except:
some_var = "couldn't do it"
etc.
But with a large number of operations, this gets very cumbersome. I looked into the various questions about multiple try/excepts, but unless I'm missing something, they don't address this.
Based on someone's suggestion (sorry, lost the link), I tried to create a function with a built-in try/except, create another list of these operations, and send each operation to the function. Something along the lines of
def careful(op):
try:
return op
else:
return "None"
And use it with, for example, the first operation:
my_text = careful(my_list[1]+"hello")
The problem is python seems to evaluate the careful() argument before it's sent out to the function and the error is generated before it can be caught...
So I guess I'm looking for a form of a ternary operator that can do something like:
my text = my_list[1]+"hello" if (this doesn't cause any type of error) else "None"
But, if one exist, I couldn't find it...
Any ideas would be welcome and sorry for the long post.
Maybe something like this?
def careful(op, default):
ret = default
try:
ret = computation()
else:
pass
return ret
If you must do this, consider keeping a collection of the operations as strings and calling exec on them in a loop
actions = [
'my_text = my_list[1]+"hello"',
'some_var = my_list[10]',
'mini_list = my_list[0].split("s")[1]',
'my_sum = my_list[7]+2',
]
If you make this collection a dict, you may also assign a default
Note that if an action default (or part of an action string) is meant to be a string, it must be quoted twice. Consider using block-quotes for this if you already have complex escaping, like returning a raw strings or a string representing a regular expression
{
"foo = bar": r"""r'[\w]+baz.*'"""
}
complete example:
>>> actions_defaults = {
... 'my_text = my_list[1]+"hello"': '"None"',
... 'some_var = my_list[10]': '"couldn\'t do it"',
... 'mini_list = my_list[0].split("s")[1]': '"None"',
... 'my_sum = my_list[7]+2': '"None"',
... }
>>>
>>> for action, default in actions_defaults.items():
... try:
... exec(action)
... except Exception: # consider logging error
... exec("{} = {}".format(action.split("=")[0], default))
...
>>> my_text
'None'
>>> some_var
"couldn't do it"
Other notes
this is pretty evil
declaring your vars before running to be their default values is probably better/clearer (sufficient to pass in the except block, as the assignment will fail)
you may run into weird scoping and need to access some vars via locals()
This sounds like an XY Problem
If you can make changes to the source logic, returning a dict may be a much better solution. Then you can determine if a key exists before doing some action, and potentially also look up the action which should be taken if the key exists in another dict.
I am new to python and i have this project I am working on a small project with two functions where the first returns the index of the first time a difference is spotted in a string. The next function does that but in a list of strings. Now, due to my being an amateur, i have used an excessive amount of if and else statements which resulted in too many return statements especially in the second function, and i get the error [R1710: inconsistent-return-statements]. How do i fix it and can anybody give me clear examples to better pieces of code? Sorry for the question being so long.
IDENTICAL = -1
def singleline_diff(line1, line2):
"""
Inputs:
line1 - first single line string
line2 - second single line string
Output:
Returns the index where the first difference between
line1 and line2 occurs.
Returns IDENTICAL if the two lines are the same.
"""
len1 = len(line1)
len2 = len(line2)
minimum_length = min(len1, len2)
if len1 != len2:
if minimum_length == 0:
return 0
for idx in range(minimum_length):
if line1[idx] == line2[idx]:
pass
else:
return idx
return idx + 1
for idx in range(len1):
if line1[idx] == line2[idx]:
pass
else:
return idx
return IDENTICAL
def multiline_diff(lines1, lines2):
"""
Inputs:
lines1 - list of single line strings
lines2 - list of single line strings
Output:
Returns a tuple containing the line number (starting from 0) and
the index in that line where the first difference between lines1
and lines2 occurs.
Returns (IDENTICAL, IDENTICAL) if the two lists are the same.
"""
line_no = singleline_diff(lines1, lines2)
len_lines1, len_lines2 = len(lines1), len(lines2)
if len_lines1 == len_lines2:
if (len_lines1 or len_lines2) == 0:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
if line_no == IDENTICAL:
return (IDENTICAL, IDENTICAL)
elif line_no != IDENTICAL:
return (line_no, idx)
else:
return (line_no, 0)
Where was a semantic mistake in OP's code is in Abhishek Arya's answer
TL;DR - early return:
def your_function():
if not should_do():
return # NO RETURN VALUE!
# rest of the function
...yes, this will no longer emit the inconsistent-return-statements ;)
This Q/A pops also when you search for inconsistent-return-statements, I want to give a brief "common problems" guide for those.
Case A: return value is irrelevant, you just want to exit function early
There are cases, where there are functions (or "procedures" if you want to get technical about it) that just do something, but are not expected to have any return values AT ALL,
at the same time, there may be e.g. some sort of check at the start of the function whether this function run even makes sense, what may first come to your mind, is wrapping the whole function code in an if statement:
def your_function(article):
if display_content():
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
...this is oversimplified, but let's hope you can imagine how such coding can pretty quickly fall into a "spaghetti code" if there are more checks and more code in general + it also steals that one "tab" of a space that you so desperately need to fit into your project's max line length.
Luckily, same as in many other programming languages, there IS a way of an early ending of a function by returning at ANY place within the function run, meaning in any "Control Flow" - including if/elif/else, for/while loops, ...
Now you'd probably jump quick to just return None, False, etc. although it would work, you'd still get the pylint inconsistent-return-statements warning - to understand why let's see the warning's message:
Either all return statements in a function should return an
expression, or none of them should. pylint(inconsistent-return-statements)
From pylint's point of view, if you put anything after the return it will be considered as an expression. So what to do? Actually, in Python, you CAN return "nothing" (again this is not unique to Python)
def your_function(article):
if not display_content():
return
content = get_content(article)
# do some extensive logic to generate final content
# ...
print(content)
Although in Python returning "nothing" should be (and technically, to my knowledge, it is) an equivalent of return None, by physically writing "None" you are expressing the intention no matter the implicity of it.
Don't confuse this though with pylint(assignment-from-none) (Assigning result of a function call, where the function returns None) - where both "return" AND "return None" are considered as returning None!
Case B: Your function has a case when it doesn't return
Quite common mistake especially in a larger code is to create a code part which results in simply not returning anything. This is not exactly OP's case, since they used just a negation of the same condition, but pylint doesn't know that, so here's its thought process:
if SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
elif OPPOSITE_OF_SOME_CONDITION: # ok, here's just another condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# WAIT ! What?! THERE WAS NO "else:"! Hmmm...
# ...what happens if both conditions fail? NOTHING WOULD BE RETURNED!
# We need to make a warning about that!
# (fact that sometimes they return SOMETHING and sometimes NOTHING)
So this inconsistent-return-statements could be resolved with
if SOME_CONDITION: # ok, here's some condition
return someReturnExpression # and ok, it returns SOMETHING, let's note that
else: # ok, here's else
return someReturnExpression # and ok, it returns SOMETHING, let's note that
# Ok, so if returns SOMETHING, else returns SOMETHING,
# so SOMETHING is returned every time! that's good!
...this in itself works, but it will generate yet another pylint issue
Unnecessary "else" after "return" pylint(no-else-return)
See python actually encourages early returns since it often leads to a cleaner code.
return during function run ENDS(/exits) the function and pylint sees that - it sees that if the condition was true, the function code would simply end there - so what it, Abhishek Arya, me and many others suggest is simply continuing with the code after the if part:
if SOME_CONDITION:
return someReturnExpression
# ... some more code ...
# ... some more code ...
return someReturnExpression
Case C: Combination
Simply don't combine "just" return with return SOMETHING,
if you really need to return None, simply explicitly return None in that case
def get_article(id):
article = find_article(id)
if article.id == 0:
return None
return article
This is just an example, this is not how you'd really check for some articles ;)
Look at the code here:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
else:
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You could have written the above thing like:
if len_lines1 == len_lines2:
return (IDENTICAL, IDENTICAL)
idx = singleline_diff(lines1[line_no], lines2[line_no])
return (line_no, idx)
You just don't need an else block to return this expression as this part of code will automatically be called if the control doesn't go into if block. Hope it helps.
Suppose I have function with list parameter, and inside it's body I want to modify passed list, by this code:
spy = [0,0,7]
def replace_spy(lista):
return lista[2]=lista[2]+1
but it show me the error : SyntaxError: invalid syntax
Assignment is a statement, not an expression. It has no value. So you can't return the value of an assignment.
Across languages that do allow this kind of thing, it's ambiguous what exactly the return value should be, but most of them—including C and the many languages derived from or inspired by C—would give you the new value of lista[2]1. So presumably you want this:
def replace_spy(lista):
lista[2]=lista[2]+1
return lista[2]
If you're looking to shorten things, this is fewer keystrokes, and probably more readable:
def replace_spy(lista):
lista[2] += 1
return lista[2]
1. As an "lvalue", but that isn't a meaningful thing in Python.
I find that in lots of different projects I'm writing a lot of code where I need to evaluate a (moderately complex, possibly costly-to-evaluate) expression and then do something with it (e.g. use it for string formatting), but only if the expression is True/non-None.
For example in lots of places I end up doing something like the following:
result += '%s '%( <complexExpressionForGettingX> ) if <complexExpressionForGettingX> else ''
... which I guess is basically a special-case of the more general problem of wanting to return some function of an expression, but only if that expression is True, i.e.:
f( e() ) if e() else somedefault
but without re-typing the expression (or re-evaluating it, in case it's a costly function call).
Obviously the required logic can be achieved easily enough in various long-winded ways (e.g. by splitting the expression into multiple statements and assigning the expression to a temporary variable), but that's a bit grungy and since this seems like quite a generic problem, and since python is pretty cool (especially for functional stuff) I wondered if there's a nice, elegant, concise way to do it?
My current best options are either defining a short-lived lambda to take care of it (better than multiple statements, but a bit hard to read):
(lambda e: '%s ' % e if e else '')( <complexExpressionForGettingX> )
or writing my own utility function like:
def conditional(expr, formatStringIfTrue, default='')
... but since I'm doing this in lots of different code-bases I'd much rather use a built-in library function or some clever python syntax if such a thing exists
I like one-liners, definitely. But sometimes they are the wrong solution.
In professional software development, if the team size is > 2, you spent more time on understanding code someone else wrote than on writing new code. The one-liners presented here are definitely confusing, so just do two lines (even though you mentioned multiple statements in your post):
X = <complexExpressionForGettingX>
result += '%s '% X if X else ''
This is clear, concise, and everybody immediately understands what's going on here.
Python doesn't have expression scope (Is there a Python equivalent of the Haskell 'let'), presumably because the abuses and confusion of the syntax outweigh the advantages.
If you absolutely have to use an expression scope, the least worst option is to abuse a generator comprehension:
result += next('%s '%(e) if e else '' for e in (<complexExpressionForGettingX>,))
You could define a conditional formatting function once, and use it repeatedly:
def cond_format(expr, form, alt):
if expr:
return form % expr
else:
return alt
Usage:
result += cond_format(<costly_expression>, '%s ', '')
After hearing the responses (thanks guys!) I'm now convinced there's no way to achieve what I want in Python without defining a new function (or lambda function) since that's the only way to introduce a new scope.
For best clarity I decided this needed to be implemented as a reusable function (not lambda) so for the benefit of others, I thought I'd share the function I finally came up with - which is flexible enough to cope with multiple additional format string arguments (in addition to the main argument used to decide whether it's to do the formatting at all); it also comes with pythondoc to show correctness and illustrate usage (if you're not sure how the **kwargs thing works just ignore it, it's just an implementation detail and was the only way I could see to implement an optional defaultValue= kwarg following the variable list of format string arguments).
def condFormat(formatIfTrue, expr, *otherFormatArgs, **kwargs):
""" Helper for creating returning the result of string.format() on a
specified expression if the expressions's bool(expr) is True
(i.e. it's not None, an empty list or an empty string or the number zero),
or return a default string (typically '') if not.
For more complicated cases where the operation on expr is more complicated
than a format string, or where a different condition is required, use:
(lambda e=myexpr: '' if not e else '%s ' % e)
formatIfTrue -- a format string suitable for use with string.format(), e.g.
"{}, {}" or "{1}, {0:d}".
expr -- the expression to evaluate. May be of any type.
defaultValue -- set this keyword arg to override
>>> 'x' + condFormat(', {}.', 'foobar')
'x, foobar.'
>>> 'x' + condFormat(', {}.', [])
'x'
>>> condFormat('{}; {}', 123, 456, defaultValue=None)
'123; 456'
>>> condFormat('{0:,d}; {2:d}; {1:d}', 12345, 678, 9, defaultValue=None)
'12,345; 9; 678'
>>> condFormat('{}; {}; {}', 0, 678, 9, defaultValue=None) == None
True
"""
defaultValue = kwargs.pop('defaultValue','')
assert not kwargs, 'unexpected kwargs: %s'%kwargs
if not bool(expr): return defaultValue
if otherFormatArgs:
return formatIfTrue.format( *((expr,)+otherFormatArgs) )
else:
return formatIfTrue.format(expr)
Presumably, you want to do this repeatedly to build up a string. With a more global view, you might find that filter (or itertools.ifilter) does what you want to the collection of values.
You'll wind up with something like this:
' '.join(map(str, filter(None, <iterable of <complexExpressionForGettingX>>)))
Using None as the first argument for filter indicates to accept any true value. As a concrete example with a simple expression:
>>> ' '.join(map(str, filter(None, range(-3, 3))))
'-3 -2 -1 1 2'
Depending on how you're calculating the values, it may be that an equivalent list or generator comprehension would be more readable.