Python coroutine serisi (üç) üzerinden verimin ayrıntılı açıklaması (Python yolu ve makalenin sonuna eklenmiş PDF)

Python coroutine serisi (üç) - verimin ayrıntılı açıklaması

Python gelişmiş öğretici

Makine öğrenme

Derin öğrenme

Metni girin

Python coroutine serisi (üç) - verimin ayrıntılı açıklaması

Feragatname: Bu makale, python coroutine'in uygulama mekanizmasını ayrıntılı olarak açıklayacaktır.Neyle ilgili olduğunu iyice anlamak için, alanın uzunluğu göz önüne alındığında, en basit verimle başlayıp en basit jeneratörle başlayacağız. Çünkü birçok insan böyle bir cümle gördüklerinde kafaları karışıyor, yani "verim de basit bir koroutindir." Neden bu? Bu makale dizisi "python coroutine series" en basit oluşturucu, verim ve verim ile başlayacak ve daha sonra asyncio uygulamasını ayrıntılı olarak açıklayacaktır. Bu makale esas olarak verimin ayrıntılı olarak gerçekleştirilmesinin ne olduğunu, işlevinin ne olduğunu, gerçekleştirme motivasyonunun ne olduğunu açıklar ve bunu katman katman ortaya çıkaracaktır.

içindekiler

1. Verimin basit bir uygulaması 2. 2.1'den gelişmiş getiri uygulamaları Üreticinin getiri değeri elde edilemiyor 2.2 Verim ile gerçekleştirilen veri iletim kanalı 2.3 Verimin ikinci dezavantajı 3. Verim kullanımının bir örneği

01

Basit verim uygulaması

Önceki yazı dizilerinden, verimin her seferinde "tembelce dönen" bir değer olduğunu öğrendik. Aslında, verimin yükseltilmiş ve iyileştirilmiş bir versiyonu olduğu adından da anlaşılıyor. Verimi "getiri" olarak anlıyorsanız, o zaman Verim, genel verim sözdizimini oluşturan "şeyden getiri (üretici)" anlamına gelir, yani

jeneratörden elde edilen verim

Böyle bir form. Basit bir örnek üzerinden bakalım:

def generator2 (): generator1'den verim'a'yield'b'yield'c'yi aldı1 () # yinelenebilir öğe için özde eşdeğerdir: getiri öğesinden elde edilen verimin kısaltılmış hali (12,23,34) generator2 () 'deki i için aralık (3)' ten verim: print (i, end = ',') '' 'İşlemin sonucu: a, b, c, 0, 1, 2, 3, 4, 5, 6 , 7, 8, 9, 11, 22, 33, 44, 12, 23, 34, 0, 1, 2, '' '

sonuç olarak:

Yukarıdaki koddan kitabı okuyabilir, verinin ardından "oluşturucu, tuple, liste, range () işlevi tarafından oluşturulan sıra ve diğer yinelenebilir nesneler" gelebilir.

Basitçe söylemek gerekirse, jeneratörden verim. Aslında, başka bir jeneratör döndürür. Ve verim sadece bir element döndürür. Bu düzeyden, aşağıdaki eşdeğerlik ilişkisi vardır: yinelenebilir üründen elde edilen getiri, temelde yinelenebilir öğe için eşdeğerdir: getiri öğesi.

02

Gelişmiş verim uygulaması

Elbette, verim, verimin yükseltilmiş ve geliştirilmiş bir versiyonu olarak adlandırıldığından, sadece yukarıdaki etki ise, açıkça bu yeterli değildir, çünkü yalnızca bir veya iki kod cümlesini basitleştirir. Serideki bir önceki makale verim eksikliklerini açıkladı, bir önceki makaleye bakın: python coroutine serisi (2)

Verim resmi olarak eksiklikleri gidermeyi hedefliyor.

Gelişmiş verim uygulaması

2.1 Üreticinin getirisinin dönüş değeri yiled için elde edilemez

Hepimiz biliyoruz ki, getiri oluşturucuyu kullanırken, oluşturucuyu yinelemek için for deyimini kullanırsanız, bunun StopIteration istisnasını açıkça başlatmayacağını, ancak StopIteration istisnasını otomatik olarak yakalayacağını, dolayısıyla bir dönüşle karşılaşırsanız, yinelemeyi sonlandıracağını ve Hiçbir istisna tetiklenmez, bu nedenle dönüş değerini almanın bir yolu yoktur. aşağıdaki gibi:

def my_generator (): aralıktaki i için (5): eğer i == 2: eğer i == 2: return 'kesintiye uğramak zorunda kaldım' else: idef main (oluşturucu) verin: try: for i in generator: # açıkça bir istisnayı tetiklemeyecek , Bu nedenle, StopIteration dışında, exc: print (exc.value) g = my_generator () #call main (g) '' 'Çalışan sonuç: 01' '' dışında print (i) dönüş değerini almak imkansızdır.

Yukarıdaki örnekten görülebileceği gibi, for iteration ifadesi açıkça bir istisnayı tetiklemez, bu nedenle dönüş değeri elde edilemez.Iterasyon 2'ye ulaştığında return ifadesiyle karşılaşıldığında, StopIteration istisnası dolaylı olarak tetiklenir ve yineleme sonlandırılır, ancak Programda görüntülenmeyecektir.

Ancak, bir seferde yinelemek için next (g) 'yi kullanırsam, açıkça bir istisna tetiklenir, ancak dönüşün dönüş değerini elde etmek için aşağıdakileri yapmam gerekir:

def my_generator (): aralıktaki i için (5): i == 2 ise: return 'Kesmeye zorlandım' else: idef main (oluşturucu): deneyin: print (sonraki (oluşturucu)) # her yineleme için bir Değer, açıkça StopIterationprint (sonraki (oluşturucu)) print (next (generator)) print (next (generator)) print (next (generator)) hariç StopIteration as exc: print (exc.value) #Get döndürülen Değeri g = my_generator () main (g) '' 'Çalışan sonuç: 01 araya girmeye zorlandım' ''

Şimdi, yukarıdakiyle aynı işlevi yerine getirmek için from verimini kullanıyoruz:

def my_generator (): aralıktaki i için (5): i == 2 ise: return 'kesintiye uğramak zorunda kaldım' else: idef wrap_my_generator (jeneratör) üretin: # "oluşturucu" yu saran bir üreteci tanımlayın, Esas olan, oluşturucu sonucu = jeneratörden elde edilen verim # Otomatik olarak StopIteration istisnasını tetikler ve geri dönüşün dönüş değerini ifadeden elde edilen verimin sonucuna atayın, yani sonuç baskısı (sonuç) def main (oluşturucu): jeneratörde j için: baskı (j) g = my_generator () wrap_g = wrap_my_generator (g) main (wrap_g) #call `` 'İşlemin sonucu: 01 Kesmeye zorlandım' ''

Yukarıdaki karşılaştırmadan elde edilen verimin aşağıdaki özelliklere sahip olduğu görülebilir:

(1) Yukarıdaki my_generator, orijinal oluşturucudur ve asıl, arayan kişidir. Verim kullanılırken, yalnızca bu iki işlev söz konusudur, yani "arayan" ve "oluşturucu (koroutin işlevi)" doğrudan etkileşime girer , Başka yöntemler içermez, yani "arayan -- > Üretici işlevi (korutin işlevi) ";

(2) verimini kullanırken, orijinal my_generator için ek bir sarmalayıcı işlevi vardır ve ardından arayan, bu sarmalayıcı işlevi aracılığıyla oluşturucu ile etkileşime girer (daha sonra uygun isimler hakkında konuşacaktır), yani "çağrı Meydan-- > Jeneratör sarmalayıcı işlevi > Üretici işlevi (korutin işlevi) ";

(3) Yineleme yapısından elde edilen verim, yineleme oluşturucunun StopIteration istisnasını dahili olarak otomatik olarak yakalayacaktır. Bu işleme yöntemi, for döngüsü işleme StopIteration istisnası ile aynıdır. Ve yapıdan elde edilen verim için, yorumlayıcı yalnızca StopIteration istisnasını yakalamakla kalmaz, aynı zamanda return ile döndürülen değeri veya StopIteration'ın değer özniteliğinin değerini, yukarıdaki sonuç olan ifade veriminin değerine çevirir.

Gelişmiş verim uygulaması

2.2 Verimle gerçekleştirilen veri iletim kanalı

Yukarıda özetlenen özellikler, verim ve verimin veri etkileşimi yöntemini tanıtmıştır. Verim, "arayan ve oluşturucu" arasındaki etkileşimi içerir. Jeneratör, değeri next () çağrısı yoluyla arayan kişiye döndürür ve Arayan, veriyi send () yöntemi ile jeneratöre gönderir;

Ancak getiri için üçüncü taraf bir işlev de vardır: Aşağıdakiler ilgili kavramlarla başlayacaktır.

PEP 380'de, verimde kullanılan bazı özel terimler kullanılmaktadır:

Yetki verilmiş jeneratör: verimi içerir < tekrarlanabilir > İfadenin oluşturucu işlevi; yani yukarıdaki wrap_my_generator oluşturucu işlevi

Alt oluşturucu: ifade veriminden < tekrarlanabilir > Kısmen edinilmiş jeneratör; yukarıdaki my_generator jeneratör işlevi

Arayan: delege oluşturucunun müşteri kodunu çağırın; yani yukarıdaki ana oluşturucu işlevi

Aşağıdaki şekil, bu üçü arasındaki etkileşimi göstermektedir (blog bahçesinden alınmıştır):

Delege oluşturucu, ifade veriminde durakladığında, arayan, verileri doğrudan alt üretecine gönderebilir ve alt oluşturucu, çıktı değerini arayana gönderir. Alt üreteç döndükten sonra, yorumlayıcı bir StopIteration istisnası atacak ve dönüş değerini istisna nesnesine ekleyecektir.Bu anda, delege oluşturucu devam edecektir.

sonuç olarak:

(1) Verim, temel olarak işlem görevlerini alt oluşturuculara devretmek için tasarlanmıştır, ancak işlemlerin herhangi bir yinelenebilir nesneye delege edilebilmesi için verim;

(2) Bir delegasyon oluşturucu (grup) bir boru hattına eşdeğerdir, bu nedenle herhangi bir sayıda delegasyon jeneratörü birbirine bağlanabilir - bir delegasyon jeneratörü, bir alt jeneratörü çağırmak için verimi kullanır ve alt üreticinin kendisi de bir delege neslidir Jeneratör, verimini kullanarak başka bir jeneratörü çağırın.

Gelişmiş verim uygulaması

2.3 Verimin ikinci dezavantajı

Önce ne ifade etmek istediğine bir bakın. Sınırlaması, doğrudan arayan kişiye bir seferde yalnızca bir değer verebilmesidir. Bu, verim içeren kodun diğer kodlar gibi ayrı bir işleve ayrılamayacağı anlamına gelir. Bu, tam olarak hangi verimin çözülmek istediğidir. Ayrıntılar için yukarıya bakın:

https://blog.csdn.net/qq_27825451/article/details/85234610

Bu cümlenin anlaşılması gerçekten zor, ama aslında ifade etmek istediği şey şudur: çünkü üretici, tanımı gereği sıradan bir işlev gibidir, o zaman sıradan bir işlev olduğu için, tekrar tekrar çağrılabilmelidir. , Ancak jeneratör çalışmıyor. Öyleyse neden verim bu sorunu çözebilir, çünkü esas olarak verim herhangi bir jeneratör tarafından takip edilebilir, yani verim herhangi bir görevi herhangi bir jeneratör işlevine atayabilir, böylece alt jeneratörün doğrudan arayan kişiye kaçınması Tek bir değerin döndürüldüğü durum.

(Not: Bunu çok net anladığımı sanmıyorum. Kim görürse görürse, umarım ona her türlü tavsiyede bulunabilirim)

03

Örnek verim kullanımı

Aslında, verimin en önemli rolü bir "veri aktarım hattı" sağlamaktır.Aşağıdaki basit bir örnek, bunun neden bir boru hattı olduğunu açıklamaktadır:

def ortalama (): toplam = 0.0 # Sayıların toplamı = 0 # Sayıların sayısı ort = Yok #Ortalama True while: num = verim ortalama + = numcount + = 1avg = toplam / sayım def wrap_average (oluşturucu): getiri generator # Ortalama fonksiyona bir değer gönderilecek bir fonksiyon tanımlayın def main (wrap): print (next (wrap)) # Generator print (wrap.send (10)) # 10print (wrap.send (20)) # 15print (wrap.send (30)) # 20print (wrap.send (40)) # 25g = average () wrap = wrap_average (g) main (wrap) '' 'Çalışan sonuç: None10.015.020.025.0' ' '

Yukarıdan, arayan tarafından gönderilen verilerin wrap_average'a gönderildiğini bulabiliriz, neden hala üreteç fonksiyon ortalamasında? Bu, "veri iletim hattının işlevidir". Yani, ana işlev çağıran ana her bir değeri gruplayıcıya iletir ve aktarılan değer nihayet ortalama işlevine ulaşır; gruplayıcı hangi değerin iletildiğini bilmez, çünkü yukarıdaki koddan, sarma_ortalama işlevinin bunu hiç ele almadığını görebiliriz Herhangi bir kodun değeri!

"Veri aktarım hattını" şimdi daha iyi anlıyor musunuz?

Geely'nin yeni coupe SUV önizlemesi yayınlandı: yakıt tüketimi CR-V'den yalnızca 1,2 litre daha yüksek
önceki
Başkent Havaalanına top mu atacaksın? Netease News'in 6 operasyonu var
Sonraki
Şişirmeye ve reklama dayanamıyor musunuz? Bu Weibo müşterileri resmi olarak kullanmaktan daha iyidir
Telefonunuz ne zaman Android 8.0'a yükseltilebilir? Üreticiler ne diyor
Intel'in katili: Sizi anakartı değiştirmeye zorlayın! Eski kullanıcılar sersemlemiş ağlıyor
94 yıldır ilk kez gece açılan Yasak Şehir web sitesi çöktü! Netizenler oylar için 4000 yuan harcamaya hazır
Yeterli bir bütçe iyidir ve inanç dolu olabilirsiniz! 6000 yuan oyun konsolu yapılandırması
GTX960, 3000 yuan giriş seviyesi oyun konsolu yapılandırma ekranından kurtulun
Vivo X20Plus İncelemesi Vivo X20Plus Satın Almaya Değer mi?
Cep telefonu endüstrisinin kralları duygularını ancak şimdi satabildi mi?
Altıncı nesil i3 + GTX1050, 3200 yuan giriş seviyesi oyun yapılandırma ekranı
Sadece zaman çok kısa, yoksa iyidir! DOBBY cep drone uçuş deneyimi
2133 ve 2400 bellek konusunda endişelenmeyin, i56500 işlemciler kullanılabilir
Mezunların% 50'sinden fazlası yeni birinci kademe şehirleri seçiyor ve 7116 yuan maaş bekliyor
To Top