This question already has answers here:
How to avoid having class data shared among instances?
(7 answers)
Closed 14 days ago.
I'm following the YouTube video Learn Python through Data Hacking and am expanding on the sort of "legacy" inline way by adding classes to learn all the ins and outs of Python OOP. Basically the guy in the video has you grab the Chicago bus line's route, parse it, and find which bus his friend left his suitcase on by comparing lat, long, time, distace, etc.
The XML file I'm working with has a bunch of values like so:
<bus>
<id>1867</id>
<rt>22</rt>
<d>North Bound</d>
<dd>Northbound</dd>
<dn>N</dn>
<lat>41.89167051315307</lat>
<lon>-87.6297836303711</lon>
<pid>5421</pid>
<pd>Northbound</pd>
<run>P258</run>
<fs>Howard</fs>
<op>30090</op>
<dip>8858</dip>
<bid>7323012</bid>
<wid1>0P</wid1>
<wid2>258</wid2>
</bus>
From there, I need to find which bus' latitude are north from his position (defined in the class, moot for this example). From those nodes, I'm creating a Bus object like so:
class Bus:
# The original XML node
__xml = None
# Our dictionary for properties to shadow a get() function on this object
__tree = {}
def __init__(self, busxml):
self.__xml = busxml
for e in busxml:
self.__tree[e.tag] = busxml.findtext(e.tag)
def gettree(self):
return self.__tree
# Tries to return prop, or returns None
def get(self, prop):
try:
return self.__tree[prop]
except KeyError:
return -1
def getall(self):
return self.__tree
From the "main" file, I'm looping through the values and appending matches based on the lat node's text value:
# __getRouteData() is the url open and write function, works fine.
# parser is the xml.etree.ElementTree parse class
if self.__getRouteData() == True:
xmlParser = parser(self.__xmlFile)
busses = xmlParser.getnodes()
matches = []
# loop over all
for busTree in busses:
bus = Bus(busTree)
if float(bus.get('lat')) > self.__lat:
matches.append(bus)
print 'appending', bus.get('id')
for bus in matches:
print bus.get('id')
The snag I'm hitting is in the second for loop above. In the first loop, the output is telling me things are working well. The second one outputs the same value twice. It reminds me of the behavior with Javascript for() loops where, without a closure, only the last value is acted upon. My output from the console is as follows:
appending 1784
appending 4057
4057
4057
See... it's telling me it's appending unique busses to my matches list, but when I iterate over the matches list, its only giving me one bus.
Another snippet that tells me something's funky with the second loop:
print 'Matches', matches
for bus in matches:
print bus.get('id')
# Matches [<busutils.Bus instance at 0xb6f92b8c>, <busutils.Bus instance at 0xb6f92d0c>]
# 4057
# 4057
The output of the list is showing me different hashes (...right?) of the objects in the list, hence saying they're two different objects, and thus have different data, but the loop isn't playing nicely.
Obviously I'm just getting into python, but have experience in Java, Javascript, PHP, etc, so I'm not sure what I'm missing in these simple loops.
Thanks!
It's because of your use of class variables on the Bus class. Make them instance variables (created in __init__).
Related
Using dragonfly2, the voice command framework, you can make a grammar like so:
chrome_rules = MappingRule(
name='chrome',
mapping={
'down [<n>]': actions.Key('space:%(n)d'),
},
extras=[
IntegerRef("n", 1, 100)
],
defaults={
"n": 1
}
)
This lets me press space n times, where n is some integer. But what do I do if I want to use the same variable (n), multiple times in the same grammar? If I repeat it in the grammar, e.g. 'down <n> <n>' and then say something like "down three four", Dragonfly will parse it correctly, but it will only execute the actions.Key('space:%(n)d') with n=3, using the first value of n. How can I get it to execute it 3 times, and then 4 times using the same variable?
Ideally I don't want to have to duplicate the variable n, in the extras and defaults, because that seems like redundant code.
TL;DR: Your MappingRule passes data to your Action (e.g. Key, Text) in the form of a dictionary, so it can only pass one value per extra. Your best bet right now is probably to create multiple extras.
This is a side-effect of the way dragonfly parses recognitions. I'll explain it first with Action objects, then we can break down why this happens at the Rule level.
When Dragonfly receives a recognition, it has to deconstruct it and extract any extras that occurred. The speech recognition engine itself has no trouble with multiple occurrances of the same extra, and it does pass that data to dragonfly, but dragonfly loses that information.
All Action objects are derived from ActionBase, and this is the method dragonfly calls when it wants to execute an Action:
def execute(self, data=None):
self._log_exec.debug("Executing action: %s (%s)" % (self, data))
try:
if self._execute(data) == False:
raise ActionError(str(self))
except ActionError as e:
self._log_exec.error("Execution failed: %s" % e)
return False
return True
This is how Text works, same with Key. It's not documented here, but data is a dictionary of extras mapped to values. For example:
{
"n": "3",
"text": "some recognized dictation",
}
See the issue? That means we can only communicate a single value per extra. Even if we combine multiple actions, we have the same problem. For example:
{
"down <n> <n>": Key("%(n)d") + Text("%(n)d"),
}
Under the hood, these two actions are combined into an ActionSeries object - a single action. It exposes the same execute interface. One series of actions, one data dict.
Note that this doesn't happen with compound rules, even if each underlying rule shares an extra with the same name. That's because data is decoded & passed per-rule. Each rule passes a different data dict to the Action it wishes to execute.
If you're curious where we lose the second extra, we can navigate up the call chain.
Each rule has a process_recognition method. This is the method that's called when a recognition occurs. It takes the current rule's node and processes it. This node might be a tree of rules, or it could be something lower-level, like an Action. Let's look at the implementation in MappingRule:
def process_recognition(self, node):
"""
Process a recognition of this rule.
This method is called by the containing Grammar when this
rule is recognized. This method collects information about
the recognition and then calls *self._process_recognition*.
- *node* -- The root node of the recognition parse tree.
"""
# Prepare *extras* dict for passing to _process_recognition().
extras = {
"_grammar": self.grammar,
"_rule": self,
"_node": node,
}
extras.update(self._defaults)
for name, element in self._extras.items():
extra_node = node.get_child_by_name(name, shallow=True)
if extra_node:
extras[name] = extra_node.value()
elif element.has_default():
extras[name] = element.default
# Call the method to do the actual processing.
self._process_recognition(node, extras)
I'm going to skip some complexity - the extras variable you see here is an early form of the data dictionary. See where we lose the value?
extra_node = node.get_child_by_name(name, shallow=True)
Which looks like:
def get_child_by_name(self, name, shallow=False):
"""Get one node below this node with the given name."""
for child in self.children:
if child.name:
if child.name == name:
return child
if shallow:
# If shallow, don't look past named children.
continue
match = child.get_child_by_name(name, shallow)
if match:
return match
return None
So, you see the issue. Dragonfly tries to extract one value for each extra, and it gets the first one. Then, it stuffs that value into a dictionary and passes it down to Action. Additional occurrences are lost.
I'm trying to write a general test script to find errors in new software builds. My idea is to iterate through the controls in the window and interact with each one, logging any errors that are caused and restarting the software if it crashes.
I'm looking for a way to dynamically find control identifiers, a bit like print_control_identifiers() but with the output being a list or similar structure which I can iterate through.
On a GitHub question about control identifiers this was mentioned:
it's possible to walk the hierarchy by using .children() (immediate children only) and .descendants() (the whole subtree as a plain list)
I assumed I could just iterate through my Application object's descendants() list and call a relavant interaction method for each, however I can't work out how to get this list. I assumed I could do something like this, but I haven't had any success:
def test(application):
for child in application.descendants():
#interact with child control
software = Application(backend='uia').start(cmd_line=FILE_PATH)
test(software)
AttributeError: Neither GUI element (wrapper) nor wrapper method 'descendants' were found (typo?)
EDIT
I resorted to looking through the code and found the print_control_identifiers method:
class Application(object):
def print_control_identifiers(self, depth=None, filename=None):
"""
Prints the 'identifiers'
Prints identifiers for the control and for its descendants to
a depth of **depth** (the whole subtree if **None**).
.. note:: The identifiers printed by this method have been made
unique. So if you have 2 edit boxes, they won't both have "Edit"
listed in their identifiers. In fact the first one can be
referred to as "Edit", "Edit0", "Edit1" and the 2nd should be
referred to as "Edit2".
"""
if depth is None:
depth = sys.maxsize
# Wrap this control
this_ctrl = self.__resolve_control(self.criteria)[-1]
# Create a list of this control and all its descendants
all_ctrls = [this_ctrl, ] + this_ctrl.descendants()
# Create a list of all visible text controls
txt_ctrls = [ctrl for ctrl in all_ctrls if ctrl.can_be_label and ctrl.is_visible() and ctrl.window_text()]
# Build a dictionary of disambiguated list of control names
name_ctrl_id_map = findbestmatch.UniqueDict()
for index, ctrl in enumerate(all_ctrls):
ctrl_names = findbestmatch.get_control_names(ctrl, all_ctrls, txt_ctrls)
for name in ctrl_names:
name_ctrl_id_map[name] = index
# Swap it around so that we are mapped off the control indices
ctrl_id_name_map = {}
for name, index in name_ctrl_id_map.items():
ctrl_id_name_map.setdefault(index, []).append(name)
This shows that .descendants() isn't a method of the Application class, but belongs to the control. I was wrong there it seems. Is it possible to create my own version of print_control-identifiers() which returns a list of control objects that can be iterated through?
Correct method to list top-level windows is application.windows(). Then you can call .descendants() for every listed window. In the most cases application has only one top-level window. Particularly for backend="uia" even new dialogs are children of the main window (for backend="win32" every dialog is a top-level window).
This question already has answers here:
How can you dynamically create variables? [duplicate]
(8 answers)
Closed 4 years ago.
I have a class for which I want to create instances through a function, but I also want to be able to name the instances with the value of a Tkinter.Entry widget.
The simplified version of that I am trying to achieve is the following:
class vtdiagram():
IO=0.0
IC=0.0
EO=0.0
EC=0.0
IGA=0.0
def printvtvalues(self):
print self.IO
print self.IC
print self.EO
print self.EC
print self.IGA
def createvtinstance():
global Nametemp
Nametemp=vtdiagram()
If I run this code, then I can call Nametemp.printvtvalues() and get all values printed, so it works fine.
I am now trying to change the name of the instance Nametemp to the string that is on the Tkinter entry widget. Basically, if engine1 is written on the entry box when I createvtinstance(), I would like to then call the instance by:
engine1.printvtvalues()
and get the values.
I imagine the function should look something like this:
def createvtinstance():
global Nametemp
Nametemp=vtdiagram()
Nametemp._command_to_change_the_name_=stringinentrybox.get()
Do you guys have know of a command that can do such a thing?
Or is there a way that I could achieve the same effect, maybe using a dictionary?
***edit: The reason I need to name the variables is for the following (in plain English): I am creating an 'engine simulator'.
The idea is that the user will enter engine parameters -plus its name- in a GUI and this is the vtdiagram class.
The reason for using a class is that I have the characteristics of 'engine1, engine2...' saved as an instance of the class but I also need to have functions attached to it. This is because I want to generate graphs and diagrams of saved engines but only when called. So I can compare engine1 and engine2, but then get 'forget' engine2 from the GUI to compare 1 and 3.
Please keep in mind I am quite new to python :) ***
Many thanks!
Juan
I wouldn't recommend changing the name of a variable based on user input.
You could "achieve the same effect" like this:
Objects=[]
Names=[]
def createvtinstance(Object=4,Name="engine1"):
global Nametemp
global Objects
global Names
Nametemp=Object # I'll just use an int to demonstrate.
Objects+=[Nametemp]
Names+=[Name]
def Use(Name="engine1"):print(Objects[Names.index(Name)]) # Or: Objects[Names.index(Name)].SomeFunction()
If you REALLY want to alter the name of a variable based on user input, then you could do it like this:
def createvtinstance(Name="engine1"):
if (not Name[0]in"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM") or False in(i in"1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"for i in Name) or Name in("tkinter","createvtinstance","Name","vtdiagram",):return "Invalid name." # This should make the code more "robust".
try:exec("global "+Name+"\n"+Name+"=vtdiagram()")
except SyntaxError:return "Invalid name."
Or this:
def createvtinstance(Name="engine1"):
if (not Name[0]in"qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM") or False in(i in"1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"for i in Name) or Name in("tkinter","createvtinstance","Name","vtdiagram",):raise NameError("The name "+Name+" does not comply to validation rules.") # This should make the code more "robust".
try:exec("global "+Name+"\n"+Name+"=vtdiagram()")
except SyntaxError:raise NameError(Name+" is a reserved keyword.")
The top example shows how you would use a list to find an object in another list; using a string. This is what I'd probably do in this situation, however a dictionary could be better.
The bottom examples show how you would actually name a variable based on user input. This is NOT RECOMMENDED. Everyone seems to agree that using exec is counterproductive, and should be avoided. Python can't compile code in exec statements until execution, and won't be able to colour code your code.
People have been suggesting the use of python dictionaries, so I decided to research them. Dictionaries (dict) seem to be a data type similar to lists, except they can be indexed using strings (or other "immutable" data types). Here is a version of my first example that uses a dictionary instead of lists:
Objects={}
def createvtinstance(Object=4,Name="engine1"):
global Objects
Objects[Name]=Object
def Use(Name="engine1"):print(Objects[Name]) # Or: Objects[Name].SomeFunction()
Python seems to have a built in dictionary called globals, which stores all your variables, so you could probably do:
def createvtinstance(Object=4,Name="engine1"):
globals()[Name]=Object # Or globals()[Name]=vtdiagram()
However, this will allow the user to break your program, if they use a name like createvtinstance or tkinter.
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've seen several answers about how to check if list is empty, but didn't find excatly what i need.
shortly - in python, I need a way to check if list is full, and then empty it, but i need that the check will start just after i fill the list.
I'm define list by call my class - Packet()
class Packet(object):
"""description of class"""
def __init__(self):
self.newPacket = []
newPacket = Packet()
I have menu, which one of the options is to call function in the class to fill the list.
but, if the function get chose again, i need to empty the instance, and start a new one.
I've tried to do that:
if newPacket:
del newPacket
newPacket.MakePacket()
but this don't let me start the list by call the function..
if i disable the
if newPacket:
del newPacket
the function works just fine.
You appear to be confusing a particular Packet instance that you have created and chosen to name newPacket, with its attribute of the same name. Rather than delete the instance, or even delete the list, it sounds like you want to empty the list. Because you've given two different things the same name, the list in question is now accessible from your command-line as newPacket.newPacket (although which the object itself likes to refer to it, in its own methods, as self.newPacket).
So. When you del newPacket, you are removing the reference to the object newPacket from the current workspace. The interpreter will then raise a NameError if you try to do anything with that symbol, such as newPacket.MakePacket() - because that variable no longer exists in the current workspace.
If you want to implement Packet methods that count the items in the self.newPacket list attribute, or empty it, you could say:
class Packet(object):
# ...
def count( self ):
return len( self.newPacket )
def clear( self ):
del self.newPacket[:]
That incidentally illustrates one way of emptying a list, while retaining a reference to the now-empty list: del myList[:]
values = input("Enter a list (U CAN ALSO CREATE AN EMPTY LIST. IF YOU WANT THEN SIMPLY PRESS 'ENTER'). If not then write e.g. ABC or 1, 2 or 2019 to insert: ")
list = list(values)
if list == []:
print("Your list", list, "is an empty list!")
else:
print("Your list", list, "is not an empty list.")
Firstly, it'll take an input from user. Secondly, after giving the input it'll check the given input. Finally, after the checking process completion it'll give a msg to the user (will show a msg if the given input empty or not? Whatever the scenario is).