Let's make some of your code a little more "Pythonic" first. You wrote:
calcInputs = {}
def fetch(entries):
for entry in entries:
field = entry[0]
text = entry[1].get() # User input for each textbox
print('%s: %s' % (field, text)) # Print to stdout with name
if len(text) == 0:
pass # Don't update dictionary with nulls
else:
calcInputs.update({field:text}) # name : value updated to dictionary
This has the problem that calcInputs
is going to be persistent - that is, it will stay around until the next cycle (assuming there are multiple cycles) and so might keep data around from one time to the next. Let's initialize that empty dictionary inside the function, so we always start with a clean slate. (Note: if the entry box keeps its value from cycle to cycle, that's okay with me - the user can see it and clean it if she wants.)
def fetch(entries):
inputs = {}
This next bit seems okay, although I'm not familiar with TkInter under Python:
for entry in entries:
field = entry[0]
text = entry[1].get()
This is obviously debug code - keep it until you're happy.
print('%s: %s' % (field, text)) # Print to stdout with name
The next part is "just wrong." It looks like you're coming from Java - which is a great language to come from. But we can do things a little cleaner because of "truthiness" and syntactic sugar. In Python, strings are "true" if they aren't empty, and dictionaries can be indexed using dict[key]
notation:
if text:
inputs[field] = text
And that's it. But since we're not using a global variable, let's go ahead and return the result:
return inputs
Now you can call fetch, and use the result. Or, you could reassign the result to a global, if you like:
global calcInputs
calcInputs = inputs # instead of return inputs
Once you have the inputs, go ahead and process them. You have a problem in that you don't actually know which inputs you've been given. One easy way is just a series of if/then statements involving two values, which we can make easier by defining some constants (so as not to have to type quote marks all the time):
KW = 'kW'
PF = 'PF'
THETA = 'Theta'
:
calcInputs = fetch(entries) # Or however you choose to init calcInputs
if KW in calcInputs and PF in calcInputs:
triangle_from_KWPF(calcInputs)
elif KW in calcInputs and THETA in calcInputs:
triangle_from_KWTHETA(calcInputs)
elif ...
:
else:
report_error("You didn't provide enough inputs! I need at least 2!")
Python's in
operator works for dictionaries and sets as a key- or membership test, for strings as a substring search, and lists as a linear scan.
This approach is the binary style sequence that @Alden describes, with everything spelled out.
Another way would be to create a hashable object that encodes your given parameters, and use a dictionary to dispatch them:
given_keys = []
for key in sorted(fields):
if key in calcInputs:
given_keys.append(key)
if len(given_keys) == 2:
break
else: # Fell through
report_error("You didn't provide enough inputs! I need at least 2!")
# given_keys has 2 field-names in it. Concatenate them.
calc_key = '_'.join(given_keys)
# calc_key looks like "KW_Theta"
dispatch = { # dictionary: string -> function
'KW_Theta' : triangle_from_KW_Theta,
'KW_PF' : triangle_from_KW_PF,
# etc....
}
calc_function = dispatch[calc_key]
calc_function(calcInputs)
Note: for...else
is a valid Python form. It runs the else
clause when the for loop exhausts its iterable. So it is pretty much tailor-made for a block with a break statement in the middle.