질문자 :NorthIsUp
Python 2.6 %
연산자와 약간 다른 구문으로 str.format()
어떤 상황이 더 낫습니까?
f"my string"
구문을 통해 문자열 리터럴(일명 "f" 문자열)의 또 다른 문자열 형식화 형식을 도입했습니다. 이 서식 옵션이 다른 것보다 낫습니까?
다음은 각각의 방법을 사용하고 동일한 결과를 가집니다. 그렇다면 차이점은 무엇입니까?
#!/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!"
또한 Python에서 문자열 형식 지정은 언제 발생합니까? 예를 들어, 내 로깅 수준이 HIGH로 설정되어 있으면 다음 %
작업을 수행할 때 여전히 적중을 합니까? 그렇다면 이를 피할 수 있는 방법이 있습니까?
log.debug("some debug info: %s" % some_info)
첫 번째 질문에 답하기 위해... .format
은 여러 면에서 더 정교해 보입니다. %
대한 성가신 점은 변수나 튜플을 취할 수 있다는 것입니다. 다음이 항상 작동한다고 생각할 수 있습니다.
"hi there %s" % name
그러나 name
이 (1, 2, 3)
이면 TypeError
합니다. 항상 인쇄되도록 하려면 다음을 수행해야 합니다.
"hi there %s" % (name,) # supply the single argument as a single-item tuple
그냥 못생긴 것입니다. .format
에는 이러한 문제가 없습니다. 또한 당신이 준 두 번째 예에서 .format
예가 훨씬 더 깔끔해 보입니다.
왜 사용하지 않겠습니까?
- 그것에 대해 알지 못함 (이 글을 읽기 전의 나)
- Python 2.5와 호환되어야 함
두 번째 질문에 답하기 위해 문자열 서식 지정은 문자열 서식 지정 표현식이 평가될 때 다른 작업과 동시에 발생합니다. 그리고 Python은 게으른 언어가 아니기 때문에 함수를 호출하기 전에 표현식을 평가하므로 log.debug
예제에서 "some debug info: %s"%some_info
은 먼저 "some debug info: roflcopters are active"
, 그러면 해당 문자열이 log.debug()
전달됩니다.
Claudiu모듈로 연산자( % )가 할 수 없는 것, 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
eyquemlogging
모듈을 사용하고 있다고 가정하면 직접 형식 지정을 수행하는 대신 문자열 형식 지정 인수를 .debug()
log.debug("some debug info: %s", some_info)
로거가 실제로 무언가를 기록하지 않는 한 서식 지정을 피합니다.
WooblePython 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 참조
Colonel PanicPEP 3101 %
연산자를 기본값이 되는 Python 3의 새로운 고급 문자열 형식으로 대체할 것을 제안합니다.
BrainStorm하지만 조심하세요. 방금 기존 코드에서 %
를 .format
으로 바꾸려고 할 때 한 가지 문제를 발견했습니다 '{}'.format(unicode_string)
은 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
는 유니코드 문자열(Python3에서는 '문자열'이라고 함)입니다.
; '%s' % s '\xd0\xb9' ; '%s' % u u'\u0439'
유니코드 개체를 %
연산자에 매개변수로 제공하면 원래 문자열이 유니코드가 아니더라도 유니코드 문자열이 생성됩니다.
; '{}'.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'
원래 문자열이 유니코드인 경우에만 유니코드 인수와 함께 잘 작동합니다.
; '{}'.format(u'i') 'i'
또는 인수 문자열이 문자열로 변환될 수 있는 경우(소위 '바이트 배열')
wobmene%
는 내 테스트의 format
보다 더 나은 성능을 제공합니다.
테스트 코드:
파이썬 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
파이썬 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
보다 훨씬 빠릅니다.
샘플 코드에 대해 @Chris Cogdon에게 감사드립니다.
편집 1:
2019년 7월 Python 3.7.2에서 다시 테스트되었습니다.
결과:
> format: 0.86600608 > %: 0.630180146
큰 차이는 없습니다. 파이썬이 점차 발전하고 있다고 생각합니다.
편집 2:
누군가가 주석에서 python 3의 f-string을 언급한 후 python 3.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
보다는 나은 것 같습니다.
lcltj.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 {ax}, y is {ay}'.format(a=a) Out[15]: 'x is 2, y is 3'
내가 말할 수있는 한 %
matiasg%
를 통해 문자열을 형식화하는 이전 방법은 기본적으로 소수점 고정 소수점 및 부동 소수점 산술을 위한 Python 모듈인 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.00000000000000000000031237523900000009907464850 0.0000000000000000000000312375239000000000
분명히 해결 방법이 있을 수 있지만 여전히 format()
메서드를 즉시 사용하는 것을 고려할 수 있습니다.
balupython >= 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)
zhengcao참고로 로깅과 함께 새로운 스타일 형식을 사용하기 위해 성능 저하를 겪을 필요는 없습니다. __str__
매직 메소드를 구현하는 logging.debug
, logging.info
등에 모든 객체를 전달할 수 있습니다. 로깅 모듈이 메시지 개체(무엇이든 간에)를 내보내야 한다고 결정하면 그렇게 하기 전에 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))
이것은 모두 Python 3 문서( 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 ).
이 기술을 사용할 때의 장점 중 하나는 형식화 스타일에 구애받지 않는다는 사실 외에 expensive_func
_func와 같은 게으른 값을 허용한다는 것입니다. 이것은 Python 문서(https://docs.python.org/2.6/library/logging.html#optimization) 에 제공된 조언에 대한 보다 우아한 대안을 제공합니다.
David Sanders%
가 도움이 될 수 있는 한 가지 상황은 정규 표현식의 형식을 지정할 때입니다. 예를 들어,
'{type_names} [az]{2}'.format(type_names='triangle|square')
IndexError
시킵니다. 이 상황에서 다음을 사용할 수 있습니다.
'%(type_names)s [az]{2}' % {'type_names': 'triangle|square'}
'{type_names} [az]{{2}}'
로 쓰는 것을 방지할 수 있습니다. 이것은 두 개의 정규식이 있을 때 유용할 수 있습니다. 하나는 형식 없이 단독으로 사용되지만 둘의 연결은 형식이 지정됩니다.
Jorge Leitao버전 3.6부터 다음과 같이 fstrings를 사용할 수 있다고 덧붙였습니다.
foo = "john" bar = "smith" print(f"My name is {foo} {bar}")
어느 줄
내 이름은 존 스미스
모든 것이 문자열로 변환됩니다.
mylist = ["foo", "bar"] print(f"mylist = {mylist}")
결과:
mylist = ['푸', '바']
다른 형식 메서드와 같이 함수를 전달할 수 있습니다.
print(f'Hello, here is the date : {time.strftime("%d/%m/%Y")}')
예를 들어
안녕하세요, 날짜는 2018년 4월 16일입니다.
Sylvan LE DEUNFFPython 버전의 경우> = 3.6( PEP 498 참조)
s1='albha' s2='beta' f'{s1}{s2:>10}' #output 'albha beta'
Roushan파이썬 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 -----
Felix Martinez그러나 한 가지는 중첩 중괄호가 있는 경우 형식에서는 작동하지 않지만 %
는 작동한다는 것입니다.
예시:
>>> '{{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}' >>>
U12-Forward출처 : http:www.stackoverflow.com/questions/5082452/string-formatting-vs-format-vs-f-string-literal