Reputation: 1294
My current code uses tenary assignments One line if-condition-assignment, but with more verbose identifyers it is easily passing line length limits.
Since I am not yet into pythonic coding, I would be glad to see some refactoring suggestions.
for label in range(num_labels):
d_tresh = drop_treshold[label] if type(drop_treshold) == numpy.ndarray) else drop_treshold
r_tresh1 = relabel_treshold1[label] if type(relabel_treshold1) == numpy.ndarray else relabel_treshold1
r_tresh2 = relabel_treshold2[label] if type(relabel_treshold2) == numpy.ndarray else relabel_treshold2
Using locally short variable names seems part of solution, but I like to have more explanatory function arguments. Hm. So dramatically shortening function argument names results in (for me) unreadable code.
for l in range(n_labels):
t0 = d_t[l] if type(d_t) == numpy.ndarray) else d_t
t1 = r_t1[l] if type(r_t1) == numpy.ndarray else r_t1
t2 = r_t2[l] if type(r_t2) == numpy.ndarray else r_t1
So shall I resort to multi line if - else assignments? It will stretch and bloat the simple logic dramatically.
for label in range(num_labels):
if type(drop_treshold) == numpy.ndarray):
d_tresh = drop_treshold[label]
else:
d_tresh = drop_treshold
if type(relabel_treshold1) == numpy.ndarray:
r_tresh1 = relabel_treshold1[label]
else:
d_tresh = relabel_treshold1
if type(relabel_treshold2) == numpy.ndarray:
r_tresh2 = relabel_treshold2[label]
else:
d_tresh = relabel_treshold2
(Surely I (sh/)could also refactor the whole code around the shown example... This example snippet comes from function with arguments, which could be scalar float/int or 1D numpy.array. If it is an array it will apply each item to each label, just being plain scalar it will apply it globally to all labels) But here again how is the pythonic way? When to start to refactor more exhaustively and when to stay put - because it works?
Upvotes: 1
Views: 135
Reputation: 1121834
The issue here is that you are repeating yourself for each variable; indexing if the object is an array, otherwise using the object directly. I'd use a utility function here:
def threshold_label(ob, i):
# the threshold label can be a scalar or an array
return ob[i] if isinstance(ob, numpy.ndarray) else ob
for label in range(num_labels):
d_tresh = threshold(drop_treshold, label)
r_tresh1 = threshold(relabel_treshold1, label)
r_tresh2 = threshold(relabel_threshold2, label)
Note that I used isinstance()
to test for the type of each object, see What are the differences between type() and isinstance()?
Another option is to not test for arrays each iteration. Test once, and if it is not an array, turn the scalar float or int value into a sequence of the expected length:
# turn scalar labels into sequences for easy iteration
if not isinstance(drop_threshold, numpy.ndarray):
drop_threshold = [drop_threshold] * num_labels
if not isinstance(relabel_treshold1, numpy.ndarray):
relabel_treshold1 = [relabel_treshold1] * num_labels
if not isinstance(drop_threshold, numpy.ndarray):
relabel_treshold2 = [relabel_treshold2] * num_labels
or, again, with a helper function:
def ensure_sequence(ob, cnt):
# turn a scalar label value into a sequence if needed
return [ob] * cnt if not isinstance(ob, numpy.ndarray) else ob
drop_threshold = ensure_sequence(drop_threshold, num_labels)
relabel_treshold1 = ensure_sequence(relabel_treshold1, num_labels)
relabel_treshold2 = ensure_sequence(relabel_treshold2, num_labels)
at which point you can use zip()
to iterate:
labels = zip(drop_threshold, relabel_threshold1, relabel_threshold2)
for d_thresh, r_thresh1, r_thresh2 in labels:
# ...
Upvotes: 2