Câu hỏi Python tham gia: tại sao nó string.join (danh sách) thay vì list.join (string)?


Điều này luôn làm tôi bối rối. Có vẻ như điều này sẽ đẹp hơn:

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

Hơn cái này:

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

Có lý do cụ thể nào không?


1383
2018-01-29 22:45


gốc


Để dễ nhớ và hiểu, - tuyên bố rằng bạn đang tham gia một danh sách và chuyển đổi thành một chuỗi. - JawSaw
@ JawSaw: Điều đó chỉ gây nhầm lẫn cho mem nhiều hơn. - einpoklum


Các câu trả lời:


Đó là bởi vì bất kỳ iterable có thể được tham gia, không chỉ danh sách, nhưng kết quả và "joiner" luôn luôn là chuỗi.

VÍ DỤ:

import urllib2
print '\n############\n'.join(
    urllib2.urlopen('http://data.stackexchange.com/users/7095'))

1001
2018-01-29 22:51



Đây có thể là giải thích ngắn gọn nhất về một khái niệm khá liên quan mà tôi từng thấy. Ví dụ tuyệt vời - Adam Hughes
Tôi không đồng ý về mặt khái niệm ngay cả khi nó có nghĩa là viết mã. list.join(string) xuất hiện nhiều hơn một cách tiếp cận hướng đối tượng trong khi string.join(list) nghe có vẻ nhiều thủ tục hơn. - Eduardo Pignatelli
Vậy tại sao nó không được thực hiện trên iterable? - Time Sheep
@TimeSheep: Một danh sách các số nguyên không có sự tham gia có ý nghĩa, mặc dù nó có thể lặp lại được. - recursive
@krysopath: Nó có thể được, nhưng có nhiều hiểu biết như vậy. Không lặp lại danh sách các chuỗi cần một cách để được tham gia. Và danh sách các chuỗi có thể lặp lại được. Vì vậy, nó có thể đáp ứng tất cả các trường hợp sử dụng với phương pháp duy nhất này. Danh sách có thể có một phương thức join, như trong javascript, nhưng có rất nhiều trường hợp sử dụng trong python, nơi mà phương thức join hiện tại vẫn cần thiết. Và bạn có thể biến đổi một cách đáng kể cái hiện tại thành những gì bạn đang nghĩ. ví dụ. ", ".join(map(str,numbers)). - recursive


Bởi vì join() phương thức là trong lớp chuỗi, thay vì lớp danh sách?

Tôi đồng ý có vẻ buồn cười.

Xem http://www.faqs.org/docs/diveintopython/odbchelper_join.html:

Ghi chú lịch sử. Khi tôi lần đầu tiên học   Python, tôi mong đợi tham gia là một phương pháp   của một danh sách, sẽ lấy   delimiter làm đối số. Nhiều   mọi người cũng cảm thấy như vậy, và có   một câu chuyện đằng sau phương thức kết nối. Trước   với Python 1.6, các chuỗi không có tất cả   những phương pháp hữu ích này. Có một   mô-đun chuỗi riêng biệt chứa   tất cả các hàm chuỗi; mỗi   chức năng lấy một chuỗi như là đầu tiên của nó   tranh luận. Các chức năng được coi là   đủ quan trọng để đưa vào   dây tự, có ý nghĩa   cho các chức năng như dưới, trên và   chia nhỏ. Nhưng nhiều Python lõi cứng   các lập trình viên phản đối việc tham gia mới   phương pháp, lập luận rằng nó phải là một   thay vào đó, hoặc là   không nên di chuyển chút nào nhưng chỉ đơn giản là ở lại   một phần của mô-đun chuỗi cũ (mà   vẫn còn rất nhiều công cụ hữu ích trong đó).   Tôi chỉ sử dụng phương thức kết hợp mới,   nhưng bạn sẽ thấy mã được viết   và nếu nó thực sự làm phiền bạn, bạn   có thể sử dụng hàm string.join cũ   thay thế.

--- Đánh dấu Pilgrim, Lặn sâu vào Python


228
2018-01-29 22:48





Điều này đã được thảo luận trong Phương thức chuỗi ... cuối cùng trong Python-Dev achive, và được chấp nhận bởi Guido. Chủ đề này bắt đầu vào tháng 6 năm 1999 và str.join đã được bao gồm trong Python 1.6 được phát hành vào tháng 9 năm 2000 (và hỗ trợ Unicode). Python 2.0 (được hỗ trợ str phương pháp bao gồm join) được phát hành vào tháng 10 năm 2000.

  • Có bốn tùy chọn được đề xuất trong chuỗi này:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join như một hàm dựng sẵn
  • Guido muốn hỗ trợ không chỉ listS, tuples, nhưng tất cả các chuỗi / vòng lặp.
  • seq.reduce(str) rất khó cho những người mới đến.
  • seq.join(str) giới thiệu sự phụ thuộc không mong muốn từ các chuỗi đến str / unicode.
  • join() như một hàm tích hợp sẽ chỉ hỗ trợ các kiểu dữ liệu cụ thể. Vì vậy, bằng cách sử dụng một không gian tên được xây dựng trong không phải là tốt. Nếu join() hỗ trợ nhiều kiểu dữ liệu, việc tạo ra việc triển khai tối ưu sẽ khó khăn, nếu được thực hiện bằng cách sử dụng __add__ thì đó là O (n²).
  • Chuỗi phân tách (sep) không nên bỏ qua. Rõ ràng là tốt hơn là ngầm.

Không có lý do nào khác được cung cấp trong chuỗi này.

Dưới đây là một số suy nghĩ bổ sung (của riêng tôi, và của bạn tôi):

  • Hỗ trợ Unicode đã đến, nhưng nó không phải là cuối cùng. Vào thời điểm đó, UTF-8 có nhiều khả năng thay thế UCS2 / 4. Để tính tổng chiều dài bộ đệm của chuỗi UTF-8, cần biết quy tắc mã hóa ký tự.
  • Vào thời điểm đó, Python đã quyết định về một quy tắc giao diện chuỗi chung, nơi người dùng có thể tạo một lớp giống như trình tự (có thể lặp lại). Nhưng Python không hỗ trợ mở rộng các kiểu dựng sẵn cho đến 2.2. Vào thời điểm đó rất khó để cung cấp lớp cơ bản có thể lặp lại (được đề cập trong một bình luận khác).

Quyết định của Guido được ghi lại trong một thư lịch sử, quyết định str.join(seq):

Hài hước, nhưng nó có vẻ đúng! Barry, hãy đi ...
  --Guido van Rossum


213
2017-09-30 15:21





Tôi đồng ý rằng nó phản trực giác lúc đầu, nhưng có một lý do chính đáng. Tham gia không thể là phương thức của danh sách vì:

  • nó cũng phải hoạt động với các lần lặp khác nhau (bộ dữ liệu, máy phát, v.v.)
  • nó phải có hành vi khác nhau giữa các loại chuỗi khác nhau.

Thực tế có hai phương thức join (Python 3.0):

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

Nếu tham gia là một phương pháp của một danh sách, sau đó nó sẽ phải kiểm tra các đối số của nó để quyết định một trong số họ gọi. Và bạn không thể tham gia các byte và kết hợp với nhau, vì vậy cách mà chúng có được bây giờ có ý nghĩa.


58
2018-01-29 23:03





Tại sao lại như vậy string.join(list) thay vì list.join(string)?

Điều này là bởi vì join là một phương thức "chuỗi"! Nó tạo ra một chuỗi từ bất kỳ iterable nào. Nếu chúng ta mắc kẹt phương thức trên danh sách, thì khi nào chúng ta có các vòng lặp không phải là danh sách?

Nếu bạn có một chuỗi các chuỗi? Nếu đây là list phương pháp, bạn sẽ phải bỏ tất cả các chuỗi lặp như vậy list trước khi bạn có thể tham gia các yếu tố thành một chuỗi duy nhất! Ví dụ:

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

Hãy cuộn phương thức nối danh sách riêng của chúng ta:

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

Và để sử dụng nó, lưu ý rằng trước tiên chúng ta phải tạo một danh sách từ mỗi iterable để tham gia các chuỗi trong iterable đó, lãng phí cả bộ nhớ và sức mạnh xử lý:

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

Vì vậy, chúng ta thấy chúng ta phải thêm một bước phụ để sử dụng phương thức danh sách của chúng ta, thay vì chỉ sử dụng phương thức chuỗi dựng sẵn:

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

Hiệu suất caveat cho máy phát điện

Thuật toán Python sử dụng để tạo chuỗi cuối cùng với str.join thực sự phải vượt qua vòng lặp có thể lặp lại hai lần, vì vậy nếu bạn cung cấp cho nó một biểu thức máy phát, nó phải hiện thực hóa nó thành một danh sách đầu tiên trước khi nó có thể tạo chuỗi cuối cùng.

Do đó, trong khi truyền xung quanh máy phát điện thường tốt hơn so với danh sách hiểu, str.join là một ngoại lệ:

>>> 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

Tuy nhiên, str.join hoạt động vẫn là ngữ nghĩa một "chuỗi" hoạt động, vì vậy nó vẫn có ý nghĩa để có nó trên str đối tượng hơn trên các vòng lặp linh tinh.


36
2018-04-14 00:45





Hãy suy nghĩ về nó như là hoạt động trực giao tự nhiên để phân chia.

Tôi hiểu lý do tại sao nó có thể áp dụng cho bất kỳ thứ gì có thể lặp lại và do đó không thể dễ dàng được triển khai chỉ trong danh sách.

Để dễ đọc, tôi muốn thấy nó bằng ngôn ngữ nhưng tôi không nghĩ điều đó thực sự khả thi - nếu khả năng lặp lại là giao diện thì nó có thể được thêm vào giao diện nhưng nó chỉ là một quy ước và vì vậy không có cách nào để thêm nó vào tập hợp những thứ có thể lặp lại được.


22
2018-01-30 02:43





Chủ yếu là do kết quả của một someString.join() là một chuỗi.

Trình tự (danh sách hoặc tuple hoặc bất cứ điều gì) không xuất hiện trong kết quả, chỉ là một chuỗi. Bởi vì kết quả là một chuỗi, nó có ý nghĩa như một phương thức của một chuỗi.


11
2018-01-29 22:51





Cả hai đều không tốt đẹp.

string.join (xs, delimit) có nghĩa là mô-đun chuỗi nhận thức được sự tồn tại của một danh sách, mà nó không có kinh doanh, vì mô-đun chuỗi chỉ hoạt động với các chuỗi.

list.join (delimit) đẹp hơn một chút bởi vì chúng ta quen với các chuỗi là một kiểu cơ bản (và thường nói là chúng). Tuy nhiên điều này có nghĩa là tham gia cần phải được gửi đi động bởi vì trong bối cảnh tùy ý của a.split("\n") trình biên dịch python có thể không biết cái gì là, và sẽ cần tìm kiếm nó (tương tự như tra cứu vtable), mà là tốn kém nếu bạn làm điều đó rất nhiều lần.

nếu trình biên dịch thời gian chạy python biết rằng danh sách được xây dựng trong mô-đun, nó có thể bỏ qua tra cứu động và mã hóa ý định vào bytecode trực tiếp, trong khi ngược lại nó cần giải quyết động "join" của "a", có thể lên nhiều lớp của thừa kế cho mỗi cuộc gọi (kể từ khi giữa các cuộc gọi, ý nghĩa của tham gia có thể đã thay đổi, bởi vì python là một ngôn ngữ năng động).

thật đáng buồn, đây là lỗ hổng tối thượng của sự trừu tượng; không có vấn đề gì trừu tượng bạn chọn, trừu tượng của bạn sẽ chỉ có ý nghĩa trong bối cảnh của vấn đề bạn đang cố gắng giải quyết, và như vậy bạn không bao giờ có được một sự trừu tượng nhất quán mà không trở nên mâu thuẫn với các hệ tư tưởng cơ bản khi bạn bắt đầu dán chúng cùng nhau mà không gói chúng trong một cái nhìn phù hợp với ý thức hệ của bạn. Biết được điều này, cách tiếp cận của python linh hoạt hơn vì nó rẻ hơn, bạn có thể trả nhiều tiền hơn để làm cho nó trông đẹp hơn, hoặc bằng cách tạo trình bao bọc của riêng bạn hoặc bộ tiền xử lý của riêng bạn.


1
2018-05-07 19:32





- tham gia (my_list) tuyên bố rằng bạn đang chuyển đổi sang một chuỗi từ tham gia các yếu tố một danh sách. Đó là định hướng kết quả. (chỉ dành cho bộ nhớ và sự hiểu biết dễ dàng)

Tôi tạo một bảng tính đầy đủ của phương thức_of_string để bạn tham khảo.

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']}

1
2017-12-04 12:22