Python Tkinter title change from list - python

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.

Related

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.

Cannot understand how this Python code works

I found this question on HackerRank and I am unable to understand the code(solution) that is displayed in the discussions page.
The question is:
Consider a list (list = []). You can perform the following commands:
insert i e: Insert integer at position .
print: Print the list.
remove e: Delete the first occurrence of integer .
append e: Insert integer at the end of the list.
sort: Sort the list.
pop: Pop the last element from the list.
reverse: Reverse the list.
Even though I have solved the problem using if-else, I do not understand how this code works:
n = input()
slist = []
for _ in range(n):
s = input().split()
cmd = s[0]
args = s[1:]
if cmd !="print":
cmd += "("+ ",".join(args) +")"
eval("slist."+cmd)
else:
print slist
Well, the code takes advantage of Python's eval function. Many languages have this feature: eval, short for "evaluate", takes a piece of text and executes it as if it were part of the program instead of just a piece of data fed to the program. This line:
s = input().split()
reads a line of input from the user and splits it into words based on whitespace, so if you type "insert 1 2", s is set to the list ["insert","1","2"]. That is then transformed by the following lines into "insert(1,2)", which is then appended to "slist." and passed to eval, resulting in the method call slist.insert(1,2) being executed. So basically, this code is taking advantage of the fact that Python already has methods to perform the required functions, that even happen to have the same names used in the problem. All it has to do is take the name and arguments from an input line and transform them into Python syntax. (The print option is special-cased since there is no method slist.print(); for that case it uses the global command: print slist.)
In real-world code, you should almost never use eval; it is a very dangerous feature, since it allows users of your application to potentially cause it to run any code they want. It's certainly one of the easier features for hackers to use to break into things.
It's dirty code that's abusing eval.
Basically, when you enter, for example, "remove 1", it creates some code that looks like sList.remove(1), then gives the created code to eval. This has Python interpret it.
This is probably the worst way you could solve this outside of coding competitions though. The use of eval is entirely unnecessary here.
Actually I Find some error in the code, but I came to an understanding of how this code runs. here is it:
input :
3
1 2 3
cmd = 1 + ( 2 + 3)
then eval(cmd) i.e., eval("1 + (2 + 3)") which gives an output 6
another input:
4
4 5 6 2
cmd = 4 + ( 5 + 6 + 2)
eval(cmd)
if __name__ == '__main__':
N = int(raw_input())
lst=[]
for _ in range(N):
cmd, *line = input().split()
ele= list(map(str,line))
if cmd in dir(lst):
exec('lst.'+cmd+'('+','.join(ele)+')')
elif cmd == 'print':
print(lst)
else:
print('wrong command', cmd)

Python in Maya: main function calls other function while passing variables?

I am an animator who is a beginner at coding...I appreciate your help!
I am writing a Python script to automatically duplicate controller objects in Maya. It creates controllers for each bone in the character's hand.
It worked fine as a single long function, but I want to have a Main Function, "handCtrls()", call functions within it for the various tasks. I also need to pass variables to the sub-functions, because I am iterating on the variable "i".
I get an error on the line which calls the function "nullGrouper(side, boney, i, ctrl)", and the error says that "global variable 'ctrl' is undefined". But it is defined in the "ctrlDup" function, and I used "return ctrl", which I though would send that variable back to 'handCtrls()'.
here is the code:
import maya.cmds as c
def ctrlDup(side, boney, i, ctrlOrig):
#Select and duplicate the original Control, and place it at the appropiate boney
c.select(ctrlOrig)
ctrl = c.duplicate(ctrlOrig, n=side + boney + str(i) + '_CTRL')
print(ctrl)
print('ctrlDup passed')
return ctrl
def nullGrouper(side, boney, i, ctrl):
#Create null group at same position as Control
print(ctrl)
print(ctrl[0])
nullGrp = c.group(n=side + boney + str(i) + '_GRP', empty=1, world=1)
print(nullGrp)
c.parentConstraint(ctrl, nullGrp, n='nullGrp_parentConstr_temp')
c.delete('nullGrp_parentConstr_temp')
print('nullGrouper passed')
return ctrl, nullGrp
def handCtrls():
#First select the Controller to be duplicated
sel = c.ls(sl=1)
ctrlOrig = sel[0]
#List sides
sideList = ['L_', 'R_']
#List bones of part
boneyList = ['thumb', 'index', 'middle', 'ring', 'pinky']
#Now, iterate across finger joints, up to 3, group controls, and parent them
for side in sideList:
for boney in boneyList:
for i in range(1, 4, 1):
#Check if boney is thumb, and joint number is 3
if (boney!='thumb') or (i!=3):
ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)
else:
pass
print("It's done.")
handCtrls()
There are several 'print' commands just to check if the variable is getting passed. Thank you!
It is because you are not storing the return
...
ctrl = ctrlDup(side, boney, i, ctrlOrig)
nullGrouper(side, boney, i, ctrl)

Assign variable if list index out of range python error

How to pass a string to a variable if an index error is found? Consider the code:
for l1, l2 in zip(open('file1.list'), open ('file2.list')):
a=fasta1[int(l1)]
b=fasta2[int(l2)]
alignments = pairwise2.align.globalxx(a,b)
top_aln = alignments[0]
aln_a, aln_b, score, begin, end = top_aln
print aln_a+'\n'+aln_b
outfast1 = aln_a
outfast2 = aln_b
A number of these functions must be imported (pairwise2 align),
but the file.lists are single column text files with one sequence id (text and numbers) per line, that are used to extract from the fasta1 and fasta2 text files.
Basically, I want to try: each list command ( a=fasta1[int(l1)]) and if there is no error (the id is in range), do as normal (assign variables a and b for that iteration), but if NOT, assign the 'a' variable some placeholder text like 'GGG':
for l1, l2 in zip(open('file1.list'), open ('file2.list')):
try:
a=fasta1[int(l1)]
except IndexError,e:
a="GGG"
continue
try:
b=fasta2[int(l2)]
except (IndexError):
b="CCC"
continue
This code doesn't quite work (when integrated with above code), which isn't surprising given my lack of python prowess, but I don't quite know why. I actually get no text output, despite the print calls... Am I thinking about this right? If there is NO error in the index, I just want it to go on and do the pairwise alignment (with the first a and b variables) and then print some text to stdout.
Any ideas?
Python's conditional (aka ternary) expressions can one-line this for you. They're often criticized for lack of readability, but I think this example reads well enough.
a = fasta1[int(l1)] if int(l1) < len(fasta1) else "GGG"
You don't need continue, because it will skip that iteration of the loop. Consider the following:
for l1, l2 in zip(open('file1.list'), open ('file2.list')):
a = 'GGG'
b = 'CCC'
try:
a = fasta1[int(l1)]
b = fasta2[int(l2)]
except IndexError:
pass

How to reduce elif statements

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!

Categories