The desire is for the user to instantiate a class that represents the transeint along with automatic access to a member item for each variable being represented (up to 200 variables). The set of variable class instances would be dynamic based on file based input data and the desire is to use the file provided variable names to create a collection of these variable instances that are accessible with a natural naming scheme. Effectively, the variable class hides the details of where the data is stored and the indepedent variable (ie, time) is stored. The following pseudo code expresses random lines that the end user may express. In some cases, the post processing may be much more extensive.
tran1 = CTransient('TranData', ...)
Padj = tran1.pressPipe1 + 10 # add 10 bar to a pressure for conservatism
Tsat = TsatRoutine( tran1.tempPipe1 )
MyPlotRoutine( tran1.tempPipe1, tran1.tempPipe2 )
where pressPipeX and tempPipeX names defined in the input data files and the corresponding numpy data vectors are specified in the 'TranData' file input file and are instances of a CVariable class.
Help on how to dynamically build the set of instances that represent the transient variables such that they can be accessed would be appreciated.
Your description of what you're trying to do isn't entirely clear, but automatically naming variables something1, something2, etc. are generally a bad idea. Use a list instead:
transientvariables = []
transientvariables.append(makenewtransientvariable())
# ...
for tv in transientvariables:
print tv
Edit: OK, I think I see what you're getting at, although your explanation still isn't exactly easy to read. You have a collection of pipes, with a time series of temperature and pressure recorded for each one, right?
The easiest way would be to use a dictionary:
transients["tempPipe1"]
Or nested dictionaries:
transients["temp"]["Pipe1"]
Or you could override your class' __getattr__ method, so that it looks in a dictionary, and you can do:
transients.tempPipe1
Edit 2: Overriding __getattr__ would look a bit like this:
def __getattr__(self, name):
if name in self.varMap:
return self.varMap[name]
raise AttributeError
Related
I am trying to write a testing program for a python program that takes data, does calculations on it, then puts the output in a class instance object. This object contains several other objects, each with their own attributes. I'm trying to access all the attributes and sub-attributes dynamically with a one size fits all solution, corresponding to elements in a dictionary I wrote to cycle through and get all those attributes for printing onto a test output file.
Edit: this may not be clear from the above but I have a list of the attributes I want, so using something to actually get those attributes is not a problem, although I'm aware python has methods that accomplish this. What I need to do is to be able to get all of those attributes with the same function call, regardless of whether they are top level object attributes or attributes of object attributes.
Python is having some trouble with this - first I tried doing something like this:
for string in attr_dictionary:
...
outputFile.print(outputclass.string)
...
But Python did not like this, and returned an AttributeError
After checking SE, I learned that this is a supposed solution:
for string in attr_dictionary:
...
outputFile.print(getattr(outputclass, string))
...
The only problem is - I want to dynamically access the attributes of objects that are attributes of outputclass. So ideally it would be something like outputclass.objectAttribute.attribute, but this does not work in python. When I use getattr(outputclass, objectAttribute.string), python returns an AttributeError
Any good solution here?
One thing I have thought of trying is creating methods to return those sub-attributes, something like:
class outputObject:
...
def attributeIWant(self,...):
return self.subObject.attributeIWant
...
Even then, it seems like getattr() will return an error because attributeIWant() is supposed to be a function call, it's not actually an attribute. I'm not certain that this is even within the capabilities of Python to make this happen.
Thank you in advance for reading and/or responding, if anyone is familiar with a way to do this it would save me a bunch of refactoring or additional code.
edit: Additional Clarification
The class for example is outputData, and inside that class you could have and instance of the class furtherData, which has the attribute dataIWant:
class outputData:
example: furtherData
example = furtherData()
example.dataIWant = someData
...
with the python getattr I can't access both attributes directly in outputData and attributes of example unless I use separate calls, the attribute of example needs two calls to getattr.
Edit2: I have found a solution I think works for this, see below
I was able to figure this out - I just wrote a quick function that splits the attribute string (for example outputObj.subObj.propertyIWant) then proceeds down the resultant array, calling getattr on each subobject until it reaches the end of the array and returns the actual attribute.
Code:
def obtainAttribute(sample, attributeString: str):
baseObj = sample
attrArray = attributeString.split(".")
for string in attrArray:
if(attrArray.index(string) == (len(attrArray) - 1)):
return getattr(baseObj,string)
else:
baseObj = getattr(baseObj,string)
return "failed"
sample is the object and attributeString is, for example object.subObject.attributeYouWant
I am using python 3.7. I am running some analysis on the RSSI values obtained from wireshark and therefore need to plot the various RSSI values with respect to a channel.
I have created the following classes to hold different attributes such as mean(list), median, mode, std dev etc.
While parsing through the individual data files I plan to go about and collect the data in the above lists for each channel.
To be able to plot these values I need to pass the attributes as a list to the plot function. I am having trouble designing/defining the data structures.
ch_rssiattr_list = collections.defaultdict(lambda : collections.defaultdict(list))
ch_rssiattr_list[channel]['mean'].append(mean)
The above method would be acceptable - not a class instantiation method.
A more elegant way I could think was creating a class with the various attributes as I was explaining above as I am parsing the data through various distances.
In C++ I would create a map with the key as a channel and value as a class object.
As I am parsing through the data. I almost need a way to update the values in the following way.
ch_rssiattr_list[channel].mean_list.append(mean)
I do not know how to declare this data structure.
Any other design/ implementation methods are welcome as well but the above two ways seem simple enough to me so the right way to declare data structures here would be helpful to know. Hopefully I explained my question well enough, a google search on nested dictionaries and lists did not exactly give me what I was looking for although I do understand how nested dictionaries and lists can be declared, but in general how would you declare them for your custom class seems a bit confusing to me.
Here is what my custom class looks like.
class summary_lists(object):
def __init__(self,dist_list, mean_list, median_list, mode_list,
std_dev_list, mmode_list, unique_count_list, total_datapoint_list,
min_list, max_list):
self.dist_list = dist_list
self.mean_list = mean_list
self.mode_list = mode_list
self.median_list = median_list
self.std_dev_list = std_dev_list
self.mmode_list = mmode_list
self.unique_count_list = unique_count_list
self.total_datapoint_list = total_datapoint_list
self.min_list = min_list
To provide a bit of context, I am building a risk model that pulls data from various different sources. Initially I wrote the model as a single function that when executed read in the different data sources as pandas.DataFrame objects and used those objects when necessary. As the model grew in complexity, it quickly became unreadable and I found myself copy an pasting blocks of code often.
To cleanup the code I decided to make a class that when initialized reads, cleans and parses the data. Initialization takes about a minute to run and builds my model in its entirety.
The class also has some additional functionality. There is a generate_email method that sends an email with details about high risk factors and another method append_history that point-in-times the risk model and saves it so I can run time comparisons.
The thing about these two additional methods is that I cannot imagine a scenario where I would call them without first re-calibrating my risk model. So I have considered calling them in init() like my other methods. I haven't only because I am trying to justify having a class in the first place.
I am consulting this community because my project structure feels clunky and awkward. I am inclined to believe that I should not be using a class at all. Is it frowned upon to create classes merely for the purpose of organization? Also, is it bad practice to call instance methods (that take upwards of a minute to run) within init()?
Ultimately, I am looking for reassurance or a better code structure. Any help would be greatly appreciated.
Here is some pseudo code showing my project structure:
class RiskModel:
def __init__(self, data_path_a, data_path_b):
self.data_path_a = data_path_a
self.data_path_b = data_path_b
self.historical_data = None
self.raw_data = None
self.lookup_table = None
self._read_in_data()
self.risk_breakdown = None
self._generate_risk_breakdown()
self.risk_summary = None
self.generate_risk_summary()
def _read_in_data(self):
# read in a .csv
self.historical_data = pd.read_csv(self.data_path_a)
# read an excel file containing many sheets into an ordered dictionary
self.raw_data = pd.read_excel(self.data_path_b, sheet_name=None)
# store a specific sheet from the excel file that is used by most of
# my class's methods
self.lookup_table = self.raw_data["Lookup"]
def _generate_risk_breakdown(self):
'''
A function that creates a DataFrame from self.historical_data,
self.raw_data, and self.lookup_table and stores it in
self.risk_breakdown
'''
self.risk_breakdown = some_dataframe
def _generate_risk_summary(self):
'''
A function that creates a DataFrame from self.lookup_table and
self.risk_breakdown and stores it in self.risk_summary
'''
self.risk_summary = some_dataframe
def generate_email(self, recipient):
'''
A function that sends an email with details about high risk factors
'''
if __name__ == "__main__":
risk_model = RiskModel(data_path_a, data_path_b)
risk_model.generate_email(recipient#generic.com)
In my opinion it is a good way to organize your project, especially since you mentioned the high rate of re-usability of parts of the code.
One thing though, I wouldn't put the _read_in_data, _generate_risk_breakdown and _generate_risk_summary methods inside __init__, but instead let the user call this methods after initializing the RiskModel class instance.
This way the user would be able to read in data from a different path or only to generate the risk breakdown or summary, without reading in the data once again.
Something like this:
my_risk_model = RiskModel()
my_risk_model.read_in_data(path_a, path_b)
my_risk_model.generate_risk_breakdown(parameters)
my_risk_model.generate_risk_summary(other_parameters)
If there is an issue of user calling these methods in an order which would break the logical chain, you could throw an exception if generate_risk_breakdown or generate_risk_summary are called before read_in_data. Of course you could only move the generate... methods out, leaving the data import inside __init__.
To advocate more on exposing the generate... methods out of __init__, consider a case scenario, where you would like to generate multiple risk summaries, changing various parameters. It would make sense, not to create the RiskModel every time and read the same data, but instead change the input to generate_risk_summary method:
my_risk_model = RiskModel()
my_risk_model.read_in_data(path_a, path_b)
for parameter in [50, 60, 80]:
my_risk_model.generate_risk_summary(parameter)
my_risk_model.generate_email('test#gmail.com')
How do I use text from a file as a variable name?
I am pulling values out of an excel file.
I am using xlrd and xlutils with python 3.
class employee(object):
def __init__(self, name):
self.name = name
emp_list.append(name)
def bulk_hours(self,sunday=0,monday=0,tuesday=0,wednesday=0,thursday=0,friday=0,saturday=0):
self.sunday = sunday
self.monday = monday
self.tuesday = tuesday
self.wednesday = wednesday
self.thursday = thursday
self.friday = friday
self.saturday = saturday
I'm pulling employees out of a spreadsheet.
I'm trying to use their actual names.
I would love to know any working solution.
Thanks!
Edit: Pardon my ignorance regarding programming and my horrible post.
I'm trying to make a simple program that allows me to load an employees name and work schedule from Excel.
I will also make sure any edits are saved back into the spreadsheet.
The employees are labeled by their names. I'm trying to load their name as a variable so I can do:
John = employee('John')
John.bulk_hours(0,8,8,8,8,8,0)
Stacy = employee('Stacy')
print(John.monday)
I'm aiming to use their name as the variable I can use dot notation on.
Is this feasible? Is their some other way I should approach this?
def load(row):
employee2 = employee(s.cell(row, 0).value)
employee2.bulk_hours(s.cell(row, 1).value, s.cell(row, 2).value, s.cell(row, 3).value, s.cell(row, 4).value,
s.cell(row, 5).value, s.cell(row, 6).value, s.cell(row, 7).value)
print(employee2.saturday)
I'm trying to use a function like this to load multiple employees and their hours.
Could I use a list like this somehow?
worker = ['Joe']
worker[0] = employee('Joe')
worker[0].bulk_hours(0,8,8,8,8,8,0)
print(worker[0].monday)
Thank you for your valuable time.
Override __getattr__ to transparently access an internal dictionary.
class employee(object):
def __init__(self, ...):
self._internal_d = extract_data() # replace extract_data with however you extract CSV values to a dictionary
... # perform other initialization
def __getattr__(self, name):
try:
return self._internal_d[name]
except KeyError:
raise AttributeError()
Optionally, you can implement __setattr__ to allow writing properties.
def __setattr__(self, name, value):
return self._internal_d[name] = value
Explanation: when python does variable assignment and can't find a variable name "normally", it checks if an object has __getattr__. If it does, it calls __getattr__ to get the value with the specified name. Thus, you can have dynamic variable names. Likewise for __setattr__.
You don't want to use variable names comming from the spreadsheet.
or one: variable names are internal to the running program, and are not meant to be exported again to an output file.
It is meaningless that the variable is bamed John to represent John's data when the program is running. For example, let's suppose it would be possible to create a special markup to use teh variable name - say a ? prefix to fetch the name from another variable. Your example would be something like this:
def row_data(emp_name, *args):
?emp_name = employee(emp_name)
?emp_name.bulk_hours(*args)
print(?emp_name.monday)
So, even if at runtime ?emp_name would be exchanged by the contents of the variable name, yur program would still look the same to someone reading the code. So, it makes more sense to simply let the variable be named person or employee or anything, since it can represent any employee (and in fact will, as you loop through the spreadsheet contents, usually the variable will carry the data about one person a time).
That said, there are times when we do want to have data in the program which do have programmatic labeling. but still on those cases - that is what dictionaries are for - create an employees dict, and fill it - and then you can have the names as the keys:
employees = dict()
def row_data(emp_name, name):
person = employee(emp_name)
person.bulk_hours(*args)
employes[emp_name] = person
def print_employeers():
for person_name, person_data in employees.items():
print(person_name, person_data)
As you can see, it is possible to print all employees data without having to type in their names. Also, if it is an interactive program, it is possible to find the data related to a name that is input by the user, using it as the dictionary key.
However if you intend to have a program to generate other Python source files themselves, and end-up with a .py file for each employee. In that case just make use of a templating engine, like Jinja2, or simply use str's format method. (It still hard to imagine why you would need such a thing).
And, just to have a complete answer, it is possible to create dynamic variable names in Python. However, you will be in the exact same situation I described in the first example here.
Global variables for any running code are kept in a regular Python dictionary, which is returned by a call to the globals() function. And similarly, values for local variables are kept in a dictionary that returned by a call to locals() - although these do not behave nicely for variables known at compile time (in that case, the local variables are cached in the frame object, and the locals dict is only synchornized with them when it is read, but they can't be written via locals)
So:
def row_data(emp_name, *args):
globals()[emp_name] = employee(emp_name)
globals()[emp_name].bulk_hours(*args)
print(globals()[emp_name].monday)
will work just as you asked - but it is easy to see it is useless.
I have a function named getTicket which take two argument id which is a number and format (string)
def getTicket(id, format):
if format == "pdf":
getTicketPDF(id) #some specialized pdf method gets called
elif format == "json":
getTicketJSON(id) #specialized json method
Now if I have to support some new format like "html" then I can create another elif for html.
But I want to generalize this code so that if in future n new method gets added I do not have to change my code
How can I design my getTicket api?
You can create a dictionary that stores the format to function mapping , like "pdf" mapping to function getTicketPDF , etc. And then in your getTicket() function you call the dictionary's value for format and call it by passing id parameter to it. Example -
funcdict = {"pdf":getTicketPDF
"json":getTicketJSON}
def getTicket(id, format):
try:
funcdict[format](id)
except KeyError:
#Handle case where format is not found in dictionary
If later you decide to add a new function for a new format, you just need to add a new mapping to the dictionary.
Your use case calls for a Strategy Pattern Implementation(PDF/JSON/HTML ticket generation strategies) which uses a Factory Pattern to obtain the correct strategy implementation class.
Here are the high-level steps -
Separate the functionality of ticket generation into a class TicketGenerator. Let this be an interface. It will have a single abstract method generateTicket()
Use a TicketGeneratorFactory to get the correct TicketGenerator instance based on the type of ticket i.e. an instance of PDFTicketGenerator, JSONTicketGenerator, HTMLTicketGenerator and so on... Each of these implemention classes have a generateTicket() implementation as per the type i.e. PDF/JSON/HTML.
This instance should be assigned to the base TicketGenerator Type.
TicketGenerator.generateTicket() would then give you the ticket in the desired format - PDF/JSON/HTML.