Should I use f-string when writing with eval() - python-3.x

So recently I learned that eval() is a surprising function that can turn a string into a code command, it could be quite useful when writing a function where an argument is a string of a function's name.
But I wonder what is more pythonic way of using it.
Example:
a = [1,2,3,1,2,3,4,1,2,5,6,7]
b = 'count'
target = 2
# regular way
print(a.count(target)) # >>> 3
I tried to write with f-string, which it would work:
print(eval(f'{a}' + '.' + b + f'({target})')) # >>> 3
What amazed me is that it will work even if I don't use f-string:
print(eval('a' + '.' + b + '(target)')) # >>> 3
This is now a little questioning to me, because without f-string, 'a' can be confusing, it won't be easy to tell if this is just a string or a variable pretending to be a string.
Not sure how you guys think about this? Which one is more pythonic to you?
Thanks!

As people have mentioned in the comments, eval is dangerous (Alexander Huszagh) and rarely necessary.
However, you seem to have a problem with f-strings.
Before 3.6, there were two ways of constructing strings:
'a' + '.' + b + '(target)'
and
'{}.{}({})'.format(a, b, target)
With your values for a, b, and target, they both evaluate to: '[1,2,3,1,2,3,4,1,2,5,6,7].count(2)'
When you have several variables, the first option is cluttered with pluses and quotes, while the second one has the readability problem; which set of {} matches which variable (or expression).
A variant of the second way is to put names in the {} and refer to those names in format:
'{a}.{b}({target})'.format(a=a, b=b, target=target)
This makes the .format version more readable, but very verbose.
With the introduction of f-strings, we now include expressions inside the {}, similar to the named version of .format, but without the .format(...) part:
f'{a}.{b}({target})'
F-strings are a clear improvement on both + and .format version in readability and maintainability.
The way you are using f-strings, while technically correct, is not pytonic:
f'{a}' + '.' + b + f'({target})'
It seems you basically using f'{a}' as alternative to str(a).
To summarize, f'{a}' + '.' + b + f'({target})' can be simplified as f'{a}.{b}({target})'

Related

Python ord() and chr()

I have:
txt = input('What is your sentence? ')
list = [0]*128
for x in txt:
list[ord(x)] += 1
for x in list:
if x >= 1:
print(chr(list.index(x)) * x)
As per my understanding this should just output every letter in a sentence like:
))
111
3333
etc.
For the string "aB)a2a2a2)" the output is correct:
))
222
B
aaaa
For the string "aB)a2a2a2" the output is wrong:
)
222
)
aaaa
I feel like all my bases are covered but I'm not sure what's wrong with this code.
When you do list.index(x), you're searching the list for the first index that value appears. That's not actually what you want though, you want the specific index of the value you just read, even if the same value occurs somewhere else earlier in the list too.
The best way to get indexes along side values from a sequence is with enuemerate:
for i, x in enumerate(list):
if x >= 1:
print(chr(i) * x)
That should get you the output you want, but there are several other things that would make your code easier to read and understand. First of all, using list as a variable name is a very bad idea, as that will shadow the builtin list type's name in your namespace. That makes it very confusing for anyone reading your code, and you even confuse yourself if you want to use the normal list for some purpose and don't remember you've already used it for a variable of your own.
The other issue is also about variable names, but it's a bit more subtle. Your two loops both use a loop variable named x, but the meaning of the value is different each time. The first loop is over the characters in the input string, while the latter loop is over the counts of each character. Using meaningful variables would make things a lot clearer.
Here's a combination of all my suggested fixes together:
text = input('What is your sentence? ')
counts = [0]*128
for character in text:
counts[ord(character)] += 1
for index, count in enumerate(counts):
if count >= 1:
print(chr(index) * count)

How to replace several characters in a string using Julia

I'm essentially trying to solve this problem: http://rosalind.info/problems/revc/
I want to replace all occurrences of A, C, G, T with their compliments T, G, C, A .. in other words all A's will be replaced with T's, all C's with G's and etc.
I had previously used the replace() function to replace all occurrences of 'T' with 'U' and was hoping that the replace function would take a list of characters to replace with another list of characters but I haven't been able to make it work, so it might not have that functionality.
I know I could solve this easily using the BioJulia package and have done so using the following:
# creating complementary strand of DNA
# reverse the string
# find the complementary nucleotide
using Bio.Seq
s = dna"AAAACCCGGT"
t = reverse(complement(s))
println("$t")
But I'd like to not have to rely on the package.
Here's the code I have so far, if someone could steer me in the right direction that'd be great.
# creating complementary strand of DNA
# reverse the string
# find the complementary nucleotide
s = open("nt.txt") # open file containing sequence
t = reverse(s) # reverse the sequence
final = replace(t, r'[ACGT]', '[TGCA]') # this is probably incorrect
# replace characters ACGT with TGCA
println("$final")
It seems that replace doesn't yet do translations quite like, say, tr in Bash. So instead, here are couple of approaches using a dictionary mapping instead (the BioJulia package also appears to make similar use of dictionaries):
compliments = Dict('A' => 'T', 'C' => 'G', 'G' => 'C', 'T' => 'A')
Then if str = "AAAACCCGGT", you could use join like this:
julia> join([compliments[c] for c in str])
"TTTTGGGCCA"
Another approach could be to use a function and map:
function translate(c)
compliments[c]
end
Then:
julia> map(translate, str)
"TTTTGGGCCA"
Strings are iterable objects in Julia; each of these approaches reads one character in turn, c, and passes it to the dictionary to get back the complimentary character. A new string is built up from these complimentary characters.
Julia's strings are also immutable: you can't swap characters around in place, rather you need to build a new string.

How can I write the following script in Python?

So the program that I wanna write is about adding two strings S1 and S2 who are made of int.
example: S1='129782004977', S2='754022234930', SUM='883804239907'
So far I've done this but still it has a problem because it does not rive me the whole SUM.
def addS1S2(S1,S2):
N=abs(len(S2)-len(S1))
if len(S1)<len(S2):
S1=N*'0'+S1
if len(S2)<len(S1):
S2=N*'0'+S2
#the first part was to make the two strings with the same len.
S=''
r=0
for i in range(len(S1)-1,-1,-1):
s=int(S1[i])+int(S2[i])+r
if s>9:
r=1
S=str(10-s)+S
if s<9:
r=0
S=str(s)+S
print(S)
if r==1:
S=str(r)+S
return S
This appears to be homework, so I will not give full code but just a few pointers.
There are three problems with your algorithm. If you fix those, then it should work.
10-s will give you negative numbers, thus all those - signs in the sum. Change it to s-10
You are missing all the 9s. Change if s<9: to if s<=9:, or even better, just else:
You should not add r to the string in every iteration, but just at the very end, after the loop.
Also, instead of using those convoluted if statements to check r and substract 10 from s you can just use division and modulo instead: r = s/10 and s = s%10, or just r, s = divmod(s, 10).
If this is not homework: Just use int(S1) + int(S2).

Convert a string to a set without splitting the characters

I have a quick question: a='Tom', a type of str. I want to make it into a set with one item. If I use the command b = set(a), I got a set with 3 items in it, which is set(['m',''T','o']). I want set(['Tom']). How could I get it? Thanks.
The set builtin makes sets out of iterables. Iterating over a string yields each character one-by-one, so wrap the string in some other iterable:
set(['Tom'])
set(('Tom',))
If you're used to the mathematical notation for sets, you can just use curly braces (don't get it confused with the notation for dictionaries):
{'Tom'}
{'Tom', 'Bob'}
The resulting sets are equivalent
>>> {'Tom'} == set(['Tom']) == set(('Tom',))
True
set(['Tom'])
You just answered your own question (give list, instead of string).
Like this:
a = "Tom"
b = set([a])

perl interpolate code

I know in perl you can interpolate scalars by simply doing this:
"This is my $string"
However, I'm wondering if there is a way where I can interpolate actual perl code to be evaluated? An idea of what I want can be seen with ruby strings:
"5 + 4 = #{5 + 4}"
And it will evaluate whatever is in between the {}.
Does anyone know of a way to do this in perl? Thanks!
You can use the following trick:
"5 + 4 = #{[ 5 + 4 ]}"
Alternatively, you can use sprintf:
sprintf("5 + 4 = %d", 5 + 4);
Either of these yields the desired string. Arguably, sprintf is safer than the first one, as you can restrict the type of the interpolated value somewhat. The first one is closer in spirit to what you desire, however.
Further reading:
Why does Perl evaluate code in ${…} during string interpolation?
If you want to interpolate computations in string, you can do 3 things:
Use #{[]}. Inside the third brackets, place whatever expression you want.
Use ${\ do {}}. Place your expression within the 2nd braces.
Use a simple string concatenation: $targetstring = "$string1".func()."$string2", where func() will contain the dynamic content.
print "5 + 4 = ", 5 + 4;
Simply move it outside the quotes. Is there a point in forcing it to be within the quotes?
You can do a bit more formatting with printf, e.g.:
printf "5 + 4 = %s\n", 5 + 4;
You can use eval:
eval('$a = 4 + 5');
Mind you, eval should be used sparingly, it is pretty unsafe.

Resources