How do I call a function within my class? - python

I'm trying to practice classes in python by trying to make a class which normalizes the currency to all GBP using an exchnage rate table. I'm not sure why i'm getting the below error. CurrencyCombo is a column name in the exchnagerate table which i pass into init as 'CurrencyPairCol'
rateList = ['EURGBP','USDGBP', 'SEKGBP']
Month = ['2018-11', '2018-12', '2019-01', '2019-02', '2019-03']
class CurrencyNormalize():
def __init__(self,filename,rateList,monthList,orders_filename,CurrencyPair):
self.ExchangeRate = pd.read_csv(filename)
self.OrdersTrain = pd.read_csv(orders_filename)
self.rateList=rateList
self.monthList=monthList
self.currencyPairCol=self.ExchangeRate[CurrencyPair]
def remove_char(self):
return (self.replace('GBP', ''))
def normalize(self):
ExchangeRateFilt= self.ExchangeRate[self.ExchangeRate.CurrencyCombo.isin(self.rateList)]
monthOnly= ExchangeRateFilt[ExchangeRateFilt.TradeMonth.isin(self.monthList)]
print(monthOnly['CurrencyCombo'])
monthOnly['CurrencyCombo] = monthOnly['CurrencyCombo].apply(self.remove_char())
I want to apply the function remove_char in the normalize function but i'm not sure if i'm doing it wrong. WHen i run the above as follows:
CurrencyNormalize('MonthlyExchangeRates.csv',rateList,Month,'Orderss.csv','CurrencyCombo').normalize()
I get the following error:
AttributeError: 'CurrencyNormalize' object has no attribute 'replace'
I think the error has something to do with how i appply the remove_char function, before i tried the OOP way the function was:
def remove_char(col):#
return (col.replace('GBP', ''))
and i would call it as :
ExchangeRate['CurrencyCombo'].apply(remove_char)
where Exchange rate is the df. How do i generalilse the function remove_char within the class?

self refers to your class. When you call self.replace() you are trying to run the method replace (which doesn't exist). What you want to do is something like:
self.ExchangeRate[CurrencyPair].replace('GBP', '')
EDIT: Since you correctly defined the attribute currencyPairCol you can simply call:
self.currencyPairCol.replace('GBP', '')
Clearly, the latter will modify only the attribute currencyPairCol and not the originally imported dataframe ExchangeRate (nor the column CurrencyPair in it)

Related

Python - function calling exec() does not see variable

I have following script that works well on it's own, but once I wrap it all into a function does not return data.
The command changes based on input data structure. This is an example of the command I want to feed into the exec():
cross_data=pd.crosstab(src_data['result'],[src_data['c1'],src_data['c2']],normalize='index')
This is my function I want to wrap the code in and call:
def calcct(file_path='src_data.csv', separator = ",", res_col = 'result'):
#define function
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
# create command based on headers and execute that. Should return dataframe called cross_data.
exec(crosstabcmd(head_list))
return cross_data
Results in:
NameError: name 'cross_data' is not defined
I cannot seem to find the correct syntax for calling exec inside a function.
I tried defining and passing the cross_data variable, but I just get an error it doesnt see pandas when I do that.
Or is there some better way? I need to compose the command of 2-x column names, count and names of columns are variable.
First up
You probably don't mean to be using exec - that's a pretty low-level functionality! There isn't really enough context to understand how to fix this yet. Could you write out (in your question) what the crosstabcmd function looks like?
The error
NameError: name 'cross_data' is not defined
is because you've never defined a variable called cross_data in the scope of function calcct, i.e. you have never done cross_data = "something".
I'll give it a go
Assuming you have something like
import pandas as pd
def crosstabcmd(head_list):
# ? I can only guess what your crosstabcmd does, this won't work though
return pd.crosstab(*head_list, normalize='index')
then the solution would look like:
def calcct(file_path = 'src_data.csv', separator = ",", res_col = 'result'):
src_data = csv_import(file_path, separator) #import data
reorder_cols = reorder_columns(src_data, res_col) #work with data
head_list=list(reorder_cols.columns.values) #get dataframe headers
cross_data = crosstabcmd(head_list)
return cross_data
In my case I had main script which called a second script. I needed to use the "c" variable within the second script. Therefore I used locals(),loc as arguments for exec().
loc = {}
a = 10
b = 5
def abc(a,b):
qwerty = "c = %d + %d"%(a,b)
exec(qwerty, locals(), loc)
c = loc['c']
d = c+2
print(d)
abc(a,b)

Call many python functions from a module by looping through a list of function names and making them variables

I have three similar functions in tld_list.py. I am working out of mainBase.py file.
I am trying to create a variable string which will call the appropriate function by looping through the list of all functions. My code reads from a list of function names, iterates through the list and running the function on each iteration. Each function returns 10 pieces of information from separate websites
I have tried 2 variations annotated as Option A and Option B below
# This is mainBase.py
import tld_list # I use this in conjunction with Option A
from tld_list import * # I use this with Option B
functionList = ["functionA", "functionB", "functionC"]
tldIterator = 0
while tldIterator < len(functionList):
# This will determine which function is called first
# In the first case, the function is functionA
currentFunction = str(functionList[tldIterator])
Option A
currentFunction = "tld_list." + currentFunction
websiteName = currentFunction(x, y)
print(websiteName[1]
print(websiteName[2]
...
print(websiteName[10]
Option B
websiteName = currentFunction(x, y)
print(websiteName[1]
print(websiteName[2]
...
print(websiteName[10]
Even though it is not seen, I continue to loop through the iteration by ending each loop with tldIterator += 1
Both options fail for the same reason stating TypeError: 'str' object is not callable
I am wondering what I am doing wrong, or if it is even possible to call a function in a loop with a variable
You have the function names but what you really want are the function objects bound to those names in tld_list. Since function names are attributes of the module, getattr does the job. Also, it seems like list iteration rather than keeping track of your own tldIterator index would suffice.
import tld_list
function_names = ["functionA", "functionB", "functionC"]
functions = [getattr(tld_list, name) for name in function_names]
for fctn in functions:
website_name = fctn(x,y)
You can create a dictionary to provide a name to function conversion:
def funcA(...): pass
def funcB(...): pass
def funcC(...): pass
func_find = {"Huey": funcA, "Dewey": funcB, "Louie": FuncC}
Then you can call them, e.g.
result = func_find["Huey"](...)
You should avoid this type of code. Try using if's, or references instead. But you can try:
websiteName = exec('{}(x, y)'.format(currentFunction))

Declaring a pandas series with a user-defined function

I am trying to simplify some code with a function. The intent is to use the function to declare blank series to populate later.
The code currently declares each series on a separate line like this:
series1=pd.Series()
series2=pd.Series()
This approach works well but makes the code lengthy with many series.
I would like to do the following:
Create a list of blank objects to use in the function with the names series1, series2, etc. or with a more descriptive name for each
series_list=[series1,series2]
Declare function
def series(name):
name=pd.Series()
return name
Call function with input
for i in series_list:
series(i)
However, when I try to declare the series_list, it returns the NameError: [variable] is not defined. Is there a way to populate the series_list with empty objects(i.e. no data but with the names series1, series2, ... series1000)?
Here's how you instantiate the Series objects iteratively, then use the generated list to assign to known variables
def assign_series(n):
series_list = []
#series_dict = {}
num_of_series = n
for i in range(num_of_series):
series_list.append(pd.Series())
#or if you want to call them by name
#series_dict['series'+str(i)] = pd.Series()
return series_list
corporate_securities, agency_securities, unrealized_gainloss = assign_series(3)
corporate_securities
Series([], dtype: float64)

Create variable from string in python

I have read a lot of posts about this subject but I haven't found an answer to my problem.
Wants to write a function that allows you to create DF with different names and columns.
So I try this:
def createDT(name,c1,c2,c3):
name = pd.DataFrame(columns = [c1,c2,c3])
print(type(name))
return name
createDT(DT,"col1","col2","col3")
and I receive:
NameError: name 'DT' is not defined
when I change the "name" variable to String I receives the message:
<class 'pandas.core.frame.DataFrame'>
and the table below
Which confirms the creation of DF, but if I want to call the DT variable I get a
NameError: name 'DT' is not defined
I know I can do it this way
DT2 = createDT(DT,"col1","col2","col3")
But then I have to name the variables again and I would like to avoid that and
I want it to be written as a function. Any ideas on how to solve it?
It's not that easy unfortunately:
def createDT(name,c1,c2,c3):
globals()[name] = pd.DataFrame(columns = [c1,c2,c3])
print(type(globals()[name]))
return globals()[name]
createDT("DT","col1","col2","col3")
But a preferred and efficient solution would be:
def createDT(name,c1,c2,c3):
return pd.DataFrame(columns = [c1,c2,c3])
createDT("col1","col2","col3")
Wouldn't simple
def createDT(c1,c2,c3):
temp = pd.DataFrame(columns = [c1,c2,c3])
print(type(temp))
return temp
DT = createDT("col1","col2","col3")
work?
In Python you (almost always) don't use function parameters as return value. And you don't need to worry about copying since in Python everything is (kind of like) pointers.

Why is Float object not callable?

Looking at the code I have below as an example. Why is it I get the error "Float object not callable" when using print statement 1 but not print statement 2? what do I need to do to my class if I was wanting to make print statement 1 work?
var1 = float(input())
class ExampleClass(object):
def __init__(self, thing1):
self.getThing1 = thing1
def getThing1(self):
return self.getThing1
a = ExampleClass(var1)
print(str(a.getThing1())) #print statement 1 that doesn't work
print(str(a.getThing1)) #print statement 2 that does work
You are trying to use getThing1 as a method name and an attribute. You declare a method getThing1, but then you assign self.getThing1 = thing1. So getThing1 isn't a method anymore; it's the value of thing1.
Perhaps you meant this:
class ExampleClass(object):
def __init__(self, thing1):
self.thing1 = thing1
def getThing1(self):
return self.thing1
However, getXXX methods are not the convention in Python. If you need a method wrapping your attribute, you should make it a property.
This:
class ExampleClass(object):
def __init__(self, thing1):
---> self.getThing1 = thing1
shadows this:
def getThing1(self):
return self.getThing1
Python functions are objects don't live in a distinct namepsace, so to make a long story short you cannot have an attribute and a method by the same name.
The solution is simple: don't use getThing1 as an attribute name - specially since "get" is a verb so it's a poor name for a value.
Also note that Python has a string support for computed attributes so you don't need systematic getters/setters for attributes. You can start with a plain attribute and turn it into a computed one later if the need arises.

Categories

Resources