I've got a piece of code which contains a for loop to draw things from an XML file;
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName( "type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName( "typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName( "level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
evolutions.append("%s x %s" % (evoLevel, evoName))
Currently it outputs into a list called evolutions as it says in the last line of that code, for this and several other for functions with very similar functionality I need it to output into a class instead.
class evolutions:
def __init__(self, evoName, evoId, evoLevel, evoCost)
self.evoName = evoName
self.evoId = evoId
self.evoLevel = evoLevel
self.evoCost = evoCost
How to create a series of instances of this class, each of which is a response from that for function? Or what is a core practical solution? This one doesn't really need the class but one of the others really does.
A list comprehension might be a little cleaner. I'd also move the parsing logic to the constructor to clean up the implemenation:
class Evolution:
def __init__(self, node):
self.node = node
self.type = property("type")
self.typeid = property("typeid")
self.level = property("level")
self.costperlevel = property("costperlevel")
def property(self, prop):
return getText(self.node.getElementsByTagName(prop)[0].childNodes)
evolutionList = [Evolution(evoNode) for evoNode in node.getElementsByTagName('evolution')]
Alternatively, you could use map:
evolutionList = map(Evolution, node.getElementsByTagName('evolution'))
for evoNode in node.getElementsByTagName('evolution'):
evoName = getText(evoNode.getElementsByTagName("type")[0].childNodes)
evoId = getText(evoNode.getElementsByTagName("typeid")[0].childNodes)
evoLevel = getText(evoNode.getElementsByTagName("level")[0].childNodes)
evoCost = getText(evoNode.getElementsByTagName("costperlevel")[0].childNodes)
temporaryEvo = Evolutions(evoName, evoId, evoLevel, evoCost)
evolutionList.append(temporaryEvo)
# Or you can go with the 1 liner
evolutionList.append(Evolutions(evoName, evoId, evoLevel, evoCost))
I renamed your list because it shared the same name as your class and was confusing.
Related
First time poster and python newbie here, this question is probably asked before, but I am not able to find any answer.
I have a Class that reads robot status data, this works fine and I am able to dive my data into methods that are working fine when i call them. But I would like to divide my class even more, so the data is structured better. for example
I have some methods the reads and return target_data
def target_joint_positions(self):
t_j_p = self.read_data()[1:7]
return t_j_p
def target_joint_velocities(self):
t_j_v = self.read_data()[7:13]
return t_j_v
def target_joint_currents(self):
t_j_c = self.read_data()[19:25]
return t_j_c
And similar methods returning actual_data:
def actual_joint_positions(self):
a_j_p = self.read_data()[31:37]
return a_j_p
def actual_joint_velocities(self):
a_j_v = self.read_data()[37:43]
return a_j_v
def actual_joint_currents(self):
a_j_c = self.read_data()[43:49]
return a_j_c
So what I would like to accomplish is that when i make a instance of my class, instead of getting all the methods i would like something like this:
inst = Class_Name()
inst.target. (list of target methods)
inst.actual. (list of actual methods)
I have looked into nested classes and inheritance but I have not been successful in achieving my goal. Thanks for any pointers.
Welcome!
You can do the following:
class TargetMetrics:
def __init__(self, data):
self.data = data
def joint_positions(self):
return self.data[1:7]
...
class ActualMetrics:
def __init__(self, data):
self.data = data
def joint_positions(self):
return self.data[31:37]
...
class RobotMetrics:
def __init__(self):
data = read_data()
self.actual = ActualMetrics(data)
self.target = TargetMetrics(data)
...
w_rook_1 = ChessPiece('w_rook_1')
w_knight_1 = ChessPiece('w_knight_1')
w_bishop_1 = ChessPiece('w_bishop_1')
w_king = ChessPiece('w_king')
w_queen = ChessPiece('w_queen')
w_bishop_2 = ChessPiece('w_bishop_2')
w_knight_2 = ChessPiece('w_knight_2')
w_rook_2 = ChessPiece('w_rook_2')
w_pawn_1 = ChessPiece('w_pawn_1')
w_pawn_2 = ChessPiece('w_pawn_2')
w_pawn_3 = ChessPiece('w_pawn_3')
w_pawn_4 = ChessPiece('w_pawn_4')
w_pawn_5 = ChessPiece('w_pawn_5')
w_pawn_6 = ChessPiece('w_pawn_6')
w_pawn_7 = ChessPiece('w_pawn_7')
w_pawn_8 = ChessPiece('w_pawn_8')
Is there an easier way to do this? I would also like to be able to use the objects afterwards.
Here is a simple approach using a dictionary when dealing with this type of challenge.
I added some comments within the code, please read.
instance_names = ['w_rook_1',
'w_knight_1',
'w_bishop_1',
'w_king',
'w_queen',
'w_bishop_2',
'w_knight_2',
'w_knight_2']
class ChessPiece(object):
def __init__(self, name):
self.name = name
self.move = "moving {}".format(name)
chess_objs = {}
for obj in instance_names:
# insert instance names ex. 'w_rook_1' as the key
# the ChessPiece instance is set as the value
chess_objs.setdefault(obj, ChessPiece(obj))
# here just illustrates how to access fields
# bound to each object
print(chess_objs['w_bishop_1'].name)
print(chess_objs['w_bishop_1'].move)
outputs:
w_bishop_1
moving w_bishop_1
If you follow #kaya3's advice and redesign your ChessPiece class, you could use a list comprehension easily, something like this (using abbreviations and ignoring number):
color = 'W'
non_pawns = [ChessPiece(color, c) for c in 'RNBKQBNR']
pawns = [ChessPiece(color, 'P') for _ in range(8)]
I have created a script that stores and edits meta-data in a system. I am now cleaning up my code by defining a class and methods, previously I only used separate functions.
In the script I am storing old and new values of certain types of metadata in lists, which I print out after the script has completed its run. I have defined multiple lists (16 to be exact), which I realized is quite a lot when passing them through a method. I was wondering what is the most pythonic way to approach this.
These are the following list variables that i define in the beginning. In the function/method I append values to them. In the end I print the stored valued out as a report.
split_name = []
split_name_new = []
name = []
name_new = []
meta = []
meta_new = []
series = []
series_new = []
product = []
owner = []
desc = []
desc_new = []
keywords = []
keywords_new = []
no_edit_page =[]
no_edit_page_name = []
In a class i figured it will look something like (if I define all the list separately)
class Metadata_editor():
def __init__(self,url):
self.split_name = []
self.split_name_new = []
self.name = []
self.name_new = []
self.meta = []
self.meta_new = []
self.series = []
self.series_new = []
self.product = []
self.owner = []
self.desc = []
self.desc_new = []
self.keywords = []
self.keywords_new = []
self.no_edit_page =[]
self.no_edit_page_name = []
#Ugly solution because the method gets crowded by all the variables passed through
def data_edit(self, split_name, split_name_new, name, name_new,.. etc):
#Not the whole method, but just to give some idea..
#Selenium function that locates meta
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
#replace_words translate the word using a dictionary object
meta_data_new = replace_words(meta_data,c)
meta.append(meta_data)
meta_new.append(meta_data_new)
The solution above I realized would not be ideal.
I found an alternative way that I could use, which is I define a list of lists. The solution would then look something like this (see below). However 'data_list[10]' is not as self-explanatory as for say 'owner'. My question is, is this the 'best' way to solve this, or do you have any other suggestions? I don't really have anything against this solution, but was wondering if there is a more 'pythonic' way to approach this.
class Metadata_editor():
def __init__(self,url):
self.data_list=[[] for _ in range(16)] #Creates a list, that contains 16 lists
# More eloquent solution, as only one variable is passed through. However finding
# the right data from data_list is perhaps not as easy before
def data_edit(self, data_list):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
data_list[5].append(meta_data)
data_list[6].append(meta_data_new)
You could store it as a dictionary. That would have the advantage of being able to reference the keys by name rather than having to remember the indexes.
class Metadata_editor():
def __init__(self, url):
keys = [
'split_name', 'split_name_new', 'name', 'name_new' 'meta', 'meta_new',
'series', 'series_new', 'product', 'owner', 'desc', 'desc_new',
'keywords', 'keywords_new', 'no_edit_page', 'no_edit_page_name',
]
self.data_dict = dict((x, []) for x in keys)
def data_edit(self):
md = driver.find_element_by_xpath("//input[#name='metadata-name']")
meta_data = md.get_attribute("value")
meta_data_new = replace_words(meta_data,c)
self.data_dict['meta'].append(meta_data)
self.data_dict['meta_new'].append(meta_data_new)
A few extra points to note:
class names generally follow the UpperCaseCamelCase convention. So Metadata_editor would more conventionally be written as MetadataEditor
Using self sets an attribute on the class, it can be accessed in the class using self and the attribute does not need to be passed into the method. I have shown this in the example above, accessing self.data_dict in the data_edit method.
You can also use setattr to set attributes to the class as shown in some of the other answers.
You can initialize multiple lists as below:
class Metadata_editor():
def __init__(self,list_names):
[setattr(self,name,[]) for name in list_names]
me = Metadata_editor(['split_name','split_name_new']) # initialize two lists
me.split_name.append(5) # add value to a list
print(me.split_name, me.split_name_new)
>>[5], [ ]
Once set as part of the class via self.list_name, the list(s) can be accessed globally within the class - no longer requiring to be 'passed in'. To initialize lists to specific values, you can do:
def __init__(self,list_names,list_values):
[setattr(self,name,value) for name,value in zip(list_names,list_values)]
Use setattr:
...
def __init__(self, url):
names = '''split_name split_name_new name
name_new meta meta_new series series_new
product owner desc desc_new keywords
keywords_new no_edit_page
no_edit_page_name'''.split()
for name in names:
setattr(self, name, [])
...
I have a small Python OOP program in which 2 class, Flan and Outil inherit from a superclass Part.
My problem is when I call Flan everything works perfectly, however when I call Outil the program fails silently.
The Outil instance is created, but it lacks all the attributes it doesn't share with Part.
The Outil instance isn't added to Outil.list_instance_outils, nor to Part.list_instances.
class Outil(Part):
list_instance_outils = []
def __init___(self, name, part_type, nodes, elems):
Part.__init__(self, name, part_type, nodes, elems)
self.vect_norm = vectnorm(self.nodes[self.elems[0,1:]-1, 1:])
self.elset = Elset(self)
self.nset = Nset(self, refpoint=True, generate=False)
self.SPOS = Ab_surface(self, self.elset)
self.SNEG = Ab_surface(self, self.elset, type_surf='SNEG')
Outil.list_instance_outils.append(self)
Part.list_instances.append(self)
class Flan(Part):
list_instances_flans = []
def __init__(self, name, part_type, nodes, elems):
Part.__init__(self, name, part_type, nodes, elems)
self.vect_norm = vectnorm(self.nodes[self.elems[0,1:4]-1, 1:])
self.elset = Elset(self)
self.nset = Nset(self)
self.SPOS = Ab_surface(self, self.elset)
self.SNEG = Ab_surface(self, self.elset, type_surf='SNEG')
Flan.list_instances_flans.append(self)
Part.list_instances.append(self)
Both this Classes inherit from Part :
class Part():
list_instances = []
def __init__(self, name, part_type, nodes, elems):
self.name = name
self.name_instance = self.name + '-1'
self.part_type = part_type
self.elems = elems
self.nodes = nodes
offset = np.min(self.elems[:, 1:])-1
self.nodes[:, 0] -= offset
self.elems[:, 1:] -= offset
I cannot stress enough that I have no error message whatsoever.
What am I doing wrong here ?
You wrote __init__ with three trailing underscores instead of two in Outil.
Because of this, it doesn't get called -- Part.__init__ gets called instead. That's why the class is created but it lacks the attributes beyond what are in Part.
To solve this sort of problem, the best thing to do is to run the code through the debugger.
Get your classes into the python interpreter (import, paste, whatever you like), then call pdb: import pdb; pdb.run('Outil()'). You can now step through the code to see what is happening.
I am maintaining a little library of useful functions for interacting with my company's APIs and I have come across (what I think is) a neat question that I can't find the answer to.
I frequently have to request large amounts of data from an API, so I do something like:
class Client(object):
def __init__(self):
self.data = []
def get_data(self, offset = 0):
done = False
while not done:
data = get_more_starting_at(offset)
self.data.extend(data)
offset += 1
if not data:
done = True
This works fine and allows me to restart the retrieval where I left off if something goes horribly wrong. However, since python functions are just regular objects, we can do stuff like:
def yo():
yo.hi = "yo!"
return None
and then we can interrogate yo about its properties later, like:
yo.hi => "yo!"
my question is: Can I rewrite my class-based example to pin the data to the function itself, without referring to the function by name. I know I can do this by:
def get_data(offset=0):
done = False
get_data.data = []
while not done:
data = get_more_starting_from(offset)
get_data.data.extend(data)
offset += 1
if not data:
done = True
return get_data.data
but I would like to do something like:
def get_data(offset=0):
done = False
self.data = [] # <===== this is the bit I can't figure out
while not done:
data = get_more_starting_from(offset)
self.data.extend(data) # <====== also this!
offset += 1
if not data:
done = True
return self.data # <======== want to refer to the "current" object
Is it possible to refer to the "current" object by anything other than its name?
Something like "this", "self", or "memememe!" is what I'm looking for.
I don't understand why you want to do this, but it's what a fixed point combinator allows you to do:
import functools
def Y(f):
#functools.wraps(f)
def Yf(*args):
return inner(*args)
inner = f(Yf)
return Yf
#Y
def get_data(f):
def inner_get_data(*args):
# This is your real get data function
# define it as normal
# but just refer to it as 'f' inside itself
print 'setting get_data.foo to', args
f.foo = args
return inner_get_data
get_data(1, 2, 3)
print get_data.foo
So you call get_data as normal, and it "magically" knows that f means itself.
You could do this, but (a) the data is not per-function-invocation, but per function (b) it's much easier to achieve this sort of thing with a class.
If you had to do it, you might do something like this:
def ybother(a,b,c,yrselflambda = lambda: ybother):
yrself = yrselflambda()
#other stuff
The lambda is necessary, because you need to delay evaluation of the term ybother until something has been bound to it.
Alternatively, and increasingly pointlessly:
from functools import partial
def ybother(a,b,c,yrself=None):
#whatever
yrself.data = [] # this will blow up if the default argument is used
#more stuff
bothered = partial(ybother, yrself=ybother)
Or:
def unbothered(a,b,c):
def inbothered(yrself):
#whatever
yrself.data = []
return inbothered, inbothered(inbothered)
This last version gives you a different function object each time, which you might like.
There are almost certainly introspective tricks to do this, but they are even less worthwhile.
Not sure what doing it like this gains you, but what about using a decorator.
import functools
def add_self(f):
#functools.wraps(f)
def wrapper(*args,**kwargs):
if not getattr(f, 'content', None):
f.content = []
return f(f, *args, **kwargs)
return wrapper
#add_self
def example(self, arg1):
self.content.append(arg1)
print self.content
example(1)
example(2)
example(3)
OUTPUT
[1]
[1, 2]
[1, 2, 3]