왜 list.join (string) 대신 string.join (list)입니까?


1762

이것은 항상 나를 혼란스럽게했습니다. 더 좋을 것 같습니다.

my_list = ["Hello", "world"]
print(my_list.join("-"))
# Produce: "Hello-world"

이것보다:

my_list = ["Hello", "world"]
print("-".join(my_list))
# Produce: "Hello-world"

이와 같은 특별한 이유가 있습니까?


1
메모리와 이해를 쉽게 -하기 위해 목록에 가입하고 문자열로 변환하고 있음을 선언합니다. 결과 지향적입니다.
Calculus

11
@JawSaw : 더 혼란스러워합니다.
einpoklum

33
짧은 대답은 파이썬의 유형 시스템이 충분히 강력하지 않기 때문에 str모든 반복 가능한 유형에 구현하는 것 보다이 기능을 한 번 구현하는 것이 더 쉽다는 것입니다.
BallpointBen

3
원래 아이디어는 join ()이 문자열을 반환하기 때문에 문자열 컨텍스트에서 호출해야한다고 생각합니다. 목록에 join ()을 넣는 것은 목록이 객체의 컨테이너이며 문자열에만 해당하는 일회성 함수를 가져서는 안된다는 점에서 의미가 없습니다.
Joshua Burns

답변:


1247

iterable (예 : list, tuple, dict, set)을 조인 할 수 있지만 결과와 "joiner" 문자열 이어야합니다 .

예를 들면 다음과 같습니다.

'_'.join(['welcome', 'to', 'stack', 'overflow'])
'_'.join(('welcome', 'to', 'stack', 'overflow'))
'welcome_to_stack_overflow'

문자열 이외의 것을 사용하면 다음 오류가 발생합니다.

TypeError : sequence item 0 : 예상 str 인스턴스, int found


57
코드 적으로 이해가 되더라도 개념적으로 동의하지 않습니다. list.join(string)더 객체 지향적 인 접근법으로 보이지만 string.join(list)훨씬 더 절차 적으로 들립니다.
Eduardo Pignatelli

22
그렇다면 왜 iterable에 구현되지 않습니까?
Steen Schütt

10
@TimeSheep : 정수 목록은 반복 가능하지만 의미있는 조인이 없습니다.
재귀 적

16
나는 사용하려고 노력했지만 print(str.join('-', my_list))더 잘 느낀다.
pimgeek

13
@TimeSheep iterable은 구체적 유형이 아니기 때문에 iterable은 인터페이스, __iter__메소드 를 정의하는 모든 유형입니다 . 모든 iterable을 구현해야 join한다면 매우 특정한 사용 사례에 대한 일반 인터페이스 (문자열이 아닌 iterable도 포함)가 복잡해집니다. join스트레인을 정의 하면 "직관적이지 않은"순서의 비용으로이 문제를 회피 할 수 있습니다. 더 나은 선택은 첫 번째 인수가 반복 가능하고 두 번째 (선택적 인수)는 조이너 문자열 인 함수를 유지하는 것이 었습니다. 그러나 그 배는 항해했습니다.
user4815162342

319

이것은 String 메소드 에서 논의되었습니다 ... 마침내 Python-Dev achive의 스레드이며 Guido에 의해 승인되었습니다. 이 스레드는 1999 년 6 월에 시작되었으며 str.join2000 년 9 월에 릴리스 된 Python 1.6에 포함되었으며 유니 코드를 지원합니다. Python 2.0 (을 str포함하여 지원되는 메소드 join)은 2000 년 10 월에 릴리스되었습니다.

  • 이 스레드에는 네 가지 옵션이 제안되었습니다.
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join 내장 함수로
  • Guido는 lists, tuples뿐만 아니라 모든 시퀀스 / iterable 을 지원하고자했습니다 .
  • seq.reduce(str) 새로 온 사람에게는 어려움이 있습니다.
  • seq.join(str) 시퀀스에서 str / unicode에 예기치 않은 종속성이 발생합니다.
  • join()내장 함수는 특정 데이터 유형 만 지원합니다. 따라서 내장 네임 스페이스를 사용하는 것은 좋지 않습니다. join()많은 데이터 유형을 지원하는 경우 최적화 된 구현을 작성하는 것은 어려울 수 있습니다. __add__메소드를 사용하여 구현하면 O (n²)입니다.
  • 구분자 문자열 ( sep)은 생략하면 안됩니다. 암시적인 것보다 명시적인 것이 좋습니다.

이 글타래에 다른 이유가 없습니다.

여기에 몇 가지 추가 생각 (나 자신과 친구)이 있습니다.

  • 유니 코드 지원이오고 있지만 최종적인 것은 아닙니다. 당시 UTF-8은 UCS2 / 4를 대체 할 가능성이 가장 컸습니다. UTF-8 문자열의 총 버퍼 길이를 계산하려면 문자 코딩 규칙을 알아야합니다.
  • 그 당시 Python은 이미 사용자가 시퀀스와 같은 (반복 가능한) 클래스를 만들 수있는 공통 시퀀스 인터페이스 규칙을 결정했습니다. 그러나 파이썬은 내장 유형을 2.2까지 확장하는 것을 지원하지 않았습니다. 그 당시에는 기본 반복 가능 클래스를 제공하기가 어려웠습니다 (다른 의견에서 언급 함).

Guido의 결정은 다음 과 같이 결정 하는 역사적인 메일에 기록 됩니다 str.join(seq).

재밌지 만 옳은 것 같습니다! 배리, 가서 ...
--Guido van Rossum


251

join()메소드가 목록 클래스 대신 문자열 클래스에 있기 때문에 ?

나는 그것이 재미있어 보인다는 것에 동의합니다.

http://www.faqs.org/docs/diveintopython/odbchelper_join.html을 참조 하십시오 .

역사적 메모.파이썬을 처음 배웠을 때 join은 목록의 메소드가 될 것으로 예상했는데, 구분 기호를 인수로 사용합니다. 많은 사람들이 같은 방식으로 느끼고 조인 방법 뒤에 이야기가 있습니다. 파이썬 1.6 이전에는 문자열에 유용한 메소드가 없었습니다. 모든 문자열 함수를 포함하는 별도의 문자열 모듈이있었습니다. 각 함수는 문자열을 첫 번째 인수로 사용했습니다. 함수는 문자열 자체에 놓을만큼 충분히 중요하다고 여겨졌으며, 이는 하한, 상한 및 분할과 같은 기능에 적합합니다. 그러나 많은 하드 코어 파이썬 프로그래머는 새로운 조인 메소드에 반대하여 대신 목록의 메소드 여야하거나 전혀 움직이지 말고 단순히 기존 문자열 모듈의 일부를 유지해야한다고 주장했습니다. 유용한 것들).

--- Mark Pilgrim, Python으로 다이빙


12
Python 3 string라이브러리는 모든 중복 str메소드를 제거 하므로 더 이상 사용할 수 없습니다 string.join(). 개인적으로, 나는 그것이 '재미있는'것이라고 생각하지 않았습니다. 단순히 목록보다 더 많은 것을 참여시킬 수 있기 때문에 완벽한 의미가 있습니다. 그러나 결합자는 항상 문자열입니다!
Martijn Pieters

67

나는 그것이 처음에는 직관적이지 않다는 데 동의하지만 그만한 이유가 있습니다. 다음과 같은 이유로 조인을 목록의 방법으로 사용할 수 없습니다.

  • 다른 iterables (튜플, 생성기 등)에서도 작동해야합니다.
  • 다른 유형의 문자열간에 다른 동작을 가져야합니다.

실제로 두 가지 조인 방법이 있습니다 (Python 3.0).

>>> b"".join
<built-in method join of bytes object at 0x00A46800>
>>> "".join
<built-in method join of str object at 0x00A28D40>

join이리스트의 메소드 인 경우, 인수 중 하나를 호출하도록 결정하기 위해 인수를 검사해야합니다. 그리고 당신은 바이트와 str을 결합 할 수 없으므로 그들이 가지고있는 방식이 합리적입니다.


45

string.join(list)대신에 list.join(string)?

이것은 join"문자열"방법 이기 때문 입니다! iterable에서 문자열을 만듭니다. 메소드를리스트에 붙였다면리스트가 아닌 iterable이있을 때는 어떻습니까?

튜플 문자열이 있으면 어떻게 되나요? 이것이 list방법 이라면 list요소를 단일 문자열로 결합하기 전에 문자열 반복자를 모두 캐스팅해야 합니다! 예를 들면 다음과 같습니다.

some_strings = ('foo', 'bar', 'baz')

우리 자신의리스트 조인 메소드를 굴 리자 :

class OurList(list): 
    def join(self, s):
        return s.join(self)

그리고 그것을 사용하려면 먼저 메모리와 처리 능력을 낭비하면서 반복 가능한 문자열을 결합하기 위해 각 반복 가능한 목록을 작성해야합니다.

>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'

따라서 내장 문자열 메소드를 사용하는 대신 목록 메소드를 사용하려면 추가 단계를 추가해야합니다.

>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'

발전기를위한 성능주의 사항

파이썬이 최종 문자열을 생성하는 데 사용하는 알고리즘은 str.join실제로 반복 가능한 반복문을 두 번 전달해야하므로 생성기 표현식을 제공하면 최종 문자열을 생성하기 전에 먼저 목록으로 구체화해야합니다.

따라서 일반적으로 생성기를 통과하는 것이 목록 이해보다 낫지 만 str.join예외는 다음과 같습니다.

>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173

그럼에도 불구하고, str.join작업은 여전히 ​​의미 상 "문자열"작업이므로 str기타 반복 가능 개체보다 개체 에 작업하는 것이 좋습니다.


24

그것을 분리하기위한 자연스러운 직교 연산으로 생각하십시오.

반복 가능한 것에 적용 가능한 이유를 이해하고 있으므로 목록 에서만 쉽게 구현할 수 없습니다 .

가독성을 위해 언어로보고 싶지만 실제로 실현 가능하다고 생각하지 않습니다. 반복성이 인터페이스라면 인터페이스에 추가 될 수는 있지만 단지 관습이므로 중앙에 방법이 없습니다. 반복 가능한 것들에 추가하십시오.


13

주로 a의 결과 someString.join()가 문자열 이기 때문에 .

시퀀스 (목록 또는 튜플 또는 기타)는 결과에 나타나지 않고 문자열 만 나타납니다. 결과는 문자열이므로 문자열의 메서드로 의미가 있습니다.


10

- "-". join (my_list)은 요소를 목록에서 결합하여 문자열로 변환하고 있음을 선언합니다. 결과 지향적입니다. (쉬운 메모리와 이해를 위해)

나는 참고로 methods_of_string의 완전한 치트 시트를 만듭니다.

string_methonds_44 = {
    'convert': ['join','split', 'rsplit','splitlines', 'partition', 'rpartition'],
    'edit': ['replace', 'lstrip', 'rstrip', 'strip'],
    'search': ['endswith', 'startswith', 'count', 'index', 'find','rindex', 'rfind',],
    'condition': ['isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isnumeric','isidentifier',
                  'islower','istitle', 'isupper','isprintable', 'isspace', ],
    'text': ['lower', 'upper', 'capitalize', 'title', 'swapcase',
             'center', 'ljust', 'rjust', 'zfill', 'expandtabs','casefold'],
    'encode': ['translate', 'maketrans', 'encode'],
    'format': ['format', 'format_map']}

3

둘 다 좋지 않습니다.

string.join (xs, delimit)은 문자열 모듈이 문자열에서만 작동하므로 문자열 모듈이 목록의 존재를 인식한다는 것을 의미합니다.

list.join (delimit)은 문자열이 기본 유형 (언어 적으로 말하면)에 익숙하기 때문에 조금 더 좋습니다. 그러나 이것은 a.split("\n")파이썬 컴파일러 의 임의의 컨텍스트에서 a가 무엇인지 알지 못하고 그것을 찾아야 할 필요가 있기 때문에 조인이 동적으로 전달되어야 함을 의미 합니다 (vtable 조회와 유사). 타임스.

python 런타임 컴파일러가 해당 목록이 내장 모듈임을 알고 있으면 동적 조회를 건너 뛰고 의도를 바이트 코드로 직접 인코딩 할 수 있지만, 그렇지 않으면 "a"의 "join"을 동적으로 해결해야합니다. 호출 당 상속 (파이썬은 동적 언어이기 때문에 호출간에 조인의 의미가 변경되었을 수 있음).

슬프게도 이것은 추상화의 궁극적 인 결함입니다. 어떤 추상화를 선택하든 추상화는 해결하려는 문제의 맥락에서만 의미가 있으며, 따라서 당신은 그것들을 붙일 때 기본 이념과 일치하지 않는 일관된 추상화를 가질 수 없습니다. 당신의 이데올로기와 일치하는 견해로 포장하지 않고 함께. 이것을 알면 파이썬의 접근 방식은 더 저렴하기 때문에 더 유연합니다. 자신의 래퍼를 만들거나 자신의 전처리기를 만들어서 "더 똑똑해"보이도록 더 많이 지불하는 것은 당신에게 달려 있습니다.


0

변수 my_list와는 "-"모두 개체입니다. 구체적으로, 이들은 각각 클래스 list와의 인스턴스입니다 str. 이 join함수는 클래스에 속합니다 str. 따라서 "-".join(my_list)오브젝트 "-"my_list입력으로 사용되므로 구문 이 사용됩니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.