-1

I have the following code that attempts to run a lambda function with a string that contains a condition. Problem is that I get an error when running the function.

df = pd.DataFrame({
    'height':  [1, 2, 3, 4, 5],
    'weight': [10, 20, 30, 40, 50]
})

s = "if obj.height > 2: \
        obj.weight \
     else: \
        obj.weight * 2"

df['new_status'] = df.apply(lambda obj: eval(s), axis=1)

the error is

if obj.height > 2:         obj.weight      else:         obj.weight * 2
    ^ SyntaxError: invalid syntax

How to fix this to make it work?

Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
ps0604
  • 1,227
  • 23
  • 133
  • 330

5 Answers5

2

First of all, you can use triple quotes to make a multiline string:

s = """
if obj.height > 2:
    obj.weight
else:
    obj.weight * 2
"""

Otherwise, you have one line which does not follow python syntax indeed. That should fix your SyntaxError but wouldn't work as you expect it to work.

Second of all and very important one, try avoiding using eval. You can define a function and pass it to .apply:

df = pd.DataFrame({
    'height':  [1, 2, 3, 4, 5],
    'weight': [10, 20, 30, 40, 50]
})

def process(obj):
    if obj.height > 2:
        return obj.weight
    else:
        return obj.weight * 2

df['new_status'] = df.apply(process, axis=1)
Yevhen Kuzmovych
  • 10,940
  • 7
  • 28
  • 48
  • I need to use `eval`. When I tried with triple quotes I got the same syntax error. – ps0604 Jul 20 '21 at 15:15
  • Just to check. Why? – Yevhen Kuzmovych Jul 20 '21 at 15:29
  • I need the user to enter a condition. the user is an internal employee that has a user and a password. I also whitelist the web access and I register in an audit trail the condition that is entered. Lastly, I filter the use of keywords such as import – ps0604 Jul 20 '21 at 15:30
2

If for some reason you want just the eval(s) to work, you can define it as below:

 s="obj.weight  if obj.weight > 2 else obj.weight * 2"

But this will not work as expected in your apply function. You must use a pure function instead

IoaTzimas
  • 10,538
  • 2
  • 13
  • 30
1

This should work if you use triple quotes instead of double quotes around the code.

Is there any reason you are using eval, though? eval is almost never the answer to your problem, and in this case it can easily be ommitted:

df = pd.DataFrame({
    'height':  [1, 2, 3, 4, 5],
    'weight': [10, 20, 30, 40, 50]
})

def condition(obj):
   if obj.height > 2:
       return obj.weight
   else:
       return obj.weight * 2

df['new_status'] = df.apply(condition, axis=1)
Peter
  • 171
  • 5
1

Maybe, this is the syntax you're looking for:

df['new_status'] = df.apply(lambda obj : obj.weight if obj.height > 2 else obj.weight * 2 , axis=1)

output:

Out[7]: 
   height  weight  new_status
0       1      10          20
1       2      20          40
2       3      30          30
3       4      40          40
4       5      50          50
BlackMath
  • 1,708
  • 1
  • 11
  • 14
0

For a simple if else, you can change the way you write the condition to:

s = "obj['weight'] if obj['height'] > 2 else obj['weight'] * 2"

df['new_status'] = df.apply(lambda obj: eval(s), axis=1)
GeoMonkey
  • 1,615
  • 7
  • 28
  • 56
Xena
  • 1
  • 1