C # 'da StringBuilder gibi Python string sınıfı?


Yanıtlar:


102

Bire bir korelasyon yoktur. Gerçekten iyi bir makale için lütfen Python'da Efficient String Concatenation'a bakın :

Python programlama dilinde uzun dizeler oluşturmak bazen kodun çok yavaş çalışmasına neden olabilir. Bu makalede, çeşitli dizi birleştirme yöntemlerinin hesaplama performansını araştırıyorum.


27
Bu makalenin Python 2.2'ye göre yazıldığını unutmayın. Testler, Python'un modern bir sürümünde muhtemelen biraz farklı çıkacaktır (CPython genellikle başarılı bir şekilde birleştirmeyi optimize eder, ancak buna önemli kodda güvenmek istemezsiniz) ve bir liste anlayışını kullandığı bir jeneratör ifadesi dikkate alınmaya değer olacaktır. .
Mike Graham

4
Bu makaledeki bazı önemli noktaları, en azından birkaç uygulamayı (bağlantı çürümesi sorunlarından kaçınmak için) çekmek iyi olacaktır.
jpmc26

3
Yöntem 1: resultString + = appendString, aşağıdaki @ Antoine-tran tarafından yapılan testlere göre en hızlısı
Justas

5
Alıntınız soruya hiç cevap vermiyor. Yeni yönergelere uymak için lütfen yanıtınıza ilgili bölümleri ekleyin.
Fund Monica'nın Davası

27

Oliver Crow kodunu (Andrew Hare tarafından verilen bağlantı) kullandım ve Python 2.7.3'ü uyarlamak için biraz uyarladım. (timeit paketini kullanarak). Kişisel bilgisayarımda koştum, Lenovo T61, 6GB RAM, Debian GNU / Linux 6.0.6 (sıkıştır).

İşte 10.000 yinelemenin sonucu:

method1: 0,0538418292999 saniye
işlem boyutu 4800 kb
method2: 0,22602891922 saniye
işlem boyutu 4960 kb
method3: 0,0605459213257 saniye
işlem boyutu 4980 kb
method4: 0,0544030666351 saniye
işlem boyutu 5536 kb
method5: 0,0551080703735 saniye
işlem boyutu 5272 kb
method6: 0,0542731285095 saniye
işlem boyutu 5512 kb

ve 5.000.000 yineleme için (yöntem 2, sonsuza kadar olduğu gibi çok yavaş çalıştığı için göz ardı edildi):

yöntem1: 5,88603997231 saniye
işlem boyutu 37976 kb
method3: 8.40748500824 saniye
işlem boyutu 38024 kb
method4: 7.96380496025 saniye
işlem boyutu 321968 kb
method5: 8.03666186333 saniye
işlem boyutu 71720 kb
method6: 6.68192911148 saniye
işlem boyutu 38240 kb

Python adamlarının dize birleştirmeyi optimize etmek için oldukça iyi bir iş çıkardığı oldukça açıktır ve Hoare'nin dediği gibi: "erken optimizasyon tüm kötülüklerin köküdür" :-)


2
Görünüşe göre Hoare şunları
Pimin Konstantin Kefaloukos

5
Hassas, tercümana bağlı optimizasyonlardan kaçınmak için erken bir optimizasyon değildir. Hiç PyPy'ye geçmek veya optimizasyon için pek çok ince başarısızlık durumundan birine ulaşma riskini almak istiyorsanız , işleri doğru şekilde yapın.
Veedrac

1
Görünüşe göre Yöntem 1, derleyicinin optimize etmesi için daha kolay.
mbomb007

25

Derleyici optimizasyonlarına güvenmek kırılgandır. Kabul edilen cevapta ve Antoine-tran tarafından verilen sayılarda bağlantılı kriterlere güvenilmeyecektir. Andrew Hare repr, yöntemlerine bir çağrı da dahil etme hatasını yapar . Bu, tüm yöntemleri eşit derecede yavaşlatır, ancak dizeyi oluştururken gerçek cezayı gizler.

Kullanın join. Çok hızlı ve daha sağlam.

$ ipython3
Python 3.5.1 (default, Mar  2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python.

In [1]: values = [str(num) for num in range(int(1e3))]

In [2]: %%timeit
   ...: ''.join(values)
   ...: 
100000 loops, best of 3: 7.37 µs per loop

In [3]: %%timeit
   ...: result = ''
   ...: for value in values:
   ...:     result += value
   ...: 
10000 loops, best of 3: 82.8 µs per loop

In [4]: import io

In [5]: %%timeit
   ...: writer = io.StringIO()
   ...: for value in values:
   ...:     writer.write(value)
   ...: writer.getvalue()
   ...: 
10000 loops, best of 3: 81.8 µs per loop

Evet, reprçağrı çalışma süresine hakimdir, ancak hatayı kişiselleştirmeye gerek yoktur.
Alex Reinking

3
@AlexReinking üzgünüm, kişisel hiçbir şey ifade etmedi. Kişisel olduğunu düşünmeni neyin sağladığından emin değilim. Ancak isimlerinin kullanımıysa, bunları yalnızca kullanıcının cevaplarına başvurmak için kullandım (kullanıcı adlarıyla eşleşiyor, daha iyi bir yol olup olmadığından emin değilim).
GrantJ

1
veri başlatma ve birleştirme işlemlerini ayıran iyi zamanlama örneği
aiodintsov

19

Python, benzer amaçları yerine getiren birkaç şeye sahiptir:

  • Parçalardan büyük dizeler oluşturmanın yaygın bir yolu, dizelerin bir listesini büyütmek ve işiniz bittiğinde buna katılmaktır. Bu, sık kullanılan bir Python deyimidir.
    • Biçimlendirmeyle verileri birleştiren dizeler oluşturmak için biçimlendirmeyi ayrı yaparsınız.
  • Bir karakter düzeyinde ekleme ve silme için, bir uzunluktaki dizelerin bir listesini tutarsınız. (Bunu bir dizeden yapmak için çağırırsınız list(your_string). Bunun için de kullanabilirsiniz UserString.MutableString.
  • (c)StringIO.StringIO aksi takdirde dosya alacak şeyler için kullanışlıdır, ancak genel dizgi oluşturma için daha azdır.

10

Yukarıdaki yöntem 5'i (Sözde Dosya) kullanarak çok iyi performans ve esneklik elde edebiliriz

from cStringIO import StringIO

class StringBuilder:
     _file_str = None

     def __init__(self):
         self._file_str = StringIO()

     def Append(self, str):
         self._file_str.write(str)

     def __str__(self):
         return self._file_str.getvalue()

şimdi kullanıyorum

sb = StringBuilder()

sb.Append("Hello\n")
sb.Append("World")

print sb


-1

Açık bir analog yok - bence dizi birleştirmeleri (muhtemelen daha önce söylendiği gibi optimize edilmiş) veya üçüncü taraf sınıf (çok daha verimli olduklarından şüpheliyim) kullanmanız bekleniyor - python'daki listeler dinamik tipte olduğundan hızlı çalışma yok sandığım gibi arabellek için char []). Stringbuilder benzeri sınıflar, birçok dildeki dizelerin doğuştan gelen özelliği (değişmezlik) nedeniyle erken optimizasyon değildir - bu birçok optimizasyona izin verir (örneğin, dilimler / alt dizeler için aynı arabelleğe başvurma). Stringbuilder / stringbuffer / stringstream benzeri sınıflar, dizeleri birleştirmekten çok daha hızlı çalışır (hala ayırmalara ve çöp toplamaya ihtiyaç duyan birçok küçük geçici nesneler üretir) ve hatta printf benzeri araçları dize biçimlendirir; birçok format çağrısı.


-4

Python'da hızlı bir dizgi birleştirme yöntemi arıyorsanız, o zaman özel bir StringBuilder sınıfına ihtiyacınız yoktur. Basit birleştirme, C # 'da görülen performans cezası olmadan da aynı şekilde çalışır.

resultString = ""

resultString += "Append 1"
resultString += "Append 2"

Bkz Antoine-Tran cevabı performans sonuçları için

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.