Retaining a variable created during module import in python - python-3.x

I am trying to populate a dictionary with functions along with the name of the function contained in another file of the form:
{'fn_a': function fn_a at 0x000002239BDCB510, 'fn_b': function fn_b at 0x000002239BDCB268}.
I'm currently attempting to do it with a decorator so when the file containing the functions (definitions.py) is imported the dictionary is populated as follows. The problem is that dictionary is cleared once the import is complete.
definitions.py:
from main import formatter
#formatter
def fn_a(arg):
return arg
#formatter
def fn_b(arg):
return arg
main.py:
available_functions = {}
def formatter(func):
# work out function name and write to func_name
func_name=str(func).split()[1]
available_functions[func_name] = func
return func
import definitions
How can I keep the dictionary populated with values after the module import is finished?

I was able to solve the problem using the FunctionType module to return the available functions from the imported module. It doesn't solve the problem within the conditions I specified above, but does work.
from types import FunctionType
available_functions = {}
def formatter(func):
# work out function name and write to func_name
#global available_functions
func_name=str(func).split()[1]
available_functions[func_name] = func
return func
import definitions
funcs=[getattr(definitions, a) for a in dir(definitions)
if isinstance(getattr(definitions, a), FunctionType)]
for i in funcs:
formatter(i)

Related

Unsuccessful in trying to convert a column of strings to integers in Python (hoping to sort)

I am attempting to sort a dataframe by a column called 'GameId', which are currently of type string and when I attempt to sort the result is unexpected. I have tried the following but still return a type string.
TEST['GameId'] = TEST['GameId'].astype(int)
type('GameId')
One way to make the data life easier is using dataclasses!
from dataclasses import dataclass
# here will will be calling the dataclass decorator to send hints for data type!
#dataclass
class Columns:
channel_id : int
frequency_hz : int
power_dBmV : float
name : str
# this class will call the data class to organise the data as data.frequency data.power_dBmV etc
class RadioChannel:
radio_values = ['channel_id', 'frequency', 'power_dBmV']
def __init__(self, data): # self is 'this' but for python, it just means that you mean to reference 'this' or self instance
self.data = data # this instances data is called data here
data = Columns(channel_id=data[0], frequency=data[1], power_dBmv=data[4], name=data[3]) # now we give data var a val!
def present_data(self):
# this is optional class method btw
from rich.console import Console
from rich.table import Table
console = Console()
table = Table(title="My Radio Channels")
for item in self.radio_values:
table.add_column(item)
table.add_row(data.channel_id, data.frequency_hz, data.power_dBmv)
console.print(table)
# ignore this if its confusing
# now inside your functional part of your script
if __name__ == '__main__':
myData = []
# calling an imaginary file here to read
with open("my_radio_data_file", 'r') as myfile:
mylines = myfile.readlines()
for line in myline:
myData.append(line)
myfile.close()
#my data would look like a string ["value", value, 00, 0.0, "hello joe, from: world"]
ch1 = radioChannel(data=myData[0])
ch1.present_data()
This way you can just call the class object on each line of a data file. and print it to see if it lines up. once you get the hang of it, it starts to get fun.
I used rich console here, but it works well with pandas and normal dataframes!
dataclasses help the interpreter find its way with type hints and class structure.
Good Luck and have fun!

Python: Pseudo Enums - Classes as enums - how to avoid cyclic import

I want to create a pseudo enums in my python project.
The values are actually classes.
# file my_enums.py
import MyClass1
import MyClass2
import MyClass3
class MyEnum:
MY_CLASS_1 = MyClass1
MY_CLASS_2 = MyClass2
MY_CLASS_3 = MyClass3
# file my_class1.py
import MyEnum
class MyClass1:
def foo(self, x):
print(isinstance(x, MyEnum.MY_CLASS_2))
Doing this will result in cyclic import error.
I want to be able to use the MyEnum values in isinstance function and to import the enum to modules that define some of those classes.
Is there a way to do so?
Solution:
# file my_enums.py
import MyClass1
import MyClass2
import MyClass3
class MyEnum:
MY_CLASS_1 = None
MY_CLASS_2 = None
MY_CLASS_3 = None
#classmethod
def define(cls):
cls.MY_CLASS_1 = MyClass1
MyEnum.define()
The thing to remember is that when a module is loaded, it is executed -- but only top level statements and the immediate interior of top-level classes; the bodies of functions and methods are not evaluated until they are actually called.
# example module
CONSTANT = 7 # top-level, executed
def a_func(value=CONSTANT): # top-level, executed
return value + 9 # body, not executed
class a_class(metaclass=SomeMeta): # top-level, executed (and error as SomeMeta
# has not been defined nor imported)
CLS_CONSTANT = 3 # top-level class body, executed
def a_method(self): # executed
return self.CLS_CONSTANT + FUTURE_CONSTANT # method body, not executed
FUTURE_CONSTANT = 11
So in your example you need to make sure and not use MyEnum anywhere in my_class1.py that will be executed during import, and put the import of my_enums.py at the very end -- then when my_enums.py is executed during its import it will be able to import my_class1 which will, at that point, have the classes defined.

Retrieving the source code dependencies of a python 3 function

Using the AST in python 3, how do you build a directory or list of code dependencies of a given function?
Consider the following code, where my_clever_function has the desired behaviour:
////// myfile2.py
import numpy as np
a = 1
a += 1
def my_other_function():
def f():
return a
return np.random.randint() + f()
////// myfile1.py
import numpy as np
from . myfile2 import my_other_function
def external(a, b):
return np.sqrt(a * b) + my_other_function
class A:
def afunc(self, a, b):
v = external(a, b)
return v
>>> my_clever_function(A.afunc)
[myfile1.A.afunc, myfile1.external, myfile2.my_other_function, myfile2.a]
with the following structure:
project/
myfile1.py
myfile2.py
I want to retrieve the dependencies of the method afunc as a list.
I'm assuming that there is no funny business about functions altering global variables.
external is a dependency because it is not defined inside A.afunc
np.sqrt is not a "dependency" (in this sense anyway) because it is not defined in my project
likewise for np.random.randint
my_other_function is a dependency because it is not defined inside A.afunc
f is not a dependency because it is inside my_other_function
f needs the global variable a.
My motivation is to see if there have been any code changes between two project versions (in git perhaps).
We could find the dependencies of function like above and store the source.
In the future, we find the dependencies again and see if the source code is different.
We only compare the bits that are required (barring any funny global variables messing inside functions).
It is possible to walk the AST with python's builtin module ast.
So my_clever_function could look like this:
import ast
import dill
class Analyzer(ast.NodeVisitor):
def __init__(self):
self.stats = {...}
...
def report(self):
pprint(self.stats)
def my_clever_function(f):
source = dill.source.getsource(f)
tree = ast.parse(source)
analyser = Analyser()
analyser.visit(tree)
But how do you walk from a given function outwards to its dependencies?
I can see how you can just list symbols (https://www.mattlayman.com/blog/2018/decipher-python-ast/) but how do only list those which depend on the start node?

Calling various function based on input in python 3.x

I'm writing some code to get various data from a class (which extracts data from a '.csv' file). I was wondering if there was a way to call one of these methods based off the name of an input
I've attempted to create a function called get(), which takes in 'param_name' - the name of the method contained within the class that I want to call. I was wondering if there was a more elegant way to solve this without creating a large amount of if statements.
def get(param_name):
# Some initialisation of the .csv file goes here. This works as intended.
list_of_objects = [] # Initialised above, as a list of objects with methods function1(), function2() for getting data out of the .csv
for item in list_of_objects:
if param_name == "name of function 1":
return function1()
if param_name == "name of function 2":
return function2()
You could store your functions ina a dictionary as such:
function_dict = {
'function_1': function_1,
'function_2': function_2
}
To use these you could do:
function_to_use = function_dict.get(param_name)
function_to_use(*args, **kwargs) # *args, **kwargs are arguments to be used.
If you want to return a list after you have applied the function to all item in list_of_objects instead of the for loop you could do:
list(map(function_to_use, list_of_objects))
You could use __getattribute__:
class Alpha:
def f1(self):
print("F1")
x = Alpha()
x.__getattribute__('f1')()
You can do that using globals(), globals() returns a dict containing all methods and attributes.
def fun1():
print('this is fun1')
def fun2():
print('this is fun2')
def get(func_name):
globals()[func_name]()
get('fun1')
get('fun2')
Will Output:
this is fun1
this is fun2

import and rename functions from a folder - Python 3 [duplicate]

I would like to import all methods from a module with altered names.
For instance, instead of
from module import repetitive_methodA as methodA, \
repetitive_Class1 as Class1, \
repetitive_instance4 as instance4
I'd prefer something along the lines of
from module import * as *-without-"repetitive_"
this is a rephrasing of this clumsy unanswered question, I have not been able to find a solution or similar questions yet.
You can do it this way:
import module
import inspect
for (k,v) in inspect.getmembers(module):
if k.startswith('repetitive_'):
globals()[k.partition("_")[2]] = v
Edit in response to the comment "how is this answer intended to be used?"
Suppose module looks like this:
# module
def repetitive_A():
print ("This is repetitive_A")
def repetitive_B():
print ("This is repetitive_B")
Then after running the rename loop, this code:
A()
B()
produces this output:
This is repetitive_A
This is repetitive_B
What I would do, creating a work-around...
Including you have a file named some_file.py in the current directory, which is composed of...
# some_file.py
def rep_a():
return 1
def rep_b():
return 2
def rep_c():
return 3
When you import something, you create an object on which you call methods. These methods are the classes, variables, functions of your file.
In order to get what you want, I thought It'd be a great idea to just add a new object, containing the original functions you wanted to rename. The function redirect_function() takes an object as first parameter, and will iterate through the methods (in short, which are the functions of your file) of this object : it will, then, create another object which will contain the pointer of the function you wanted to rename at first.
tl;dr : this function will create another object which contains the original function, but the original name of the function will also remain.
See example below. :)
def redirect_function(file_import, suffixe = 'rep_'):
# Lists your functions and method of your file import.
objects = dir(file_import)
for index in range(len(objects)):
# If it begins with the suffixe, create another object that contains our original function.
if objects[index][0:len(suffixe)] == suffixe:
func = eval("file_import.{}".format(objects[index]))
setattr(file_import, objects[index][len(suffixe):], func)
if __name__ == '__main__':
import some_file
redirect_function(some_file)
print some_file.rep_a(), some_file.rep_b(), some_file.rep_c()
print some_file.a(), some_file.b(), some_file.c()
This outputs...
1 2 3
1 2 3

Resources