[python] 파이썬에서 문자열 연결과 문자열 대체

Python에서는 문자열 연결과 문자열 대체를 사용하는 위치와시기를 알 수 없습니다. 문자열 연결로 인해 성능이 크게 향상되었으므로 이것은 실용적인 결정이 아닌 문체 결정입니까?

구체적인 예를 들어, 유연한 URI 구성을 어떻게 처리해야합니까?

DOMAIN = 'http://stackoverflow.com'
QUESTIONS = '/questions'

def so_question_uri_sub(q_num):
    return "%s%s/%d" % (DOMAIN, QUESTIONS, q_num)

def so_question_uri_cat(q_num):
    return DOMAIN + QUESTIONS + '/' + str(q_num)

편집 : 문자열 목록 결합 및 명명 된 대체 사용에 대한 제안도 있습니다. 이것들은 중심 주제에 대한 변형입니다. 즉, 어떤 방법으로 어느 시점에이를 수행 할 수 있습니까? 응답 해 주셔서 감사합니다!



답변

내 컴퓨터에 따르면 연결이 (상당히) 빠릅니다. 하지만 스타일 상으로는 성능이 중요하지 않은 경우 대체 비용을 지불 할 의향이 있습니다. 음, 서식이 필요한 경우 질문도 할 필요가 없습니다. 보간 / 템플릿을 사용하는 것 외에는 옵션이 없습니다.

>>> import timeit
>>> def so_q_sub(n):
...  return "%s%s/%d" % (DOMAIN, QUESTIONS, n)
...
>>> so_q_sub(1000)
'http://stackoverflow.com/questions/1000'
>>> def so_q_cat(n):
...  return DOMAIN + QUESTIONS + '/' + str(n)
...
>>> so_q_cat(1000)
'http://stackoverflow.com/questions/1000'
>>> t1 = timeit.Timer('so_q_sub(1000)','from __main__ import so_q_sub')
>>> t2 = timeit.Timer('so_q_cat(1000)','from __main__ import so_q_cat')
>>> t1.timeit(number=10000000)
12.166618871951641
>>> t2.timeit(number=10000000)
5.7813972166853773
>>> t1.timeit(number=1)
1.103492206766532e-05
>>> t2.timeit(number=1)
8.5206360154188587e-06

>>> def so_q_tmp(n):
...  return "{d}{q}/{n}".format(d=DOMAIN,q=QUESTIONS,n=n)
...
>>> so_q_tmp(1000)
'http://stackoverflow.com/questions/1000'
>>> t3= timeit.Timer('so_q_tmp(1000)','from __main__ import so_q_tmp')
>>> t3.timeit(number=10000000)
14.564135316080637

>>> def so_q_join(n):
...  return ''.join([DOMAIN,QUESTIONS,'/',str(n)])
...
>>> so_q_join(1000)
'http://stackoverflow.com/questions/1000'
>>> t4= timeit.Timer('so_q_join(1000)','from __main__ import so_q_join')
>>> t4.timeit(number=10000000)
9.4431309007150048


답변

명명 된 대체를 잊지 마세요.

def so_question_uri_namedsub(q_num):
    return "%(domain)s%(questions)s/%(q_num)d" % locals()


답변

루프에서 문자열을 연결하지 않도록주의하십시오! 문자열 연결 비용은 결과 길이에 비례합니다. 루핑은 N 제곱의 땅으로 곧바로 이어집니다. 일부 언어는 가장 최근에 할당 된 문자열에 대한 연결을 최적화하지만 컴파일러에 의존하여 2 차 알고리즘을 선형으로 최적화하는 것은 위험합니다. join전체 문자열 목록을 취하고 단일 할당을 수행하며 한 번에 모두 연결 하는 기본 ( ?) 을 사용하는 것이 가장 좋습니다 .


답변

“문자열 연결로 성능이 크게 향상 되었기 때문에 …”

성능이 중요하다면 알아두면 좋습니다.

그러나 내가 본 성능 문제는 문자열 연산으로 내려온 적이 없습니다. 나는 일반적으로 I / O, 정렬 및 O ( n 2 ) 작업이 병목 현상이되는 문제에 봉착했습니다 .

문자열 연산이 성능 제한이 될 때까지 나는 명백한 것을 고수 할 것입니다. 대부분은 한 줄 이하인 경우 대체, 의미가있는 경우 연결, 큰 경우 템플릿 도구 (예 : Mako)입니다.


답변

연결 / 보간하려는 항목과 결과 형식을 지정하는 방법이 결정을 좌우해야합니다.

  • 문자열 보간을 사용하면 서식을 쉽게 추가 할 수 있습니다. 사실, 문자열 보간 버전은 연결 버전과 동일한 작업을 수행하지 않습니다. 실제로 q_num매개 변수 앞에 추가 슬래시를 추가합니다 . 동일한 작업을 수행하려면 return DOMAIN + QUESTIONS + "/" + str(q_num)해당 예제 를 작성해야합니다 .

  • 보간을 사용하면 숫자 형식을보다 쉽게 ​​지정할 수 있습니다. "%d of %d (%2.2f%%)" % (current, total, total/current)연결 형식에서는 가독성이 훨씬 떨어집니다.

  • 연결은 문자열화할 고정 된 수의 항목이 없을 때 유용합니다.

또한 Python 2.6에는 문자열 템플릿 이라는 새로운 버전의 문자열 보간이 도입되었습니다 .

def so_question_uri_template(q_num):
    return "{domain}/{questions}/{num}".format(domain=DOMAIN,
                                               questions=QUESTIONS,
                                               num=q_num)

문자열 템플릿은 결국 %-보간법을 대체 할 예정이지만 꽤 오랫동안 일어나지 않을 것이라고 생각합니다.


답변

저는 호기심에서 다른 문자열 연결 / 대체 방법의 속도를 테스트하고있었습니다. 주제에 대한 Google 검색이 나를 여기로 데려 왔습니다. 누군가가 결정하는 데 도움이 될 수 있기를 바라며 테스트 결과를 게시 할 것이라고 생각했습니다.

    import timeit
    def percent_():
            return "test %s, with number %s" % (1,2)

    def format_():
            return "test {}, with number {}".format(1,2)

    def format2_():
            return "test {1}, with number {0}".format(2,1)

    def concat_():
            return "test " + str(1) + ", with number " + str(2)

    def dotimers(func_list):
            # runs a single test for all functions in the list
            for func in func_list:
                    tmr = timeit.Timer(func)
                    res = tmr.timeit()
                    print "test " + func.func_name + ": " + str(res)

    def runtests(func_list, runs=5):
            # runs multiple tests for all functions in the list
            for i in range(runs):
                    print "----------- TEST #" + str(i + 1)
                    dotimers(func_list)

… 실행 한 후 runtests((percent_, format_, format2_, concat_), runs=5)% 메서드가이 작은 문자열에서 다른 메서드보다 약 두 배 빠르다는 것을 발견했습니다. concat 메서드는 항상 가장 느 렸습니다 (간신히). format()방법 에서 위치를 전환 할 때 매우 작은 차이가 있었지만 위치 전환은 항상 일반 형식 방법보다 .01 이상 느 렸습니다.

테스트 결과 샘플 :

    test concat_()  : 0.62  (0.61 to 0.63)
    test format_()  : 0.56  (consistently 0.56)
    test format2_() : 0.58  (0.57 to 0.59)
    test percent_() : 0.34  (0.33 to 0.35)

스크립트에서 문자열 연결을 사용하기 때문에 이것을 실행했으며 비용이 얼마인지 궁금했습니다. 방해가되지 않는지 확인하기 위해 다른 순서로 실행했거나 더 나은 성능을 처음 또는 마지막으로 얻었습니다. 참고로, 나는 더 긴 문자열 생성기를 같은 함수에 넣었고 "%s" + ("a" * 1024)일반 연결은 format%메서드 를 사용하는 것보다 거의 3 배 (1.1 대 2.8) 빠릅니다 . 나는 그것이 문자열과 당신이 달성하려는 것에 달려 있다고 생각합니다. 성능이 정말로 중요하다면 다른 것을 시도하고 테스트하는 것이 좋습니다. 속도가 문제가되지 않는 한, 나는 속도보다 가독성을 선택하는 경향이 있습니다. 그래서 복사 / 붙여 넣기가 마음에 들지 않았고, 제대로 보이도록 모든 것에 8 개의 공백을 넣어야했습니다. 저는 보통 4를 사용합니다.


답변

코드를 유지하거나 디버깅 할 계획이 있다면 스타일 결정 실용적인 결정이라는 점을 기억하십시오 . 조기 최적화는 모든 악의 근원입니다. “

O (n) 작업을 O (n 2 ) 작업으로 바꾸지 않도록주의하는 한 , 이해하기 가장 쉬운 방법을 사용하겠습니다.