1418

Python 2.6では、既存の演算子str.format()とは構文が少し異なるメソッドが導入されました。%どちらがより良いですか、そしてどのような状況のために?

Python 3.6では、構文を介して文字列リテラル(別名「f」文字列)の別の文字列フォーマット形式が導入されましたf"my string"。このフォーマットオプションは他のオプションよりも優れていますか?

  1. 以下はそれぞれの方法を使用し、同じ結果をもたらしますが、違いは何ですか?

     #!/usr/bin/python
     sub1 = "python string!"
     sub2 = "an arg"
    
     sub_a = "i am a %s" % sub1
     sub_b = "i am a {0}".format(sub1)
     sub_c = f"i am a {sub1}"
    
     arg_a = "with %(kwarg)s!" % {'kwarg':sub2}
     arg_b = "with {kwarg}!".format(kwarg=sub2)
     arg_c = f"with {sub2}!"
    
     print(sub_a)    # "i am a python string!"
     print(sub_b)    # "i am a python string!"
     print(sub_c)    # "i am a python string!"
    
     print(arg_a)    # "with an arg!"
     print(arg_b)    # "with an arg!"
     print(arg_c)    # "with an arg!"
    
  2. さらに、Pythonで文字列のフォーマットはいつ行われますか?たとえば、ログレベルがHIGHに設定されている場合でも、次の%操作を実行するためにヒットしますか?もしそうなら、これを回避する方法はありますか?

     log.debug("some debug info: %s" % some_info)
    
4

16 に答える 16

977

最初の質問に答えるには....format多くの点でより洗練されているようです。厄介なの%は、変数またはタプルをどのように取ることができるかということでもあります。次のことが常に機能すると思います。

"hi there %s" % name

それでも、nameたまたまである場合は(1, 2, 3)、をスローしTypeErrorます。常に印刷されることを保証するには、次のことを行う必要があります

"hi there %s" % (name,)   # supply the single argument as a single-item tuple

これはただ醜いです。.formatそれらの問題はありません。また、あなたが与えた2番目の例では、.format例ははるかにきれいに見えます。

なぜあなたはそれを使わないのですか?

  • それについて知らない(これを読む前の私)
  • Python2.5と互換性がある必要があります

2番目の質問に答えるために、文字列の書式設定は、他の操作と同時に、つまり文字列の書式設定式が評価されるときに行われます。また、Pythonは怠惰な言語ではないため、関数を呼び出す前に式を評価します。そのため、log.debugこの例では、式"some debug info: %s"%some_infoは最初に評価され"some debug info: roflcopters are active"、次にその文字列がに渡されlog.debug()ます。

于 2011-02-22T18:49:21.347 に答える
316

モジュロ演算子(%)ではできないこと、afaik:

tu = (12,45,22222,103,6)
print '{0} {2} {1} {2} {3} {2} {4} {2}'.format(*tu)

結果

12 22222 45 22222 103 22222 6 22222

非常に便利。

別のポイント:format()関数であるため、他の関数の引数として使用できます。

li = [12,45,78,784,2,69,1254,4785,984]
print map('the number is {}'.format,li)   

print

from datetime import datetime,timedelta

once_upon_a_time = datetime(2010, 7, 1, 12, 0, 0)
delta = timedelta(days=13, hours=8,  minutes=20)

gen =(once_upon_a_time +x*delta for x in xrange(20))

print '\n'.join(map('{:%Y-%m-%d %H:%M:%S}'.format, gen))

結果:

['the number is 12', 'the number is 45', 'the number is 78', 'the number is 784', 'the number is 2', 'the number is 69', 'the number is 1254', 'the number is 4785', 'the number is 984']

2010-07-01 12:00:00
2010-07-14 20:20:00
2010-07-28 04:40:00
2010-08-10 13:00:00
2010-08-23 21:20:00
2010-09-06 05:40:00
2010-09-19 14:00:00
2010-10-02 22:20:00
2010-10-16 06:40:00
2010-10-29 15:00:00
2010-11-11 23:20:00
2010-11-25 07:40:00
2010-12-08 16:00:00
2010-12-22 00:20:00
2011-01-04 08:40:00
2011-01-17 17:00:00
2011-01-31 01:20:00
2011-02-13 09:40:00
2011-02-26 18:00:00
2011-03-12 02:20:00
于 2011-06-13T20:20:32.467 に答える
156

Pythonのモジュールを使用していると仮定すると、自分でフォーマットを行うのではなくlogging、文字列のフォーマット引数を引数としてメソッドに渡すことができます。.debug()

log.debug("some debug info: %s", some_info)

これは、ロガーが実際に何かをログに記録しない限り、フォーマットを回避します。

于 2011-02-22T19:21:07.580 に答える
132

Python 3.6(2016)以降、f文字列を使用して変数を置き換えることができます。

>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'

f"プレフィックスに注意してください。Python 3.5以前でこれを試すと、が表示されますSyntaxError

https://docs.python.org/3.6/reference/lexical_analysis.html#f-stringsを参照してください

于 2016-04-15T11:12:07.080 に答える
63

PEP 3101%は、演算子をPython 3の新しい高度な文字列フォーマットに置き換えることを提案しています。これは、デフォルトになります。

于 2011-08-01T03:01:34.850 に答える
59

ただし、注意してください。既存のコードですべて%を置き換えようとすると、unicode_stringをエンコードしようとして失敗する可能性があるという、1つの問題が見つかりました。.format'{}'.format(unicode_string)

このPythonインタラクティブセッションログを見てください。

Python 2.7.2 (default, Aug 27 2012, 19:52:55) 
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'

sは単なる文字列(Python3では「バイト配列」と呼ばれます)でuあり、Unicode文字列(Python3では「文字列」と呼ばれます)です。

; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'

Unicodeオブジェクトをパラメータとして%演算子に指定すると、元の文字列がUnicodeでなくても、Unicode文字列が生成されます。

; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)

しかし、.format関数は「UnicodeEncodeError」を発生させます:

; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'

また、元の文字列がUnicodeの場合にのみ、Unicode引数で正常に機能します。

; '{}'.format(u'i')
'i'

または、引数文字列を文字列(いわゆる「バイト配列」)に変換できる場合

于 2012-09-03T18:15:42.977 に答える
46

%format私のテストよりも優れたパフォーマンスを提供します。

テストコード:

Python 2.7.2:

import timeit
print 'format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')")
print '%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')")

結果:

> format: 0.470329046249
> %: 0.357107877731

Python 3.5.2

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))

結果

> format: 0.5864730989560485
> %: 0.013593495357781649

Python2では違いはわずかですが、Python3では%よりもはるかに高速ですformat

サンプルコードを提供してくれた@ChrisCogdonに感謝します。

編集1:

2019年7月にPython3.7.2で再度テストされました。

結果:

> format: 0.86600608
> %: 0.630180146

大きな違いはありません。Pythonは徐々に改善されていると思います。

編集2:

誰かがコメントでpython3のf-stringについて言及した後、私はpython3.7.2で次のコードのテストを行いました。

import timeit
print('format:', timeit.timeit("'{}{}{}'.format(1, 1.23, 'hello')"))
print('%:', timeit.timeit("'%s%s%s' % (1, 1.23, 'hello')"))
print('f-string:', timeit.timeit("f'{1}{1.23}{\"hello\"}'"))

結果:

format: 0.8331376779999999
%: 0.6314778750000001
f-string: 0.766649943

f-stringはまだ遅いようです%が、より良いようですformat

于 2011-06-13T18:43:10.627 に答える
38

.format(回答には表示されない)さらに別の利点は、オブジェクトのプロパティを取得できることです。

In [12]: class A(object):
   ....:     def __init__(self, x, y):
   ....:         self.x = x
   ....:         self.y = y
   ....:         

In [13]: a = A(2,3)

In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'

または、キーワード引数として:

In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'

%私の知る限り、これは不可能です。

于 2014-12-04T18:33:46.877 に答える
33

今日私が発見したように、を介して文字列をフォーマットする古い方法は、Pythonの10進固定小数点および浮動小数点演算用のモジュールをそのままで%はサポートしていません。Decimal

例(Python 3.3.5を使用):

#!/usr/bin/env python3

from decimal import *

getcontext().prec = 50
d = Decimal('3.12375239e-24') # no magic number, I rather produced it by banging my head on my keyboard

print('%.50f' % d)
print('{0:.50f}'.format(d))

出力:

0.00000000000000000000000312375239000000009907464850 0.00000000000000000000000312375239000000000000000000

確かに回避策があるかもしれませんが、それでもformat()すぐにこの方法を使用することを検討するかもしれません。

于 2014-05-13T17:10:00.563 に答える
25

Python> = 3.6の場合、F文字列形式のリテラルが新しい友達になります。

よりシンプルでクリーン、そしてより良いパフォーマンスです。

In [1]: params=['Hello', 'adam', 42]

In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
于 2018-07-04T07:13:44.810 に答える
16

ちなみに、ロギングで新しいスタイルのフォーマットを使用するためにパフォーマンスを低下させる必要はありません。マジックメソッドを実装する、などlogging.debugに任意のオブジェクトを渡すことができます。ロギングモジュールは、メッセージオブジェクト(それが何であれ)を発行する必要があると判断すると、その前に呼び出します。したがって、次のようなことができます。logging.info__str__str(message_object)

import logging


class NewStyleLogMessage(object):
    def __init__(self, message, *args, **kwargs):
        self.message = message
        self.args = args
        self.kwargs = kwargs

    def __str__(self):
        args = (i() if callable(i) else i for i in self.args)
        kwargs = dict((k, v() if callable(v) else v) for k, v in self.kwargs.items())

        return self.message.format(*args, **kwargs)

N = NewStyleLogMessage

# Neither one of these messages are formatted (or calculated) until they're
# needed

# Emits "Lazily formatted log entry: 123 foo" in log
logging.debug(N('Lazily formatted log entry: {0} {keyword}', 123, keyword='foo'))


def expensive_func():
    # Do something that takes a long time...
    return 'foo'

# Emits "Expensive log entry: foo" in log
logging.debug(N('Expensive log entry: {keyword}', keyword=expensive_func))

これはすべてPython3のドキュメント(https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles)で説明されています。ただし、Python 2.6でも機能します(https://docs.python.org/2.6/library/logging.html#using-arbitrary-objects-as-messages)。

この手法を使用する利点の1つは、フォーマットスタイルに依存しないという事実以外に、expensive_func上記の関数などの遅延値を使用できることです。これにより、 https://docs.python.org/2.6/library/logging.html#optimizationのPythonドキュメントで提供されているアドバイスに代わるより洗練された方法が提供されます。

于 2014-08-21T18:00:48.120 に答える
12

役立つ可能性のある状況の1つ%は、正規表現をフォーマットする場合です。例えば、

'{type_names} [a-z]{2}'.format(type_names='triangle|square')

発生しIndexErrorます。この状況では、次を使用できます。

'%(type_names)s [a-z]{2}' % {'type_names': 'triangle|square'}

これにより、正規表現を。として記述しなくなり'{type_names} [a-z]{{2}}'ます。これは、2つの正規表現があり、一方がフォーマットなしで単独で使用されているが、両方の連結がフォーマットされている場合に役立ちます。

于 2015-04-09T20:41:40.623 に答える
8

バージョン3.6以降、次のようなfstringを使用できることを付け加えておきます。

foo = "john"
bar = "smith"
print(f"My name is {foo} {bar}")

与える

私の名前はジョン・スミスです

すべてが文字列に変換されます

mylist = ["foo", "bar"]
print(f"mylist = {mylist}")

結果:

mylist = ['foo'、'bar']

他のフォーマットメソッドのように、関数を渡すことができます

print(f'Hello, here is the date : {time.strftime("%d/%m/%Y")}')

たとえば与える

こんにちは、ここに日付があります:16/04/2018

于 2018-04-16T14:42:06.267 に答える
6

Python 3.6.7の比較:

#!/usr/bin/env python
import timeit

def time_it(fn):
    """
    Measure time of execution of a function
    """
    def wrapper(*args, **kwargs):
        t0 = timeit.default_timer()
        fn(*args, **kwargs)
        t1 = timeit.default_timer()
        print("{0:.10f} seconds".format(t1 - t0))
    return wrapper


@time_it
def new_new_format(s):
    print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")


@time_it
def new_format(s):
    print("new_format:", "{0} {1} {2} {3} {4}".format(*s))


@time_it
def old_format(s):
    print("old_format:", "%s %s %s %s %s" % s)


def main():
    samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),) 
    for s in samples:
        new_new_format(s)
        new_format(s)
        old_format(s)
        print("-----")


if __name__ == '__main__':
    main()

出力:

new_new_format: uno dos tres cuatro cinco
0.0000170280 seconds
new_format: uno dos tres cuatro cinco
0.0000046750 seconds
old_format: uno dos tres cuatro cinco
0.0000034820 seconds
-----
new_new_format: 1 2 3 4 5
0.0000043980 seconds
new_format: 1 2 3 4 5
0.0000062590 seconds
old_format: 1 2 3 4 5
0.0000041730 seconds
-----
new_new_format: 1.1 2.1 3.1 4.1 5.1
0.0000092650 seconds
new_format: 1.1 2.1 3.1 4.1 5.1
0.0000055340 seconds
old_format: 1.1 2.1 3.1 4.1 5.1
0.0000052130 seconds
-----
new_new_format: uno 2 3.14 cuatro 5.5
0.0000053380 seconds
new_format: uno 2 3.14 cuatro 5.5
0.0000047570 seconds
old_format: uno 2 3.14 cuatro 5.5
0.0000045320 seconds
-----
于 2019-02-05T09:56:38.557 に答える
5

Pythonバージョン>=3.6の場合(PEP 498を参照)

s1='albha'
s2='beta'

f'{s1}{s2:>10}'

#output
'albha      beta'
于 2018-02-14T22:42:32.920 に答える
3

ただし、中括弧をネストしている場合も、フォーマットでは機能しませんが、機能します%

例:

>>> '{{0}, {1}}'.format(1,2)
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    '{{0}, {1}}'.format(1,2)
ValueError: Single '}' encountered in format string
>>> '{%s, %s}'%(1,2)
'{1, 2}'
>>> 
于 2018-08-25T01:08:57.227 に答える