f-string formula inside curly brackets not working - python

I am on Python 3.7.
My code on line 3 works fine, however when I insert the underlying formula into line 4, my code returns the error:
SyntaxError: f-string: mismatched '(', '{', or '['
(the error points to the first '(' in line 4.
My code is:
cheapest_plan_point = 3122.54
phrase = format(round(cheapest_plan_point), ",")
print(f"1: {phrase}")
print(f"2: {format(round(cheapest_plan_point), ",")}")
I can't figure out what is wrong with line 4.

You used " quotes inside a "..." delimited string.
Python sees:
print(f"2: {format(round(cheapest_plan_point), "
,
")}")
so the )} is a new, separate string.
Use different delimiters:
print(f"2: {format(round(cheapest_plan_point), ',')}")
However, you don't need to use format() here. In an f-string, you already are formatting each interpolated value! Just add :, to apply the formatting instruction directly to the round() result:
print(f"2: {round(cheapest_plan_point):,}")
The format {expression:formatting_spec} applies formatting_spec to the outcome of expression, just as if you used {format(expression, 'formatting_spec')}, but without having to call format() and without having to put the formatting_spec part in quotes.

Related

Formatting while using "=" syntax in f-string python

If there is a variable var=0.00012646547, and it is being printed using the "=" syntax feature provided by f-string as
print(f'{var=}')
, is there a way to format the output which would provide a similar result as the following code ?
print('var\t=\t{0:.3e}'.format(var))
Naturally print(f'{var\t=%.3e}') doesnot work as it is messing with the f-string syntax
You are probably looking for this: print(f'var\t=\t{var:.3e}')
This will print out the value of var in scientific notation with three digits following the decimal point. \t is for inserting tabs for formatting.

How to pass newline characters in MEL variables to Python

I have tested the following code. It works fine.
string $testString = "test";
python("exec(\'with open(\\\'C:/Users/username/Desktop/testString.txt\\\', \\\'w\\\') as f:\\n\t\f.write(\\\'"+$testString+"\\\')\')");
Similarly, I can use Python to write a variable that contains a newline character, as shown below.
testString = "test\ntest\n"
with open('C:/Users/username/Desktop/testString.txt', 'w') as f:
f.write(testString)
However, when I tested the following code, I got an error.
string $testString = "test\ntest\n";
python("exec(\'with open(\\\'C:/Users/username/Desktop/testString.txt\\\', \\\'w\\\') as f:\\n\t\f.write(\\\'"+$testString+"\\\')\')");
error message is below:
# Error: line 2: EOL while scanning string literal #
I want to use a combination of MEL and Python to output a multi-line string to a text file. If possible, I would like to achieve this by changing only the python code, without changing the contents of the MEL variables.
How can I do this?
My environment is Maya2020 + Python2.
However, I get the exact same error with Maya2022 + Python3.
You need to escape the "\" symbol in your string several times (for MEL, for Python and for exec):
string $testString = "test\\\\ntest\\\\n";
python("exec(\'with open(\\\'C:/Users/username/Desktop/testString.txt\\\', \\\'w\\\') as f:\\n\t\f.write(\\\'"+$testString+"\\\')\')");
Or if you wish to leave your string intact use encodeString:
string $testString = "test\ntest\n";
python("exec(\'with open(\\\'C:/Users/username/Desktop/testString.txt\\\', \\\'w\\\') as f:\\n\t\f.write(\\\'"+ encodeString(encodeString($testString)) + "\\\')\')");
By the way, you don't need to use exec. This way you'll simplify the escaping quite a lot:
string $testString = "some test\ntest\n";
python("with open('C:/Users/username/Desktop/testString.txt', 'w') as f:\n\tf.write('"+ encodeString($testString) + "')");
Another option would be using MEL for file output:
string $testString = "test\ntest\n";
$file_id = `fopen "C:/Users/username/Desktop/testString.txt" "w"`;
fprint $file_id $testString;
fclose $file_id;

Remove "." and "\" from a string

my project is to capture a log number from Google Sheet using gspread module. But now the problem is that the log number captured is in the form of string ".\1300". I only want the number in the string but I could not remove it using the below code.
Tried using .replace() function to replace "\" with "" but failed.
a='.\1362'
a.replace('\\',"")
Should obtain the string "1362" without the symbol.
But the result obtained is ".^2"
The problem is that \136 has special meaning (similar to \n for newline, \t for tab, etc). Seemingly it represents ^.
Check out the following example:
a = '.\1362'
a = a.replace('\\',"")
print(a)
b = r'.\1362'
b = b.replace('\\',"")
print(b)
Produces
.^2
.\1362
Now, if your Google Sheets module sends .\1362 instead of .\\1362, if is very likely because you are in fact supposed to receive .^2. Or, there's a problem with your character encoding somewhere along the way.
The r modifier I put on the b variable means raw string, meaning Python will not interpret backlashes and leave your string alone. This is only really useful when typing the strings in manually, but you could perhaps try:
a = r'{}'.format(yourStringFromGoogle)
Edit: As pointed out in the comments, the original code did in fact discard the result of the .replace() method. I've updated the code, but please note that the string interpolation issue remains the same.
When you do a='.\1362', a will only have three bytes:
a = '.\1362'`
print(len(a)) # => 3
That is because \132 represents a single character. If you want to create a six byte string with a dot, a slash, and the digits 1362, you either need to escape the backslash, or create a raw string:
a = r'.\1362'
print(len(a)) # => 6
In either case, calling replace on a string will not replace the characters in that string. a will still be what it was before calling replace. Instead, replace returns a new string:
a = r'.\1362'
b = a.replace('\\', '')
print(a) # => .\1362
print(b) # => .1362
So, if you want to replace characters, calling replace is the way to do it, but you've got to save the result in a new variable or overwrite the old.
See String and Bytes literals in the official python documentation for more information.
Your string should contains 2 backslashes like this .\\1362 or use r'.\1362' (which is declaring the string as raw and then it will be converted to normal during compile time). If there is only one backslash, Python will understand that \136 mean ^ as you can see (ref: link)
Whats happening here is that \1362 is being encoded as ^2 because of the backslash, so you need to make the string raw before you're able to use it, you can do this by doing
a = r'{}'.format(rawInputString)
or if you're on python3.6+ you can do
a = rf'{rawInputString}'

How can I specify a variable as the first argument in re.sub

I only started python recently and have never written any code before. I used a regular expression to match a string in the input file (which was successful) but I am really struggling to find a way to replace that string in the file with another using a regular expression.
with open( fileToSearch, "r+" ) as file:
for line in fileinput.input( fileToSearch ):
string4=line
result1 = re.search(r'(KNOWLEDGECENTER\/.*?\/)' + re.escape(taxonomy), string4)
print (result1)
result2 = re.sub(result1, r'(KNOWLEDGECENTER\/\t(\1)\/\)' + taxonomy, string4)
print (result2)
file.write(result2)
I expected that re.sub would replace the string in the result1 variable with the replacement string but instead, I am getting the following error:
raise TypeError, "first argument must be string or compiled pattern"
TypeError: first argument must be string or compiled pattern
If I put the result1 variable in quotes in the re.sub statement, as shown below, I don't get an error but the input file doesn't get updated with the replacement string
result2 = re.sub('result1', r'(KNOWLEDGECENTER\/\t(\1)\/\)' +
taxonomy, string4)
re.search code appears to work as print (result1) returns: <_sre.SRE_Match object at 0x02A120E0> for each line in the input file
Since re.sub itself can perform a search, you don't need a separate call to re.search. In fact, you will lose the capture group in the regex for your call to re.search in the resulting match so the backreference in the replacement string in your call to re.sub won't be able to refer to anything. Combine to two calls and it will work (the below example code assumes that all you want to do is to add a tab after KNOWLEDGECENTER/:
for line in fileinput.input(fileToSearch):
result = re.sub('(KNOWLEDGECENTER/)(.*?/' + re.escape(taxonomy) + ')', r'\1\t\2', line)
file.write(result)
search returns an object (MatchObject) with various attributes related to regex match, not a string or compiled pattern hence the error. Maybe what you want is re.sub(results1.group(0), ...)
(By the way, you have python 2.7 as keyword. If that's the version you are using consider upgrading to python 3 instead)

The last line of this python program uses both " and ' but I don't know why

Ok on this link it shows the last line of output that has ' around everything except the third sentence and I do not know why. This bothered me at the beginning and thought it was just a weird mistake but its on the "extra credit" so now I am even more curious.
This is because the %r formatter prints the argument in the form you may use in source code, which, for strings, means that it is quote-delimited and escaped. For boolean values, this is just True or False. To print the string as it is, use %s instead.
>>> print '%s' % '"Hello, you\'re"'
"Hello, you're"
>>> print '%r' % '"Hello, you\'re"'
'"Hello, you\'re"'
python's repr() function, which is invoked by interpolating the %r formatting directive, has the approximate effect of printing objects the way they would appear in source code.
There are several ways to format strings in python source, using single or double quotes, with backslash escapes or as raw strings, as simple, single line strings or multi line strings (in any combination). Python picks only two ways to format strings, as single or double quoted, single line strings with escapes instead of raw.
Python makes a crude attempt at picking a minimal format, with a slight bias in favor of the single quote version (since that would be one fewer keystrokes on most keyboards).
The rules are very simple. If a string contains a single quote, but no double quotes, python prints the string as it would appear in python source if it were double quoted, Otherwise it uses single quotes.
Some examples to illustrate. Note for simplicity all of the inputs use triple quotes to avoid backslash escapes.
>>> ''' Hello world '''
' Hello world '
>>> ''' "Hello world," he said. '''
' "Hello world," he said. '
>>> ''' You don't say? '''
" You don't say? "
>>> ''' "Can't we all just get along?" '''
' "Can\'t we all just get along?" '
>>>

Categories