Python 2.7 Is there an equivalent method to locals formatting when adding class attributes into a string? - string

I have a class that has a number of attributes and within that class I have a function that combines those attributes into a string.
The string is quite long so for visual purposes, I would like to see exactly which variable is inserted where. The ideal solution is to use "This is my %(self.var_name)s" %locals() however the solution only works if I redefine my variable first. For example see the example script:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(self.n_apples)s
pears = %(self.n_pears)s
grapefruits = %(self.n_grapefruit)s
""" %locals()
def generate_list_redefine_variables(self):
n_apples = self.n_apples
n_pears = self.n_pears
n_grapefruit = self.n_grapefruit
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %locals()
shopping = Shopping()
# First method
shopping.generate_list_from_self()
# Second method
shopping.generate_list_redefine_variables()
The ideal solution would be to use the generate_from_self() method but the variables are not picked up by %locals(). Instead I am using the second approach and redefining the variables locally before inserting them into the string. This seems cumbersome and I am wondering if there is a better way of achieving this?
It is crucial that I am able to see where the variable is inserted into the string as the string I am working with gets very large.

First the simple approach will be changing the first method to:
def generate_list_from_self(self):
self.shoppingList = """
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
here i used the vars method
in general it's common to use __str__(self) for this approach ( converting your class to string) but since there is an init of self.shoppingList i am not sure this is the right approach for you. but i'll reference you anyway to an implementation of this:
class Shopping(object):
def __init__(self):
self.n_apples = 4
self.n_pears = 5
self.n_grapefruit =7
def __str__(self):
self.shoppingList ="""
My Shopping List
apples = %(n_apples)s
pears = %(n_pears)s
grapefruits = %(n_grapefruit)s
""" %vars(self)
return self.shoppingList
shopping = Shopping()
str(shopping) # calls your class's __str__(self) method
and lastly to generailse this class to contain all shopping needed you can use a dict and return (key, value) pairs so you don't have to define a variable for every product.

Related

Perform operations on values with class attributes

Let's say I've made a simple class
class mercury:
class orbial_characteristics:
apehilion = 69816900
perihilion = 46001200
semi_major_axis = 57909050
eccentricity = 0.205630
orbital_period = 87.9691*86400
orbital_speed = 47.362*1e3
Now, the values given here are in SI units, the value of apehilion for example, is in km. I want to make another class that can convert the value to a given unit, let's say astronomical unit. One method is to pass the value of apehilion directly to that class
change_to_AU(value_of_apehilion)
Which is relatively easy to do. However, what I'm looking for is in the lines of python core operations. Something like this
merc_apehilion_km = mercury.orbital_characteristics.apehilion
merc_apehilion_au = merc_apehilion_km.change_to_AU()
I have recently started working on classes, by reading answers here and web tutorials but I do not get how such an operation can be performed. I even try reading the core files from numpy and pandas as these two libraries that I use most have a number of things that use this notation.
Edit:
A little research led me to this stack overflow page. Take a look at the libraries mentioned in it, make sure they are actively maintained, and consider using them over doing what I demonstrate below
End of Edit
Creating custom methods like this would involve you creating a custom Object for your SI unit values. Here is an example:
class SIUnit:
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
def to_astronimical_units(self):
Calculations which convert apehilion to AU go here
return result
class mercury:
class orbial_characteristics:
apehilion = SIUnit(69816900)
perihilion = SIUnit(46001200)
semi_major_axis = SIUnit(57909050)
eccentricity = SIUnit(0.205630)
orbital_period = SIUnit(87.9691*86400)
orbital_speed = SIUnit(47.362*1e3)
Keep in mind that the to_astronomical_units method would exist for all SI units you use, not just distance so you may want to create a base SIUnit class then have a subclass for each SI Unit, e.g:
class SIUnit:
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
class Kilometer(SIUnit):
def to_au(self):
Calculations which convert apehilion to AU go here
return result
class Ampere(SIUnit):
def to_volts(self, wattage):
return self.value / wattage

Accessing a Single Variable from Another Class (Python)

So, I'm having trouble figuring out how to best structure my Python code. I have a short program using classes, which I've recreated in an example below:
prof1 = Professor()
prof2 = Professor()
professor_list = [prof1, prof2]
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
class Student:
def __init__(self):
self.name = ""
self.activities = []
So basically, I have a list of objects which are instances of the Professor class. Each Professor object also contains a list of Student objects, each of which is an instance of the Student class. I want each Student to also be able to access the course variable from its corresponding Professor (the Professor object with that Student in its list), but I wasn't sure what the neatest way to do this would be.
I considered having Student inherit from Professor, but that seemed sloppy, since I don't actually want to inherit all of the variables and functionality from Professor. For example, Professor's department variable has nothing to do with a Student object, and I don't want Students to have a department attribute. Also, Student isn't a sub-type of Professor, which is what I would associate with inheritance.
I also thought of manually adding the course information to each Student as an attribute, but that didn't seem right either. In the structure I want, the course would be a unique attribute of the Professor, and the various students would be associated with the Professor. All the students that would need to access the course variable are in the Professor's student list - so shouldn't there be a neater way of allowing them to use it than adding it manually to each student?
Here's one more idea: I might include a reference to the corresponding Professor class in each Student, and access the variable that way. Would this be bad practice?
I'd really appreciate any help you can give me with this.
You could go the route of the reference to the Professor, but I think the easiest way would be to create an add_student method which adds the Student to the corresponding Professor's list, as well as marks the course on the Student, so you don't have to do this manually and you can avoid a circular reference (which also is unnecessary because if you're marking the Professor reference on the Student just to get the course attribute, then you may as well just mark the course attribute directly):
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
def add_student(self, student):
self.students.append(student)
student.course = self.course
class Student:
def __init__(self):
self.name = ""
self.activities = []
self.course = None
Alternatively, you could add a method to the Professor which checks if the Student belongs to it and use that to get the course:
prof1 = Professor()
prof2 = Professor()
professor_list = [prof1, prof2]
class Professor:
def __init__(self):
self.name = ""
self.department = ""
self.course = ""
self.students = []
def teaches(self, student):
return student in self.students
class Student:
def __init__(self):
self.name = ""
self.activities = []
def get_course(self, professors):
for professor in professors:
if professor.teaches(self):
return professor.course
return None

How can I make this body of code through a for loop?

So, I'm trying to get this code to work in a cleaner way, mainly, through the use of a for loop, but having a really hard time trying to do so. I haven't been able to make a loop that assigns each value of the dictionary to a correspondent variable, so it can be used in the class. For context, the dictionary contains values obtained from another class, I just put those in the dict and sent it to this class, so I don't need to calculate those again.
def get_ipr_data(self):
self.reservoir_result_dict = ReservoirDataFrame.reservoir_result_dict
self.pb = self.reservoir_result_dict.get("pb")
self.rs = self.reservoir_result_dict.get("rs")
self.bo = self.reservoir_result_dict.get("bo")
self.uo = self.reservoir_result_dict.get("uo")
self.re = self.reservoir_result_dict.get("re")
self.j_index = self.reservoir_result_dict.get("j_index")
self.q_max = self.reservoir_result_dict.get("q_max")
self.pws = self.reservoir_result_dict.get("pws")
self.qb = self.reservoir_result_dict.get("qb")
You can use setattr function
for name in ["pb", "rs", "bo", "uo", "re", "j_index", "q_max", "pws", "qb"]:
setattr(self, name, self.reservoir_result_dict.get(name))
Documentation of setattr:
https://docs.python.org/3/library/functions.html#setattr
Delegating attributes is done by defining the __getattr__ method. You should store the dictionary only and then define __getattr__.
class Foo:
...
def get_ipr_data(self):
self.reservoir_result_dict = ReservoirDataFrame.reservoir_result_dict
def __getattr__(self, item):
return self.reservoir_result_dict[item]

Python3: Accessing func inside func inside class

I'm playing around and testing data structure and noticed you could print a list inside a class or a def function if you do class.list[0] or def.list[0], so I tried seeing how deep it could go and adding func inside func inside the class but instead of my expectation to just add more dots to the end of the value to chain them, it seems it doesn't work past 1 value.
class player:
def __init__(self, name, spec):
self.name = name
self.spec = spec
var1 = ('A1','A2')
def def1():
defA = "printed defA"
def def2():
defB = ('B1','B2')
print(player.def1.def2.defB[0]) #Doesn't work---
print(player.var1[0]) #Works fine---
In this case, would there be a way to print (or anything else) to the values nested deep in there? What would the address of this value be?

How to add a set of multiple values to a key?

I created a class which is basically a hobby book. The book can be accessed by two methods, enter(n,h) which takes a name and keep adding hobbies to that name(one name can have multiple hobbies). The other method returns a set of hobbies for a particular name. My hobby book is storing every hobby that I insert to one name. Can someone help me fixing it?
class Hobby:
def __init__(self):
self.dic={}
self.hby=set()
def enter(self,n,h):
if n not in self.dic.items():
self.dic[n]=self.hby
for k in self.dic.items():
self.hby.add(h)
def lookup(self,n):
return self.dic[n]
I tried running following cases
d = Hobby(); d.enter('Roj', 'soccer'); d.lookup('Roj')
{'soccer'}
d.enter('Max', 'reading'); d.lookup('Max')
{'reading', 'soccer'} #should return just reading
d.enter('Roj', 'music'); d.lookup('Roj')
{'reading', 'soccer','music'} #should return soccer and music
Why are you re-inventing a dict here? Why are you using a separate set to which you always add values, and reference it to every key which ensures that it always returns the same set on a lookup?
Don't reinvent the wheel, use collections.defaultdict:
import collections
d = collections.defaultdict(set)
d["Roj"].add("soccer")
d["Roj"]
# {'soccer'}
d["Max"].add("reading")
d["Max"]
# {'reading'}
d["Roj"].add("music")
d["Roj"]
# {'soccer', 'music'}
.
UPDATE - If you really want to do it through your own class (and before you do, watch Stop Writing Classes!), you can do it as:
class Hobby(object):
def __init__(self):
self.container = {}
def enter(self, n, h):
if n not in self.container:
self.container[n] = {h}
else:
self.container[n].add(h)
def lookup(self, n):
return self.container.get(n, None)
d = Hobby()
d.enter("Roj", "soccer")
d.lookup("Roj")
# {'soccer'}
d.enter("Max", "reading")
d.lookup("Max")
# {'reading'}
d.enter("Roj", "music")
d.lookup("Roj")
# {'soccer', 'music'}
Note how no extra set is used here - every dict key gets its own set to populate.

Resources