How can I insert for loops or if expressions inside an f-string?
I thought initially of doing something like this for if expressions:
f'{a:{"s" if CONDITION else "??"}}'
What I would like to do though is something like:
Example 1
f'{key: value\n for key, value in dict.items()}'
result:
if dict = {'a': 1, 'b': 2}
a: 1
b: 2
or Example 2
c = 'hello'
f'{c} {name if name else "unknown"}'
result:
if name exists, e.g. name = 'Mike'
hello Mike
otherwise
hello unknown
Can this be done and if yes how?
Both ternaries ("if expressions") and comprehensions ("for expressions") are allowed inside f-strings. However, they must be part of expressions that evaluate to strings. For example, key: value is a dict pair, and f"{key}: {value}" is required to produce a string.
>>> dct = {'a': 1, 'b': 2}
>>> newline = "\n" # \escapes are not allowed inside f-strings
>>> print(f'{newline.join(f"{key}: {value}" for key, value in dct.items())}')
a: 1
b: 2
Note that if the entire f-string is a single format expression, it is simpler to just evaluate the expression directly.
>>> print("\n".join(f"{key}: {value}" for key, value in dct.items())))
a: 1
b: 2
Expressions inside format strings still follow their regular semantics. For example, a ternary may test whether an existing name is true. It will fail if the name is not defined.
>>> c, name = "Hello", ""
>>> f'{c} {name if name else "unknown"}'
'Hello unknown'
>>> del name
>>> f'{c} {name if name else "unknown"}'
NameError: name 'name' is not defined
Related
I found similar question, but I'm not able to convert answer to match my needs.
(Find if value exists in multiple lists)
So, basicly, I have multiple lists, and I want to list all of them, which contain current user username.
import getpass
value = getpass.getuser()
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
#No idea how code below works
w = next(n for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), globals().items()) if value in v)
print(w)
If current user is user1, I want it to print rep_WOHTEL, rep_REPDAY and rep_ZARKGL. Code above print only ony of them.
How should I change this part of script, to print all I want?
Like I commented in the linked question, iterating through all of globals() or locals() is a bad idea. Store your lists together in a single dictionary or list, and iterate through that instead.
value = "user1"
named_lists = {
"WOHTEL": ['user1','user2','user3'],
"REPDAY": ['user4','user1','user3'],
"ZARKGL": ['user3','user1','user2'],
"WOHOPL": ['user3','user2','user5']
}
names = [name for name, seq in named_lists.items() if value in seq]
print(names)
Result:
['REPDAY', 'ZARKGL', 'WOHTEL']
Checking if value is in all global lists, and if true, print which list(s) contains the required value.
Code:
rep_WOHTEL = ['user1','user2','user3']
rep_REPDAY = ['user4','user1','user3']
rep_ZARKGL = ['user3','user1','user2']
rep_WOHOPL = ['user3','user2','user5']
value = 'user1'
x = globals().items()
for n,v in filter(lambda t: isinstance(t[1],list) and t[0].startswith('rep_'), x):
if value in v:
print(n)
Output:
rep_REPDAY
rep_ZARKGL
rep_WOHTEL
More info about the used functions:
globals()
dict.items()
filter()
isinstance()
startswith()
I'm writing some printouts for the debug mode of a script. Is there a compact way to print the names of those variables in a list that meet a condition?
specification_aw3 = 43534
specification_hg7 = 75445
specification_rt5 = 0
specification_nj8 = 5778
specification_lo4 = 34
specification_ee2 = 8785
specification_ma2 = 67
specification_pw1 = 1234
specification_mu6 = 0
specification_xu8 = 12465
specifications = [
specification_aw3,
specification_hg7,
specification_rt5,
specification_nj8,
specification_lo4,
specification_ee2,
specification_ma2,
specification_pw1,
specification_mu6,
specification_xu8
]
if any(specification == 0 for specification in specifications):
# magic code to print variables' names
# e.g. "variables equal to 0: \"specification_rt5\", \"specification_mu6\"
Just as 9000 suggests, it goes without saying that defining a dictionary is a rational approach for the minimal working example I have defined here. Please assume that this is not a feasible option for the existing code project and that I am looking for a quick, compact (plausibly ugly) bit of code to be used solely for debugging.
EDIT: illustration of something similar to what I want
So here's the beginnings of what I'm looking for:
print("specifications equal to zero:")
callers_local_objects = inspect.currentframe().f_back.f_locals.items()
for specification in [specification for specification in specifications if specification == 0]:
print([object_name for object_name, object_instance in callers_local_objects if object_instance is specification][0])
Basically, is there a compact way to do something like this?
I suggest that instead of a bunch of variables you use a dict:
specification = {
'aw3': 0,
'foo': 1,
'bar': 1.23,
# etc
}
You can access things by name like specification['aw3'].
Then you can find out names for which the value is 0:
zeroed = [name for (name, value) in specification.items() if value == 0]
In addition, since you mentioned printing the line would be:
for element in specification_dictionary:
print(element)
where you can combine it with a list comprehension as above for printing only the elements that meet your case. Element in this case only prints the variable name (key) if you want both the key and value just set it to use specification_dictionary.items(). Cheers.
>>> specification = { 'aw3': 0, 'foo': 1}
>>> for element in specification:
... print(element)
...
foo
aw3
>>> for (key, value) in specification.items():
... print(str(key) + " " + str(value))
...
foo 1
aw3 0
>>> for element in specification.items():
... print(element)
...
('foo', 1)
('aw3', 0)
how to extract the integers from the string(integers separated by space) and assign them to different variables.
eg.
Given string: "2 3 4 5"
assign: n=2, m=3, x=4, y=5
Something like (read comments):
>>> s = "2 3 4 5"
>>> s.split() # split string using spaces
['2', '3', '4', '5'] # it gives you list of number strings
>>> n, m, x, y = [int(i) for i in s.split()] # used `int()` for str --> int
>>> n # iterate over list and convert each number into int
2 # and use unpack to assign to variables
the number of values in your string might be variable. In this case you could assign the variables to a dictionnary as follows:
>>> s = "2 3 4 5"
>>> temp = [(count, int(value)) for count, value in enumerate(s.split(' '), 1)]
>>> vars = {}
>>> for count, value in temp:
... vars['var' + str(count)] = value
>>> vars
{'var4': 5, 'var1': 2, 'var3': 4, 'var2': 3}
>>> vars['var2']
3
If you really don't want a dictionnary, you could consider the following:
>>> temp = [(count, int(value)) for count, value in enumerate(s.split(' '), 1)]
>>> for count, value in temp:
... locals()['var{}'.format(count)] = value
>>> var2
3
locals()['var{}'.format(count)] = value will add a local variable named 'var{count}' and assign the value to it. locals()shows you the local variables and its values.
Remember: do this only if you really know what you are doing. Read please also the note on locals in the Python documentation: "The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter."
I'm trying to translate a single integer input to a multiple integer output, and am currently using the transtab function. For instance,
intab3 = "abcdefg"
outtab3 = "ABCDEFG"
trantab3 = maketrans(intab3, outtab3)
is the most basic version of what I'm doing. What I'd like to be able to do is have the input be a single letter and the output be multiple letters. So something like:
intab4 = "abc"
outtab = "yes,no,maybe"
but commas and quotation marks don't work.
It keeps saying :
ValueError: maketrans arguments must have same length
Is there a better function I should be using? Thanks,
You can use a dict here:
>>> dic = {"a":"yes", "b":"no", "c":"maybe"}
>>> strs = "abcd"
>>> "".join(dic.get(x,x) for x in strs)
'yesnomaybed'
In python3, the str.translate method was improved so this just works.
>>> intab4 = "abc"
>>> outtab = "yes,no,maybe"
>>> d = {ord(k): v for k, v in zip(intab4, outtab.split(','))}
>>> print(d)
{97: 'yes', 98: 'no', 99: 'maybe'}
>>> 'abcdefg'.translate(d)
'yesnomaybedefg'
I've read about LSH hashing and am wondering what is the best implementation to match strings within 1 character?
test = {'dog':1, 'cat': 2, 'eagle': 3}
test['dog']
>> 1
I would want to also return 1 if I lookup test['dogs'] or test['dogg']. I realize that it would also return 1 if I were to look up "log" or "cog", but I can write a method to exclude those results.
Also how can I further this method for general strings to return a match within X characters?
string1 = "brown dogs"
string2 = "brown doggie"
Assuming only string1 is stored in my dictionary, a lookup for string2 would return string1.
Thanks
Well, you can define the similarity between 2 strings by the length of the start they share in common (3 for doga and dogs, for instance). This is simplistic, but that could fit your needs.
With this assumption, you can define this:
>>> test = {'dog':1, 'cat': 2, 'eagle': 3}
>>> def same_start(s1, s2):
ret = 0
for i in range(min(len(s1), len(s2))):
if s1[i] != s2[i]:
break
ret += 1
return ret
>>> def closest_match(s):
return max(((k, v, same_start(k, s)) for k, v in test.iteritems()), key=lambda x: x[2])[1]
>>> closest_match('dogs') # matches dog
1
>>> closest_match('cogs') # matches cat
2
>>> closest_match('eaogs') # matches eagle
3
>>>
Maybe you could try using a Soundex function as your dictionary key?
Since your relation is not 1:1, maybe you could define your own dict type with redefined __getitem__ which could return a list of possible items. Here's what I mean:
class MyDict(dict):
def __getitem__(self, key):
l = []
for k, v in self.items():
if key.startswith(k): # or some other comparation method
l.append(v)
return l
This is just an idea, probably other dict methods should be redefined too in order to avoid possible errors or infinite loops. Also, #Emmanuel's answer could be very useful here if you want only one item returned instead of the list, and that way you wouldn't have to redefine everything.