How to reduce elif statements - python

My script runs the C program digitemp. The output is in rows containing the sensor ID and the temperature. I need to match the sensor ID with a particular name thus all the elifs. I have used first, second third in this example as the names to math the ID's. Is there any way to reduce all the elif statements as there are more to be added?
import os
# get digitemps output
cmd = "/bin/digitemp_ -c /bin/digitemp.conf -q -a"
def digitemps():
for outline in os.popen(cmd).readlines():
outline = outline[:-1].split()
if outline[0] == '28F4F525030000D1':
temp_ = outline[1]
print 'first ' + temp_
elif outline[0] == '28622A260300006B':
temp_ = outline[1]
print 'second ' + temp_
elif outline[0] == '28622A2603000080':
temp_ = outline[1]
print 'third ' + temp_
digitemps()

Use a dictionary to map from sensor ID to a human-readable name:
id_to_name = {"28F4F525030000D1": "first",
"28622A260300006B": "second",
"28622A2603000080", "third"}
print id_to_name.get(outline[0], outline[0]) + outline[1]
The advantage of this approach is that the get method will return the ID without any change if there is no human-readable name assigned to it.

Most of the logic inside the loop can be written using generator expressions, this is code is equivalent and takes into account #DSM's advice in the comments:
d = {'28F4F525030000D1':'first ',
'28622A260300006B':'second ',
'28622A2603000080':'third '}
def digitemps():
for s in (d.get(x[0],x[0]) + x[1] for x in (e.split() for e in os.popen(cmd))):
print s

Unfortunately, Python has no way of doing so. If you were using C++, you could've used the switch statement, but Python has no such equilavent. Sorry!

Related

Python nested dictionary not keeping elements in order

I've been trying to create an input library for Selenium using the nested dictionary data type, and while at first it was working perfectly I am now realizing I have gotten myself into a position where I cannot be assured that my elements will stay in order (which is very necessary for this library).
Here is an example of how I am trying to structure this code:
qlib = {
'code_xp':
{'keywords':
{'javascript':0,
'web design':1,
'python':0},
'answer':
{'4',
'yes'}}
}
for prompt, info in qlib.items()
for t, i in enumerate(list(info['answer'])):
if t == 0:
try:
print(i)
except:
pass
If you run this yourself, you will soon realize that after a few runs it will have rearranged the output from the list ['4', 'yes'], switching between ['4'] to ['yes']. Given that I depend on only referencing the first element for certain inputs ('4'), I can't allow this.
As for the 'keywords' section, I have used the structure i.e. 'javascript':0 as a necessary tag element for data processing. While this is not relevant for this problem, any solution would have to account for this. Here is my full data processing engine for those that would like to see the original context. Please note this comes before the 'for' loop listed above:
trs = 'translate(., "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz")'
input_type = ['numeric', 'text', 'multipleChoice', 'multipleChoice']
element_type = ['label', 'label', 'label', 'legend']
for index, item in enumerate(input_type):
print(f"Current input: {item}")
form_number = driver.find_elements(By.XPATH,'//' +element_type[index]+ '[starts-with(#for, "urn:li:fs_easyApplyFormElement")][contains(#for, "' +item+ '")]')
if form_number:
print(item)
for link in form_number:
for prompt, info in qlib.items():
keywords = info['keywords']
full_path = []
for i, word in enumerate(keywords):
path = 'contains(' +trs+ ', "' +word+ '")'
if i < len(keywords) - 1:
if keywords[word] == 1:
path += " and"
elif keywords[word] == 0:
path += " or"
full_path.append(path)
full_string = ' '.join(full_path)
answer = ' '.join(info['answer'])
I've been trying to find the right datatype for this code for a while now, and while this almost works perfectly the problem I'm facing makes it unusable. I've considered an OrderedDict as well, however I am not confident I can keep the structures that I depend on. Looking for anything that will work. Thank you so much for any help!

Ironpython - how do I refer to to a calculated variable in additional lines of code

I am working with IronPython inside Spotfire.
I need to extract the maximum date value from a range filter, then use that value to filter a table of exchange rates.
I have working code right up to the datatable.Select statement in which I need to do the match. If I do it based on "Date(2020,3,1)" - which is the row commented out - then the match works and the correct result is returned, however I cannot get the syntax correct for using a calculated variable "newdate" in place of the Date(xxx) statement. I am still learning python and have not come across this before.
Code as below - any help would be greatly appreciated.
from Spotfire.Dxp.Application.Filters import RangeFilter, ValueRange
from Spotfire.Dxp.Data.DataType import Date
from System.Globalization import CultureInfo
parser = Date.CreateCultureSpecificFormatter(CultureInfo("en-AU"))
#get a reference to a filter as checkbox from the myDataTable script parameter
filt=Document.FilteringSchemes[Document.ActiveFilteringSelectionReference].Item[dt].Item[dt.Columns.Item["Calendar Date"]].As[RangeFilter]()
print filt.ValueRange.High
if str(filt.ValueRange.High) == "High":
maxdate = Document.Properties["loaddate"]
else:
maxdate = filt.ValueRange.High
maxdate = Date.Formatter.Parse(maxdate)
print maxdate
new = str(maxdate.Year) + "," + str(maxdate.Month) + "," + str("1")
print new
Document.Properties["maxdate"] = new
from Spotfire.Dxp.Data import *
from System.Collections.Generic import List
table=Document.ActiveDataTableReference
# Expression to limit the data in a table
rowSelection=table.Select("CALENDAR_DATE = Date('new')")
#rowSelection=table.Select("CALENDAR_DATE = Date(2020,3,1)")
# Create a cursor to the Column we wish to get the values from
cursor = DataValueCursor.CreateFormatted(table.Columns["FY_AVERAGE_EXCHANGE"])
# Create List object that will hold values
listofValues=List[str]()
# Loop through all rows, retrieve value for specific column,
# and add value into list
for row in table.GetRows(rowSelection.AsIndexSet(),cursor):
rowIndex = row.Index
value1 = cursor.CurrentValue
listofValues.Add(value1)
for val in listofValues:
print val
I think your variable new would print out as 2020,01,01
In this line new is a string so Date() cannot extract a date.
rowSelection=table.Select("CALENDAR_DATE = Date('new')")
You should put new as variable
rowSelection=table.Select("CALENDAR_DATE = Date(" +new +")")
but not sure it'll work as Date takes in Integer not Strings So you might have to re-write to :
y = maxdate.Year
m= maxdate.Month
d = 1
rowSelection=table.Select("CALENDAR_DATE = Date("+ y + ',' + m +',' + d + ")")
or build your String before hand which is the method I would use:
y = maxdate.Year
m= maxdate.Month
d = 1
mystring = "CALENDAR_DATE = Date("+ str(y) + ',' + str(m) +',' + str(d) + ")"
rowSelection=table.Select(mystring)
One of the above ways should work, I'd start with the last one setting your string before as it makes the most sense to not deal with to many conversions of integers and strings.
If you post this question with an example DXP to Tibco Answers could possible help more since will have an example dxp to work with. but hopefully this helps you out.

Extract numbers from a string in python without the use of isdigit or re. tools

Let's say I have a string of integers generated by user input, where each integer is separated by a space (Code below for example)...
How can I search through that string and store each integer separately for use later on in the program? (I.E. Assigning each integer to its own variable) I can't use isdigit and cant use re tools, and I can't store the ints into a list.
userEntry = input("Please enter a Fahrenheit temperature: ")
for i in range(4):
userEntry += " " + input("Please enter another fahrenheit:")
Things I AM allowed to use: string methods, index find/search methods, for loops, if statements, while loops.
Something like this will parse the string into space-separated strings, using slices... (I notice the first answer came in while I was working on this, but this is slightly different, so...)
def extractor(mystr):
start = 0
for a in range(len(mystr)):
if mystr[a] == ' ' or mystr[a] == len(mystr) - 1:
temp = mystr[start:a]
print(temp)
start = a + 1
This is more like a C approach, very un-Pythonic, but standard programming fare. If you will only ever have 5 user entries, this is perhaps manageable. If you can't use a list of those variables, or if you have an unknown number of user entries, or if you have to check to make sure the user actually entered a digit and not a letter, then more work is required, but that's the basic C-string parser. Useful to know if you ever want to dive into Python internals I suppose.
If you need to convert each extracted string to an int, and exceptions are allowed, place this inside the if statement to check for type correctness:
try:
myvar1 = int(temp)
except ValueError:
print("Not an int")
Note that if you absolutely cannot use lists, (*or exec as in the above answer) then the only likely option is to keep slicing off the end of the string, i.e you'd have to do something like the following at the end of each if statement, then write that for loop out 4 more times, changing the variable name each time manually.
mystr = mystr[start:len(mystr)]
break
This will of course not work if you have a variable number of user entries. And is incredibly tedious... I suspect the instructor may have intended something different. Note that the real-world process for all that is just:
result = [int(x) for x in mystr.split(' ') if x.isdigit()]
I am not sure what your use case is, and I can not think of a way where you can assign the numbers to variable in a loop, which is what you have to do if you are not allowed to use a loop. The only way I can think of is exec and I do not feel that is allowed for your task. Regardless, I am posting the answer, in case it is usable:
last_space_index = 0
characters_checked = 0
var_num = 1
userEntry = "12.8 -15.8 125.9 0 -40.0"
for character in userEntry:
characters_checked += 1
if character == ' ':
number = float(userEntry[last_space_index:characters_checked])
var_name = 'var'+str(var_num)
var_num += 1
expression = var_name + ' = number'
# expression becomes 'var1 = number'
exec(expression)
last_space_index = characters_checked
last_number = float(userEntry[last_space_index:])
var_name = 'var'+str(var_num)
expression = var_name + ' = last_number'
exec(expression)
# if you know the number of variables you are going to get
print(var1, var2, var3, var4, var5)
# else:
# for i in range(1,var_num+1):
# var_name = 'var'+str(i)
# command = 'print('+var_name+')'
# exec(command)
Output:
>>> 12.8 -15.8 125.9 0 -40.0
You can replace print with whatever you actually want to do.
And this is completely futile if you are allowed to use dictionary, sets or tuple.

Python - turn some of the words in list/str to dots. len(list)?

I've started learning Python last week on codecademy and Google etc. but got stuck and couldn't find the answer anywhere so signed up on stackoverflow.com looking for your support.
I'm trying to build a program that only takes first 5 letters of any name and the remainder of the letter(s) to be shows as blank dot(s). e.g.
Adrian: "Adria."
Michael: "Micha.."
Alexander: "Alexa...." etc.
I tried to "fix" it with the "b" variable but that just prints three dots "..." regardless of how long the name is.
This is what I've got so far:
def namecheck():
name = raw_input("Name?")
if len(name) <=5:
print name
else:
if len(name) >5:
name = name[0:5]
b = ("...")
print name + b
namecheck()
I'm a total newbie so I apologise for any wrong spacing here, thank you for your support and patience.
As an alternative to sequence multiplication (one which is somewhat more self-documenting, and hopefully less confusing to maintainers), just use str.ljust to do your padding:
def namecheck():
name = raw_input("Name?")
# Reduce to first five (or less) characters, then pad with .s to original length
# with str.ljust
print name[:5].ljust(len(name), '.')
print name[:5] + '.' * (len(name) - 5) works fine, it's just a bit arcane (and also involves more temporary values, though in practice, the lack of actual method calls makes it faster on CPython).
you can try to use the function replace().
name = 'abcdefg'
name.replace(name[5:], '.' * len(name[5:]))
output: 'abcde..'
name='randy12345'
name.replace(name[5:],'.' * len(name[5:]))
output: 'randy.....'
name[5:] means get all the element starting 6 (5+1 because it start with 0)
'.' * len(name[5:] then this code count it and multiply it by dot
name.replace(name[5:],'.' * len(name[5:])) then use replace function to replace the excess element with dots
The most concise way I can think of:
def namecheck():
name = raw_input("Name?")
print(name[0:5] + '.' * (len(name) - 5))
namecheck()
Try something like this:
def namecheck():
name = raw_input("Name?")
if len(name) <= 5:
print name
else:
print name[0:5] + '.' * (len(name)-5)
namecheck()

Python Tkinter title change from list

I've tried to simplify the issue with my program through the code below. I can get it to work but am curious as to why it won't work using the method below.
The print values show the first index, yet the function calls the last index.
list1 = ["Title_0", "Title_1"]
for i, string in enumerate(list1):
if i == 0:
print str(i) + ", " + string # Prints: 0, Title_0
btn_monty = Button(the_window, text='Monty Python', command = lambda:the_window.title(string))
#### This also doesn't work ####
# btn_monty = Button(the_window, text='Monty Python', command = lambda:the_window.title(list1[i]))
The issue is that the string within the lambda is closed on the variable string, not the value of string . That means that the value for variable string is not evaluated until the button is actually called, and when it gets called it uses the latest value of string which would be same for both buttons.
You can instead try using default arguments to pass string . Example -
list1 = ["Title_0", "Title_1"]
for i, strng in enumerate(list1):
print str(i) + ", " + strng # Prints: 0, Title_0
btn_monty = Button(the_window, text='Monty Python', command = lambda new_title=strng:the_window.title(new_title))
I also changed the variable to strng so that it does not conflict with the string module (would be good to avoid any kind of issues in future if you decide to import that module). Also, you should make sure you place the buttons using grid or pack, etc.

Categories