When to use %r instead of %s in Python? [duplicate] - python

This question already has answers here:
What is the meaning of %r?
(9 answers)
Closed 8 years ago.
On Learn Python the Hard Way page 21, I see this code example:
x = "There are %d types of people." % 10
...
print "I said: %r." % x
Why is %r used here instead of %s? When would you use %r, and when would you use %s?

The %s specifier converts the object using str(), and %r converts it using repr().
For some objects such as integers, they yield the same result, but repr() is special in that (for types where this is possible) it conventionally returns a result that is valid Python syntax, which could be used to unambiguously recreate the object it represents.
Here's an example, using a date:
>>> import datetime
>>> d = datetime.date.today()
>>> str(d)
'2011-05-14'
>>> repr(d)
'datetime.date(2011, 5, 14)'
Types for which repr() doesn't produce Python syntax include those that point to external resources such as a file, which you can't guarantee to recreate in a different context.

Use the %r for debugging, since it displays the "raw" data of the variable,
but the others are used for displaying to users.
That's how %r formatting works; it prints it the way you wrote it (or close to it). It's the "raw" format for debugging. Here \n used to display to users doesn't work. %r shows the representation if the raw data of the variable.
months = "\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug"
print "Here are the months: %r" % months
Output:
Here are the months: '\nJan\nFeb\nMar\nApr\nMay\nJun\nJul\nAug'
Check this example from Learn Python the Hard Way.

%r shows with quotes:
It will be like:
I said: 'There are 10 types of people.'.
If you had used %s it would have been:
I said: There are 10 types of people..

This is a version of Ben James's answer, above:
>>> import datetime
>>> x = datetime.date.today()
>>> print x
2013-01-11
>>>
>>>
>>> print "Today's date is %s ..." % x
Today's date is 2013-01-11 ...
>>>
>>> print "Today's date is %r ..." % x
Today's date is datetime.date(2013, 1, 11) ...
>>>
When I ran this, it helped me see the usefulness of %r.

Related

What's the difference between f"{x}" and "{}".format(x) in python?

I'm new to python, and I just want to know the difference between those examples.
Does it differ when it comes to the execution speed?
When do I use one of them instead of the other?
x: int = 64
print(f"Your Number is {x}")
and
x: int = 64
txt = "Your Number is {}"
print(txt.format(x))
Thank you in advance!
There is no difference, technically speaking. The f-string format is recommended because it is more recent: it was introduced in Python 3.6. RealPython explains that f-strings are faster than str.format().
With f-strings the syntax is less verbose. Suppose you have the following variables:
first_name = "Eric"
last_name = "Idle"
age = 74
profession = "comedian"
affiliation = "Monty Python"
This is how you would format a str.format() statement.
print(("Hello, {name} {surname}. You are {age}. " +
"You are a {profession}. You were a member of {affiliation}.") \
.format(name=first_name, surname=last_name, age=age,\
profession=profession, affiliation=affiliation))
With formatting strings, it is considerably shortened:
print(f"Hello {first_name} {last_name}. You are {age}" +
f"You are a {profession}. You were a member of {affiliation}.")
Not only that: formatting strings offer a lot of nifty tricks, because they are evaluated at runtime:
>>> name="elvis" # note it is lowercase
>>> print(f"WOW THAT IS {name.upper()}")
'WOW THAT IS ELVIS'
This can be done inside a str.format(...) statement too, but f-strings make it cleaner and less cumbersome. Plus, you can also specify formatting inside the curly braces:
>>> value=123
>>> print(f"{value=}")
'value = 123'
Which normally you should have written as print("value = {number}".format(number=value)). Also, you can evaluate expressions:
>>> print(f"{value % 2 =}")
'value % 2 = 1`
And also format numbers:
>>> other_value = 123.456
>>> print(f"{other_value:.2f}") # will just print up to the second digit
'123.45'
And dates:
>>> from datetime.datetime import now
>>> print(f"{now=:%Y-%m-%d}")
'now=2022-02-02'
Python f-strings were added in 3.6. Therefore you should consider using format() if you need compatibility with earlier versions. Otherwise, use f-strings.
On macOS 12.1 running 3 GHz 10-Core Intel Xeon W and Python 3.10.2, f-strings are significantly faster (~60%)
Well, personally I use f string all the time, except when I'm dealing with floats or things like that, that require a specific formatting, that's when using .format is more suitable.
But if you are not dealing with text that require a specific formatting you should use f string, its easier to read.

Python "input expected at most 1 arguments, got 3"

I have seen loads of answers that say to use {} or str() + to make the input() only get given 1 argument.
But what parts of the input need to go with those? This is my code
name.append(input("What is their name"))
score.append(input("What did", name[x], "score"))
I'm pretty sure the 3 arguments are the "what did", "name[]x" and "score"
How would I make these one argument while keeping the same order and meaning?
You can format the string so that you only pass 1 argument:
score.append(input("What did %s score" % name[x]))
However if you want to add multiple arguments do this:
score.append(input("%s scored %d points!" % (name[x], points)))
You are adding three arguments in total while the function expects only one so pass one argument only:
name.append(input("What is their name"))
score.append(input("What did %s score" % name[x]))
The % syntax is the old syntax. Try to learn the new syntax as well
score.append(input("What did {} score".format(name[x])))
This website has some good breakdowns of common usages between the old and the new: https://pyformat.info/

Writing a pickle.dumps output to a file

I have the following code:
some_dict = {'a':0, 'b':1}
line = "some_dict_b = %s\n" % pickle.dumps(some_dict,2)
exec(line)
decoded_dict = pickle.loads(some_dict_b)
decoded_dict == some_dict
In python 3 this code prints True. In python 2 (2.7.8) I get an error in the exec line. I know dumps returns str in 2.7 while it returns a byte-stream in 3.
I am writing a program that parses data from an input file then creates certain memory objects and should write out a python script that uses these objects. I write these objects in the script file using pickle.dumps() and inserting it into a variable declaration line as per the idea sketched above. But I need to be able to run this code in python 2.
I did notice that in python 3 the line variable gets each backslash properly escaped and a type:
>>> line
"some_dict_b = b'\\x80\\x02...
while in python 2 I get:
>>> line
'some_dict_b = \x80\x02...
The Python 3 bytes type doesn't have a string represention, so when converted to a string with %s, the object representation is used instead. If you wanted to produce Python-compatible syntax from objects, you can use the %r formatter instead, to just use the representation directly.
In Python 2:
>>> import pickle
>>> some_dict = {'a':0, 'b':1}
>>> p = pickle.dumps(some_dict, 2)
>>> print 'string: %s\nrepresentation: %r' % (p, p)
string: ?}q(UaqKUbqKu.
representation: '\x80\x02}q\x00(U\x01aq\x01K\x00U\x01bq\x02K\x01u.'
In Python 3:
>>> import pickle
>>> some_dict = {'a':0, 'b':1}
>>> p = pickle.dumps(some_dict, 2)
>>> print('string: %s\nrepresentation: %r' % (p, p))
string: b'\x80\x02}q\x00(X\x01\x00\x00\x00bq\x01K\x01X\x01\x00\x00\x00aq\x02K\x00u.'
representation: b'\x80\x02}q\x00(X\x01\x00\x00\x00bq\x01K\x01X\x01\x00\x00\x00aq\x02K\x00u.'
Object representations (the output of the repr() function, which uses the object.__repr__ special method) generally will attempt to provide you with a representation that can be pasted back into a Python script or interactive prompt to recreate the same value.
From the documentation for repr():
For many types, this function makes an attempt to return a string that would yield an object with the same value when passed to eval(), otherwise the representation is a string enclosed in angle brackets that contains the name of the type of the object together with additional information often including the name and address of the object.
None of this is specific to pickle, really.
Whenever you think "I use exec", think again. You don't. Instead of evaluating data like this, store the contents of the data inside a dict itself.
Then, assign the data explicit to the variable.
some_dict = {'a':0, 'b':1}
line = pickle.dumps(some_dict)
decoded_dict = pickle.loads(line)
decoded_dict == some_dict
You can call repr on the string or bytes object before inserting them into the line.
# Python 2
>>> 'some_dict = %s' % repr(pickle.dumps(d))
'some_dict = "(dp0\\nS\'a\'\\np1\\nI12\\nsS\'b\'\\np2\\nI24\\ns."'
# Python 3
>>> 'some_dict = %s' % repr(pickle.dumps(d))
"some_dict = b'\\x80\\x03}q\\x00(X\\x01\\x00\\x00\\x00bq\\x01K\\x18X\\x01\\x00\\x00\\x00aq\\x02K\\x0cu.'"
Or use the format method, using !r to automatically call repr:
>>> 'some_dict = {!r}'.format(pickle.dumps(d))
"some_dict = b'\\x80\\x03}q\\x00(X\\x01\\x00\\x00\\x00bq\\x01K\\x18X\\x01\\x00\\x00\\x00aq\\x02K\\x0cu.'"
(Also works in python 2)

how % applies to this method in Python?

From my studying of python, I've found two uses for %. It can be used as what's called a modulo, meaning it will divide the value to the left of it and the value to the right of it and spit back the remainder.
The other use is a string formatter. So I can do something like 'Hi there %s' % name, where name is a list of names.
Also, if you see %% in a string formatting, that means a literal % will be entered.
Here is my question, I found this:
class FormatFormatStr(FormatObj):
def __init__(self, fmt):
self.fmt = fmt
def tostr(self, x):
if x is None: return 'None'
return self.fmt%self.toval(x)
What does return self.fmt%self.toval(x) mean? It can't be a modulo because toval will give me a string. It's not really a string formatter because there isn't another percent sign.
also, related to this:
def csvformat_factory(format):
format = copy.deepcopy(format)
if isinstance(format, FormatFloat):
format.scale = 1. # override scaling for storage
format.fmt = '%r'
return format
What does the percent mean in format.fmt = '%r' does this mean to insert a string a la repr()? Or does it mean insert what the variable r represents? r in this overall program also refers to a recarray.
Thanks everyone. Hope this makes sense =)
The string % operator is simpler than you are imagining. It takes a string on the left side, and a variety of things on the right side. The left side doesn't have to be a literal string, it can be a variable, or the result of another computation. Any expression that results in a string is valid for the left side of the %.
In your first example, self.fmt is a string. In order to be useful in this context, it should have a percent sign in it.
In your second example, format.fmt is being set to a string that would be useful as the left side of the %. In this case, "%r" means, insert the repr() of the value into the string, as you have said.
In
return self.fmt%self.toval(x)
self.fmt is a string, and that string presumably has a percent-sign placeholder in it.
%r in a format string is like %s but it prints the repr() of the string, so it'll have quotes and backslashes and all that.
% is just an operator which is just a method, and like any other method you can either pass in a literal value or a variable containing a value. In your examples they use a variable containing the format string.
def tostr(self, x):
if x is None: return 'None'
return self.fmt%self.toval(x)
The % in this is a string formatter, definitely. Pass the tostr method a formatter, eg "%s" or "%r" to see what happens
I think the '%r' in csvformat_factory is also a string formatter. '%r' means take the repr() which is a reasonable way to display something to a user. I imagine that format.fmt is used elsewhere format.fmt % somevalue.
The code:
return self.fmt % self.toval(x)
Is the "string formatting" use of the % operator, just like you suspected.
The class is handed format, which is a string containing the formatting, and when tostr(x) is called, it will return the string % x.
This is just like using % directly, only with saving the format string for later. In other words, instead of doing:
"I want to print the number: %n" % 20
What's happening is:
format_str = "I want to print the number: %n"
x = 20
print format_str % x
Which is exactly the same thing.
% has more than one use in string formatting. One use is in %s, %d, etc.
Another use is to separate 'string in which we use %d and %s' from int-value and string-value.
For example
'string in which we use %d and %s' % (17, 'blue')
would result in
'string in which we use 17 and blue'
we could store 'string in which we use %d and %s' in a variable,
a = 'string in which we use %d and %s'
then
a % (17, 'blue')
results in
'string in which we use 17 and blue'
In your example
self.fmt%self.toval(x)
self.fmt is similar to a above and self.toval(x) is (17, 'blue')

String formatting in Python version earlier than 2.6

When I run the following code in Python 2.5.2:
for x in range(1, 11):
print '{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)
I get:
Traceback (most recent call last):
File "<pyshell#9>", line 2, in <module>
print '{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x)
AttributeError: 'str' object has no attribute 'format'
I don't understand the problem.
From dir('hello') there is no format attribute.
How can I solve this?
The str.format method was introduced in Python 3.0, and backported to Python 2.6 and later.
Your example code seems to be written for Python 2.6 or later, where the str.format method was introduced.
For Python versions below 2.6, use the % operator to interpolate a sequence of values into a format string:
for x in range(1, 11):
print '%2d %3d %4d' % (x, x*x, x*x*x)
You should also be aware that this operator can interpolate by name from a mapping, instead of just positional arguments:
>>> "%(foo)s %(bar)d" % {'bar': 42, 'foo': "spam", 'baz': None}
'spam 42'
In combination with the fact that the built-in vars() function returns attributes of a namespace as a mapping, this can be very handy:
>>> bar = 42
>>> foo = "spam"
>>> baz = None
>>> "%(foo)s %(bar)d" % vars()
'spam 42'
I believe that is a Python 3.0 feature, although it is in version 2.6. But if you have a version of Python below that, that type of string formatting will not work.
If you are trying to print formatted strings in general, use Python's printf-style syntax through the % operator. For example:
print '%.2f' % some_var
Which Python version do you use?
Edit
For Python 2.5, use "x = %s" % (x) (for printing strings)
If you want to print other types, see here.
Although the existing answers describe the causes and point in the direction of a fix, none of them actually provide a solution that accomplishes what the question asks.
You have two options to solve the problem. The first is to upgrade to Python 2.6 or greater, which supports the format string construct.
The second option is to use the older string formatting with the % operator. The equivalent code of what you've presented would be as follows.
for x in range(1,11):
print '%2d %3d %4d' % (x, x*x, x*x*x)
This code snipped produces exactly the same output in Python 2.5 as your example code produces in Python 2.6 and greater.
Use this:
print "test some char {} and also number {}".format('a', 123)
result:
test some char a and also number 123

Categories

Resources