Neden list.join (string) yerine string.join (list)?


1762

Bu beni hep karıştırdı. Bu daha güzel olurdu gibi görünüyor:

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

Bundan daha:

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

Bunun böyle olmasının özel bir nedeni var mı?


1
Kolay bellek ve anlayış için, -bir listeye katıldığınızı ve bir dizeye dönüştürdüğünüzü bildirir.
Matematik

11
@ Jawaw: Bu sadece mem daha karışık.
einpoklum

34
Kısa yanıt, bunun nedeni, Python'un tip sisteminin yeterince güçlü olmaması ve bu işlevselliği bir kez struygulanmasının her yinelenebilir tipte uygulamaktan daha kolay olmasıdır.
BallpointBen

3
Orijinal fikir, join () bir dize döndürdüğü için dize bağlamından çağrılması gerektiğini düşünüyorum. Join () öğesini bir listeye koymak, bir listenin bir nesne kabı olması ve yalnızca dizelere özgü bir defalık işlevinin olmaması gerektiği anlamını taşımaz.
Joshua Burns

Yanıtlar:


1248

Herhangi bir yinelenebilir birleştirilebilir (örneğin, liste, demet, dikte, set), ancak sonuç ve "marangoz" dizeleri olmalıdır .

Örneğin:

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

Dizelerden başka bir şey kullanıldığında aşağıdaki hata ortaya çıkar:

TypeError: sıra öğesi 0: beklenen str örneği, int bulundu


57
Kodla mantıklı gelse bile kavramsal olarak aynı fikirde değilim. list.join(string)daha nesne yönelimli bir yaklaşım gibi görünürken string.join(list)bana çok daha prosedürel geliyor.
Eduardo Pignatelli

22
Öyleyse neden yinelenebilir olarak uygulanmıyor?
Steen Schütt

10
@TimeSheep: Tamsayıların bir listesi, yinelenebilir olsa bile anlamlı bir birleştirmeye sahip değildir.
özyinelemeli

16
Kullanmaya çalıştım print(str.join('-', my_list))ve işe yarıyor, daha iyi hissettiriyor.
pimgeek

13
@TimeSheep Yinelenebilir somut bir tür olmadığından, yinelenebilir bir arabirimdir, bir __iter__yöntemi tanımlayan her türdür . Tüm yinelenebilir öğelerin de uygulanmasını zorunlu kılmak, joingenel bir arabirimi (dizgeler dışındaki yinelemeleri de kapsar) çok özel bir kullanım durumu için karmaşık hale getirir. joinStrins yan adımları tanımlamak "kasıtsız" sipariş pahasına bu sorunu. İlk argüman yinelenebilir ve ikincisi (isteğe bağlı) birleştirme dizesi olmak üzere bir işlev tutmak olabilirdi - ama bu gemi yelken açtı.
user4815162342

319

Bu, String yöntemlerinde tartışıldı ... sonunda Python-Dev arşivinde işledi ve Guido tarafından kabul edildi. Bu konu Haziran 1999'da başladı ve str.joinEylül 2000'de piyasaya sürülen Python 1.6'ya dahil edildi (ve Unicode'u destekledi). Python 2.0 (desteklenen stryöntemler dahil join) Ekim 2000'de piyasaya sürüldü.

  • Bu başlıkta önerilen dört seçenek vardı:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join yerleşik bir işlev olarak
  • Guido sadece lists, tuples değil tüm dizileri / tekrarlanabilirleri de desteklemek istedi .
  • seq.reduce(str) yeni gelenler için zor.
  • seq.join(str) sekanslardan str / unicode'a beklenmedik bağımlılık getirir.
  • join()yerleşik bir işlev yalnızca belirli veri türlerini destekleyeceğinden. Yani yerleşik bir ad alanı kullanmak iyi değil. Eğer join()destekleri birçok veri türleri, optimize edilmiş uygulama yaratma zor olacaktır kullanılarak uygulanması durumunda __add__yöntemi o zaman O (n²) bulunuyor.
  • Ayırıcı dizesi ( sep) atlanmamalıdır. Açık, örtük olmaktan iyidir.

Bu başlıkta sunulan başka bir neden yok.

İşte bazı ek düşünceler (kendim ve arkadaşımın):

  • Unicode desteği geliyordu, ama nihai değildi. O zaman UTF-8, UCS2 / 4'ün yerini almak üzereydi. UTF-8 dizelerinin toplam arabellek uzunluğunu hesaplamak için karakter kodlama kuralını bilmek gerekir.
  • O zaman, Python zaten bir kullanıcının sekans benzeri (tekrarlanabilir) bir sınıf oluşturabileceği ortak bir sekans arayüz kuralına karar vermişti. Ancak Python, dahili tiplerin 2.2'ye kadar genişletilmesini desteklemedi. O zaman temel tekrarlanabilir sınıf sağlamak zordu (başka bir yorumda belirtilmiştir).

Guido'nun kararı tarihi bir postada kaydedilir ve aşağıdakilere karar verir str.join(seq):

Komik, ama doğru görünüyor! Barry, devam et ... -
Guido van Rossum


251

Çünkü join()yöntem yerine liste sınıfının, dize sınıfında mı?

Komik göründüğüne katılıyorum.

Bkz. Http://www.faqs.org/docs/diveintopython/odbchelper_join.html :

Tarihsel not.Python'u ilk öğrendiğimde, katılmanın bir sınırlayıcı olan argümanı alacağı bir liste yöntemi olmasını bekliyordum. Birçok insan aynı şekilde hissediyor ve birleştirme yönteminin arkasında bir hikaye var. Python 1.6'dan önce, dizelerde tüm bu yararlı yöntemler yoktu. Tüm dize işlevlerini içeren ayrı bir dize modülü vardı; her işlev ilk argüman olarak bir dize aldı. Fonksiyonlar, alt, üst ve bölünmüş fonksiyonlar için anlamlı olan dizelerin kendilerine konacak kadar önemli kabul edildi. Ancak birçok sabit çekirdekli Python programcısı, yeni birleştirme yöntemine itiraz etti, bunun yerine listenin bir yöntemi olması gerektiğini ya da hiç hareket etmemesi gerektiğini, ancak eski dize modülünün (hala çok yararlı şeyler).

--- Mark Pilgrim, Python'a dalın


12
Python 3 stringkitaplığı tüm gereksiz stryöntemleri sildi , böylece artık kullanamazsınız string.join(). Şahsen, 'komik' olduğunu hiç düşünmedim, sadece listelerden çok daha fazlasına katılabileceğiniz için mükemmel bir mantıklı, ama marangoz her zaman bir dize!
Martijn Pieters

67

İlk başta bunun mantık dışı olduğunu kabul ediyorum, ama bunun iyi bir nedeni var. Birleştirme bir liste yöntemi olamaz çünkü:

  • farklı yinelenebilirler için de çalışmalıdır (tuples, jeneratörler, vb.)
  • farklı dizeler arasında farklı davranışlara sahip olmalıdır.

Aslında iki birleştirme yöntemi vardır (Python 3.0):

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

Birleştirme bir listenin yöntemiyse, hangisini çağırması gerektiğine karar vermek için argümanlarını denetlemesi gerekir. Ve bayta katılamaz ve birbirine yapışamazsınız, bu yüzden şimdi sahip oldukları yol mantıklıdır.


45

Neden string.join(list)yerine list.join(string)?

Çünkü joinbir "dize" yöntemi! Herhangi bir yinelenebilir bir dize oluşturur. Yöntemi listelere takarsak, liste olmayan yinelemelere sahip olduğumuzda ne olur?

Bir dizi ipiniz varsa ne olur? Bu bir listyöntem olsaydı list, öğeleri tek bir dizeye birleştirmeden önce dizelerin her bir yineleyicisini bir olarak dökmeniz gerekir ! Örneğin:

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

Kendi liste birleştirme yöntemimizi yuvarlayalım:

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

Bunu kullanmak için, önce bu yinelenebilir dizelere katılmak için her bir yinelenebilir listeden hem bellek hem de işlem gücünü boşa harcayan bir liste oluşturmamız gerektiğini unutmayın:

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

Bu nedenle, yalnızca yerleşik dize yöntemini kullanmak yerine liste yöntemimizi kullanmak için ek bir adım eklememiz gerektiğini görüyoruz:

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

Jeneratörler için Performans Uyarısı

Python'un son dizeyi oluşturmak için kullandığı algoritma, str.joingerçekten de yinelenebilir olanı iki kez geçmelidir, bu nedenle bir jeneratör ifadesi sağlarsanız, son dizeyi oluşturmadan önce bir listeye yerleştirmesi gerekir.

Bu nedenle, jeneratörleri dolaşmak genellikle liste kavrayışlarından daha iyi olsa da str.join, bir istisnadır:

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

Bununla birlikte, str.joinişlem hala anlamsal olarak bir "dize" işlemidir, bu nedenle strnesne üzerinde tekrarlanabilir olanlardan ziyade nesneye sahip olmak hala mantıklıdır .


24

Bunu bölünecek doğal dik operasyon olarak düşünün.

Neden yinelenebilir bir şey için geçerli olduğunu ve bu yüzden sadece listede kolayca uygulanamayacağını anlıyorum .

Okunabilirlik için, bunu dilde görmek istiyorum ama bunun gerçekten mümkün olduğunu düşünmüyorum - tekrarlanabilirlik bir arayüz olsaydı, arayüze eklenebilirdi, ancak sadece bir kongre ve bu yüzden merkezi bir yol yok bunu yinelenebilir şeyler kümesine ekleyin.


13

Çünkü a sonucu someString.join()bir dizedir.

Sonuç (liste veya grup ya da başka bir şey) sonuçta görünmez, sadece bir dize. Sonuç bir dize olduğundan, bir dize yöntemi olarak mantıklıdır.


10

- join (my_list) öğesinde bir listeye katılmadan bir dizeye dönüştürdüğünüzü bildirir. Sonuç odaklı. (sadece kolay bellek ve anlayış için)

Ben başvuru için method_of_string ayrıntılı bir hile sayfası yapmak.

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

Her ikisi de hoş değil.

string.join (xs, delimit), string modülünün yalnızca dizelerle çalıştığından, işin bilmediği bir listenin varlığından haberdar olduğu anlamına gelir.

list.join (ayırma) biraz daha hoştur çünkü dizeleri temel bir tür olarak kullanmaya alışkınız (ve dilli olarak, bunlar). Ancak bu, birleştirme işleminin dinamik olarak gönderilmesi gerektiği anlamına gelir, çünkü a.split("\n")python derleyicisinin keyfi bağlamında a'nın ne olduğunu bilmeyebilir ve çok fazla yaparsanız pahalıya mal olacaktır (bu da vtable aramaya benzer) zamanlar.

python çalışma zamanı derleyicisi listenin yerleşik bir modül olduğunu bilirse, dinamik aramayı atlayabilir ve amacı doğrudan bayt koduna kodlayabilir, aksi takdirde birkaç katmandan oluşan "a" nın "birleştirme" sini dinamik olarak çözmesi gerekir. çağrı başına devralma (çağrılar arasında birleştirme anlamı değişmiş olabilir, çünkü python dinamik bir dildir).

ne yazık ki, bu soyutlamanın nihai kusuru; Hangi soyutlamayı seçerseniz seçin, soyutlamanız yalnızca çözmeye çalıştığınız sorun bağlamında anlam kazanacaktır ve bu nedenle, onları yapıştırmaya başlarken altta yatan ideolojilerle tutarsız olmayan tutarlı bir soyutlamaya asla sahip olamazsınız. ideolojinizle tutarlı bir görünümde sarmadan. Bunu bilerek, python'un yaklaşımı daha ucuz olduğu için daha esnektir, kendi paketleyicinizi veya kendi ön işlemcinizi yaparak "daha güzel" görünmesini sağlamak için daha fazla ödeme yapmak size kalmıştır.


0

Değişkenler my_listve "-"her ikisi de nesnedir. Özellikle, onlar sınıfların örneklerini konum listve strsırasıyla. joinFonksiyon sınıfa aittir str. Bu nedenle, söz dizimi "-".join(my_list)nesnesi için kullanılır "-"alıyor my_listbir girdi olarak kullanılmaktadır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.