Use eval function with 'mean()' and 'median()' - python

I want to calculate mean and median from of a dataframe so I put them in a list as follows:
comb_methods = ['median','mean']
I use a loop and use eval function to make the functions callable, and calculate the result and add it as a new column to the dataframe
for combin in comb_methods:
combination = eval(combin)
heartdata[combin] = heartdata.combination(axis=1)
I get the following error.
name 'median' is not defined
I'm trying to understand why this is occurring for hours but I can't figure it out!

You need to use getattr instead of eval:
for combin in comb_methods:
heartdata[combin] = getattr(heartdata, combin)(axis=1)
getattr looks for the attribute of a given object with a name as a string. Writing
getattr(heartdata, 'median')
returns heartdata.median (a method which we then call with the axis=1 argument).
eval on the other hand simply evaluates whatever string you pass onto it. So
eval('median')
is the same as simply typing median (without quotes) on a Python script. Python will believe that median is a variable, and will throw the error you see when it can't find said variable.

Related

How can I use Python's exec() and eval() to execute arbitrary code AND return a value afterwards?

I'm looking for a function that will let me execute code passed as a string, but also return a value upon completion. I have found Python's exec and eval, each of which manage to do a part of what I want:
exec lets me execute some lines of code which I pass as a string: print to the console; set or change variables; write to files etc.
eval lets me evaluate a single expression and returns the value of this expression.
However, the functionality I want is to combine these: with a single function call, I want to execute some arbitrary code, and then return a value, which might be dependent on the code executed.
To contextualise, I want to modify the in-built Pickle __reduce__ method so that I can execute some code in the background while the object un-pickles. However, at the end of that code execution, I still want to return the original object that was pickled.
Pickle's __reduce__ has to return a function which is used to reassemble the object on un-pickling, so I want a use of eval and exec that lets me combine their usage into a single function call.
As an example, my code might look something like this:
def __reduce__(self):
code = """with open("flag.txt", "w") as f:\n\tf.write("A flag I have left!")\ndict()"""
return exec, (code, ), None, None, iter(self.items())
The odd return formatting is a quirk of Pickle. The oddly formatted code string should do this:
with open("flag.txt", "w") as f:
f.write("A flag I have left")
dict() # I'm trying to get the intepreter to 'evaluate' this final line
However, this doesn't work, as exec just does nothing with this final line, and returns None. If I swap, and use eval instead, then I get an error too, as eval can't do anything with the lines above.
I ave tried using the in-built compile method, but this doesn't actually seem to help because eval still won't evaluate compiled execution code.
I also see that this problem has popped up elsewhere on SO (here and here) but I'm unsatisfied with the answers provided, because they involve defining new functions, which are then useless in the context of getting Pickle to execute them on un-pickling, where the interpreter is naive of their definition.
Is there any way to neatly combine these expressions to achieve arbitrary execution as well as returning a value?
The best solution I could find to this problem is one based on some code from Yannic Kilcher.
You can combine the functions like this:
eval("exec(exec_code) or to_return")
eval will always try to return the value of the expression you have passed. If you pass a conditional expression, like the one above, then it will try and evaluate each part in turn to find the value of the whole conditional. As such, it will run your exec code, achieving what you need there, and then, finding that it evaluates to None, will return whatever the value of to_return is, because of the or. Therefore, if you make to_return your dictionary object constructor, then your code will run the exec statement first upon un-pickling, and then return a dictionary object as intended.

Using a Variable in a .query function

I'm trying to create a function that takes the input name of a value in a column and that value will then be used in a df.query function. However, I cannot figure out how to make it a variable that it recognizes as the input.
This is what I have right now:
def gettingWeeks(stateAbbr, stateName):
stateCases = cases.query('state == stateName')
But it does not recognize stateName. Is there a way to do this?
Thanks!
Pandas DataFrame.query method expects an expression string created accordingly to its specific syntax. To use variables from the current name space you have to use # symbol before the name of the variable:
stateCases = cases.query("state == #stateName")
Should work fine.
Here is the doc.

Python 3.7 Variable Chained Method Calls

I've run into a similar problem as referenced here - Dynamic Method Call In Python 2.7 using strings of method names
Here's an example of what my working method call looks like, the method at the end is based on a given data type, in this case .string_value:
tag.fields[field["key"]].string_value = field["value"]
However I won't always be assigning just strings as there are methods for other data types. I attempted a solution similar to the one referenced in the linked thread:
typer = getattr(datacatalog_v1.types.TagField, f"{field['type']}_value")
tag.fields[field["key"]].typer = field["value"]
With typer being my new dynamic method call, but it's not working. I'm receiving this as an error - 'TagField' object has no attribute 'typer'.
Any suggestions?
This is quite interesting. I'm not sure what package/datatype ur working on, however it looks like you have 2 issues.
First, getattr returns a string, and you can't call a string, e.g. 'python'()
Second, if you remove the () after getattr(), typer will be a string data, and you cant use it like that. In
tag.fields[field["key"]].typer
typer must be a method/attribute of some sort rather than string. The best way is to build if statement or dict, combine different value of typer with different method/attribute calls.
type_methods = {'string_value': tag.fields[field["key"]].string_value,
'int_value': tag.fields[field["key"]].int_value,
'json_value': tag.fields[field["key"]].json_value}
typer = getattr(datacatalog_v1.types.TagField, f"{field['type']}_value")
type_method[type] = field["value"]
update:
There is a setattr(object, name, value) function
typer = getattr(datacatalog_v1.types.TagField, f"{field['type']}_value")
setattr(tag.fields[field['key']], typer, field['value'])

Calling a function in Pycharm

I am new in Python and I am currently learning OOP in Pycharm.
When I type in a simple function like type(mylist), I dont see the answer in the console, I have to add print in the beginning, same with any other function, although in the tutorials I am currently following, they just call the function by typing its name and adding a parameter.
Same with my first attribute (please see screenshots)
Please help me if you know how to get around it.
You need to separate the object instantiation from the print()
my_dog = Dog(mybreed='lab')
print(my_dog)
Instead of:
print(my_dog=Dog(mybreed='lab'))
You could either split it to two lines:
my_dog = Dog(mybreed='lab')
print(my_dog)
Or, if you don't need the my_dog variable:
print(Dog(mybreed='lab'))
In python variable_name = expression can't be regarded as expression to be used as parameter, so print(my_dog=Dog(mybreed='lab')) will raise an error.
You can sure finish your job by this way:
my_dog = Dog(mybreed='lab') # assign the variable my_dog
print(my_dog) # print the variable my_dog
If you don't need variable my_dog, you can just use print(Dog(mybreed='lab')), which will surely work.
If you do prefer assign a variable and pass it as a parameter (just like C++ does), you can use Assignment Expressions(also The Walrus Operator) := in Python 3.8 or higher version:
print(my_dog:=Dog(mybreed='lab'))
But just keep it in mind that this operator maybe not as convenient as you think!

Rename built-in python methods like replace()

I am writing a python script that uses the string.replace() method a lot. I know that if I was importing a python method from a module I could change its name using from like so:
from time import sleep as x
And then, x(5) would be the same as time.sleep(5). But how can I do that to the replace() function? It isn't from any external module, and I have tried to do this:
x = replace()
But it doesn't work. It says NameError: name 'replace' is not defined.
So please tell me how to "rename" the built-in replace function.
First, you should almost never be using string.replace. As the docs say:
The following list of functions are also defined as methods of string and Unicode objects; see section String Methods for more information on those. You should consider these functions as deprecated…
Second, this is wrong for two separate reasons:
x = replace()
First, there is no builtin named replace, and there's no global in your module named replace either. If you did from string import * or from string import replace, then you wouldn't get this error—but if you were doing that, you could just do from string import replace as x, exactly as you're already doing for time.sleep.
Second, those parentheses mean that you're calling the function, and assigning its return value to x, not using the function itself as a value.
So, I think what you want is this:
x = str.replace
That's accessing the replace method on str objects, and storing it in x. An "unbound method" like this can be called by passing an instance of str (that is, any normal string) as the first argument. So:
x(my_string, ' ', '_')
If you want to add the name x as a method on the str class itself, what you want is called "monkeypatching", and normally, it's very simple:
str.x = str.replace
Unfortunately, it doesn't work with most of the built-in types, at least in CPython; you'll get an error like this:
TypeError: can't set attributes of built-in/extension type 'str'
You could of course create your own subclass of str, and use that all over the place instead of str… but that won't help with string literals, strings you get back from other functions, etc., unless you wrap them explicitly. And I'm not sure it's worth the effort. But if you want to:
class s(str):
x = str.replace
Now you can do this:
z = s(function_returning_a_string())
z = z.x(' ', '_')
But notice that at the end, z is back to being a str rather than an s, so if you want to keep using x, you have to do this:
z = s(z.x(' ', '_'))
… and at a certain point, even if you're saving a few keystrokes, you're not saving nearly enough for the cost in readabiity and idiomaticitalnessity.
You can sort of do what you want:
a = 'asdf'
a_replace = a.replace
Now a_replace is a bound method object that does a.replace(whatever) when you call a_replace(whatever). You can also do
my_replace = str.replace
my_replace('asdf', 'a', 'f') # calls 'asdf'.replace('a', 'f')
However, what you probably want is
some_magic()
'asdf'.my_replace('a', 'f') # calls 'asdf'.replace('a', 'f')
and that's not possible without messing with things you're really not supposed to mess with:
# Awful hack. Last resort only.
import gc
for referrer in gc.get_referrers(str.replace):
if type(referrer) is dict and str.__dict__ in gc.get_referrers(referrer):
# Almost certainly the dict behind str's dictproxy.
referrer['my_replace'] = str.replace
break
This is absolutely NOT advisable to do in any of your projects. But this is possible:
We could do some metahacking - replacing the builtin str with our custom one
class myStr(str):
def def my_replace(self, __old, __new, __count):
return self.replace(__old, __new, __count)
__builtins__.__dict__['str'] = myStr
Now the all usages of str are replaced with our implementation. You can add or change whatever you want. In our case both replace methods will work, one inherited from str and one created by us:
print('dsadas'.replace('d', '_'))
>>> _sa_as
print('dsadas'.my_replace('d', '_'))
>>> _sa_as
But remember this is fun, but using those technics in real project could ruin a lot of other functionality.

Categories