Yazar | Tianyuan Prodigal Son
Editör | Liu Jing
Üretildi | CSDN Blogu
Önsöz
Bekarlar Günü yaklaşıyor İnsanları tanıtmaya gelince, sanırım Uncle Passion'un evinden Bayan Sınıfı (sınıf) ve Küçük Kardeş (def) düşünmüşsünüzdür. Başını belaya sokma, ciddi ol! Bugünkü konumuz erkek ve kadın arkadaşları tanıtmak değil, programcıların genellikle OOP dediği nesne yönelimli programlamanın nasıl yapılacağını açıklamaktır.
Öncüllerin Nesne Yönelimli Programlamayı neden nesne yönelimli programlamaya dönüştürdüklerini bilmiyorum, bu yüzden tek programcılar genellikle ekrandaki yakışıklı adamların ve güzelliklerin gelecekte karşılaşacakları nesneler olduğu yanılsamasına kapılırlar. Bunu söyledikten sonra, bilgisayar terminolojisinin Tayvan'daki meslektaşlarından çevrilmesinin daha uygun olduğunu düşünüyorum. Örneğin önbellek, biz ona "önbellek" diyoruz, diğerleri ise "önbellek", kulağa hoş geliyor. Tayvanlı meslektaşları, OPP'yi "nesne yönelimli programlama" olarak tercüme eder - eşit derecede açık olmasa da, en azından tek programcıların "nesnelere" sahip olmama zahmetini geçici olarak unutmasına neden olabilir.
Biraz tuz, bu blogcu resmi olarak nesneleri herkes için tanıtmaya başladı.
Sınıflar ve nesneler kavramı
Nesneye yönelik programlamayı öğrenmek için önce nesnenin ne olduğunu anlamalısınız? Sınıf nedir? Örnekleme ne anlama geliyor? Aşağıdaki şekil, OOP'nin bu temel kavramlarını anladığımı ifade ediyor (aslında uzlaşmanın sonucudur - bunu meslektaşlarımla uzun süre tartıştım ve duvardan Wikipedia'ya atıfta bulundum).
Sınıf, uğraşmak istediğimiz nesnel şeylerin bir soyutlamasıdır. Bir sınıf, aynı özelliklere ve yöntemlere sahip bir nesne koleksiyonunu tanımlamak için kullanılır ve koleksiyondaki her nesne için ortak olan özellikleri ve yöntemleri tanımlar. Bir nesne, bellekteki bir sınıfın bir örneğidir ve bir sınıf, birden çok nesneye örneklenebilir. Sınıflar soyuttur ve hafızayı almazken, nesneler somuttur ve depolama alanı kaplar.
Sınıf üyesi
Python'a yeni başlayan biri olarak, enerjinizi şaşırtıcı kavramlara harcamanıza gerek yoktur, yalnızca sınıfları kullanmanın temel öğelerinde ustalaşmanız gerekir. Önümüzdeki günlerde, OOP'nin derinliğini yavaş yavaş takdir etmek için yeterli zamanınız olacak. Tecrübe birikimi ile OOP doğal olarak düşünme aracınız haline gelecektir.
Aşağıdaki kod, A adlı bir sınıfı tanımlar. Tüm sınıfların kurucuları ve yıkıcıları vardır.Ayrıca üye işlevler ve üye değişkenler de içerebilirler. Üye işlevlere bir sınıfın yöntemi ve üye değişkenleri bir sınıfın özellikleri olarak çağırmayı seviyorum.
a sınıfı: def __init __ (öz): "" "Yapıcı" "" self.a = 10 # bir üye değişkeni a tanımlar def getA (öz): "" "Üye İşlevi" "" baskı ("a =% d"% self.a) def __del__: "" "Yıkıcı" "" print ("nesneyi sil") a = A a.getABir sınıf bir nesne olarak somutlaştırıldığında, önce kurucu çalıştırılır ve nesne yok edildiğinde, yıkıcı otomatik olarak çalıştırılır. Genel olarak, yapıcıda başlatma çalışması yapacağız ve yıkıcıda temizleme işi yapacağız.
Bunu okuduktan sonra, birçok yeni başlayan kesinlikle şunu söyleyecektir: Bir sınıfı tanımladığımda, bir kurucu yazdım ama asla bir yıkıcı yazmadım Neden tüm sınıfların bir kurucusu ve bir yıkıcısı olduğunu söylüyorsunuz? Bu doğru, bir sınıfı tanımlarken, bir kurucu ve bir yıkıcı yazmasak bile, bu iki yöntem hala mevcuttur (yıkıcı biraz özeldir ve onu doğrudan göremeyiz - kendimiz tanımlamadığımız sürece). Yapıcı ve yıkıcıyı kendimiz tanımlarsak, sistem tarafından otomatik olarak atanan iki işlevi değiştirecektir. Aşağıdaki örnek, gizemi açıkça göstermektedir: A Sınıfının ne kurucusu ne de yıkıcısı vardır ve B sınıfının yalnızca bir yıkıcısı vardır. Her iki sınıf da sınıf örnekleri oluşturabilir veya her ikisi de yok edilebilir ve önce b Özel bir yıkıcı denir.
> > > a sınıfı: geçmek > > > a = A > > > del a > > > a Geri izleme (en son çağrı son): Dosya " < Pyshell # 70 > ", 1. satır, içinde < modül > a NameError: name'a 'tanımlı değil > > > B sınıfı: def __del__ (öz) : print ('Yıkıcıyı çalıştır, sahneyi temizle') > > > b = B > > > del b Yıkıcıyı yürüt, sahneyi temizle > > > b Geri izleme (en son çağrı son): Dosya " < Pyshell # 75 > ", 1. satır, içinde < modül > b NameError: name'b 'tanımlı değilYeni tarz ve eski tarz
PY2'de yeni stil ve eski stil olmak üzere iki tür sınıf vardır. Yeni stil sınıfın, sanal sınıf Object'ten miras alması gerekirken, eski stil sınıfın bunu yapmaması gerekir. PY2'de sınıf yazmanın üç yolu vardır:
A sınıfı (nesne): yeni stil sınıf yazma A sınıfı: Eski stil sınıf yazısı A sınıfı: Eski stil sınıf yazısıPY3'te yalnızca yeni tarz sınıflar vardır ve eski tarz sınıflar artık desteklenmemektedir. Nesne yazısını miras almaya alışkınsanız, hiçbir sorun yoktur. Yukarıdaki üç yazma yönteminin tümü PY3'te yeni stil sınıfları olarak yorumlanır. Yeni tarz ile eski tarz arasındaki temel farklar şunlardır:
Yeni stil sınıf, Object yapıcısını ve yıkıcısını miras alabilir.Sınıfın yapıcısı ve yıkıcısının özel bir işi yoksa, bunlar çıkarılabilir. Eski tarz sınıf şunları yapamaz:
Şu anda PY2 ile çalışırken bir hata oluşacaktır: AttributeError: A sınıfının '__ init__' niteliği yoktur, PY3 kullanılırken bu hata oluşmaz. Yeni bir yazı türüne değiştirilirse:
A sınıfı (nesne): def print (kendi kendine): baskı ("Ben A") B (A) sınıfı: def __init __ (öz): A .__ init __ (kendi) b = BHala PY2 ile çalışıyor, hiçbir hata olmayacak.
Yeni stil sınıflar süper kullanabilir:
Çoklu kalıtımda, her bir ana sınıfın başlatma ve işlev arama sırası farklıdır: eski tarz sınıf derinlik öncelikli kalıtımdır ve yeni tarz sınıf, en önce kalıtımdır.
Statik değişkenler ve örnek değişkenler
Yapıcıda tanımlanan değişkenlere örnek değişkenler denir. Örnek değişkenleri yalnızca somutlaştırmadan sonra kullanılabilir < Nesne adı Değişken adı > Erişim yolu. Statik değişkenler genellikle yapıcıdan bağımsız olarak sınıfın başında tanımlanır. Statik değişkenler olabilir < Nesne adı Değişken adı > Erişim yolu, şunları da yapabilirsiniz: < Sınıf adı Değişken adı > Erişim yolu. Genel olarak, bir sınıfın statik değişkenleri, genellikle sınıfın yöntemleri tarafından kullanılabilen ancak sınıfın yöntemleriyle değiştirilmemesi gereken statik özelliklerini depolamak için kullanılır.
> > > a sınıfı: static_x = 10 # Statik değişken def __init__ (öz) : self.instance_y = 5 # örnek değişkeni > > > a = A > > > a.static_x 10 > > > a.instance_y 5 > > > A.static_x 10 > > > A.instance_y Geri izleme (en son çağrı son): Dosya " < Pyshell # 89 > ", 1. satır, içinde < modül > A.instance_y AttributeError: tür nesnesi '' duruş_y 'özniteliğine sahip değilStatik fonksiyon
Diğer seslerin statik işlevlerinden farklı olarak, her ikisi de dekoratörlerle gerçekleştirilen Python'un iki statik işlevi vardır:
a sınıfı: static_x = 10 def __init__ (öz) : self.y = 10 @hayalhanemersin def staticFuc: baskı (A.static_x) @sınıf def classFuc (cls) : baskı (cls.static_x) A.staticFuc A.classFucStaticmethod işlevi Self parametresini kullanamaz, bu nedenle herhangi bir üye değişkenine erişemez ve yalnızca sınıf adı aracılığıyla sınıfın statik değişkenlerine erişebilir.
Classmethod işlevi de Self parametresini kullanamaz, bu nedenle herhangi bir üye değişkenine erişemez, ancak bir cls parametresine sahiptir. Cls parametresi, bir nesneye bir başvuru değildir, ancak sınıfa bir başvurudur ve sınıfın statik değişkenlerine cls parametresi aracılığıyla erişilebilir.
Nesneye yönelik üç öğe
Nesne yönelimli üç öğeye sahiptir: kalıtım, kapsülleme ve çok biçimlilik. Burada çok fazla kavram var ve bunun hakkında ne kadar çok konuşursanız o kadar kafası karışıyor. Okuyucuyu yanıltmamak için elimden geldiğince açıklamamaya çalışıyorum ve sadece örnekler veriyorum, lütfen kendiniz deneyin.
(1) Kalıtım
Türetilmiş sınıfın yalnızca bir ana sınıfı varsa, bu tek kalıtımdır. Bu, sınıf tanımının en yaygın biçimidir.
sınıf Hayvan: yenilgi (öz) : print ('yiyebilirim') Sınıf Brid (Hayvan): def __init__ (öz) : Animal .__ init __ (kendi) def uçmak (öz) : print ('Uçabilirim') brid = Brid brid.eat brid.flyTüretilmiş sınıfın birden çok üst sınıfı varsa, bu çoklu mirastır.
sınıf Geyik: def showHorns (öz) : print ('boynuzlarım var') sınıf At: def showFace (öz) : baskı ('At yüzüm var') inek sınıfı: def showHoof (öz) : baskı ('toynaklarım var') sınıf Eşek: def showTail (öz) : baskı ('Eşek kuyruğum var') Sınıf Milu (Geyik, At, İnek, Eşek): # Çoklu miras, dört farklı sınıftan türemiştir. def __init__ (öz) : Deer .__ init __ (kendi) Horse .__ init __ (kendi) İnek .__ init __ (kendi) Eşek .__ init __ (kendi) milu = Milu milu.showHorns milu.showFace milu.showHoof milu.showTailİster tekli kalıtım isterse çoklu kalıtım olsun, türetilmiş sınıftaki üst sınıfın işlevini geçersiz kılabilirsiniz - buna kapsam denir.
(2) Paket
Sözde kapsülleme, sınıfın üye değişkenlerini ve üye işlevlerini entegre etmek ve anahtar bilgisini korumak veya gizlemektir. Üç bilgi koruma veya gizleme düzeyi vardır: genel, korumalı ve özel. C ++ deneyiminiz varsa, önce C ++ bilgi gizleme kurallarını gözden geçirelim:
Genel üyeler: sınıf dışındaki herhangi bir kod tarafından görülebilir;
Korumalı üyeler: sınıf dışındaki herhangi bir koda görünmez, ancak türetilmiş sınıflar tarafından görülebilir;
Özel üyeler: Sınıfın dışına ve türetilmiş sınıflara görünmez.
Bu üç seviyeye karşılık gelen Python şu şekilde tanımlanır:
İngilizce harflerle başlayan üyeler halka açık üyelerdir
Alt çizgiyle başlayan üyeler korumalı üyelerdir
İki alt çizgi anahtarı olan üyeler özel üyelerdir
Python'un bilgi korumasının veya gizleme kurallarının etkili olup olmadığını görmeye çalışalım.
> > > A sınıfı (nesne): def __init__ (öz, a, b, c) : self.a = 10 # public self._b = b # koruma self .__ c = c # özel def getA (öz) : # Halka açık kendine dön. a def setA (öz, a) : # Halka açık self.a = a def getB (öz) : # Halka açık kendine dön._b def _setB (kendisi, b) : # Koruma self._b = b def getC (öz) : # Halka açık self .__ c def __setC (kendisi, c) : # Özel self .__ c = c > > > a = A (10, 20, 30) > > > B (A) sınıfı: geçmek > > > b = B (10, 20, 30)Genel üyelere erişmeye çalışın:
> > > a.a 10 > > > a.getA 10 > > > a.setA (5) > > > a.a 5 > > > b.a 10 > > > b.getA 10 > > > b. setA (5) > > > b.a 5Genel üyeler için erişim kuralları C ++ ile aynıdır. Önce korunan üyeleri atlayın ve özel üyelere bakın:
> > > AC Geri izleme (en son çağrı son): Dosya " < küçük resim # 85 > ", 1. satır, içinde < modül > AC AttributeError: 'Bir' nesnesinin '__ c' özniteliği yok > > > a.getC 30 > > > a .__ setC (5) Geri izleme (en son çağrı son): Dosya " < Pyshell # 87 > ", 1. satır, içinde < modül > a .__ setC (5) AttributeError: 'Bir' nesnesinin '__ setC' niteliği yok > > > M.Ö Geri izleme (en son çağrı son): Dosya " < pijama # 88 > ", 1. satır, içinde < modül > M.Ö AttributeError: 'B' nesnesinin '__ c' niteliği yok > > > b.getC 30 > > > b .__ setC Geri izleme (en son çağrı son): Dosya " < Pyshell # 90 > ", 1. satır, içinde < modül > b .__ setC AttributeError: 'B' nesnesinin '__ setC' niteliği yokÖzel üyeler için erişim kuralları da C ++ ile aynıdır. Öyleyse neden üyeleri korumayı atladım? Dene:
> > > a._b 20 > > > a._setB (5) > > > a._b 5Bunu görmek doğru değil, sadece sınıfın içindeki kod ve türetilmiş sınıflar kullanılabilir.Doğrudan nasıl kullanılabilir? Evet, Python'un korumalı üye erişim kuralları gerçekten C ++ 'lardan farklıdır. Python'un korunan üyelerinin mekanizması nedir? Python'un OOP'sinde üyeleri korumakla kamu üyeleri arasında hiçbir fark olmadığı ortaya çıktı. Koruma kuralı yalnızca xxx içe aktarım * için geçerlidir.
testA.py
A sınıfı (nesne): geçmek sınıf _B (nesne): geçmektestB.py
testA içe aktarımından * a = A b = _BTestB.py yürütülürken:
Geri izleme (en son çağrı son): "TestB.py" dosyası, satır 4, içinde < modül > b = _B NameError: name'_B 'tanımlı değilŞu anda, koruma üyesi _B korunmaktadır. Ancak bu durum yalnızca xxx'den içe aktarma * için geçerlidir. TestB.py böyle yazıyorsa:
testB.py
testA'dan içe aktarma A, _B a = A b = _Bveya:
ithalat testiA a = testA.A b = testA._BSorun yok.
(3) Polimorfizm
Ana sınıf birden fazla türetilmiş sınıfa sahip olduğunda ve türetilmiş sınıfların tümü aynı üye işlevini uyguladığında, polimorfizm elde edilebilir:
H2O sınıfı (nesne): def ne (öz): baskı ("Ben H2O'yum") Sınıf Su (H2O): def ne (öz): baskı ("Ben suyum") Sınıf Buz (H2O): def ne (öz): baskı ("Ben buzum") Sınıf Su Buharı (H2O): def ne (öz): print ("Ben su buharıyım"); def ne (obj): obj.what objs = obj içindeki obj için: ne (obj)Soyut sınıf
Soyut sınıflar somutlaştırılamaz, yalnızca diğer sınıflar tarafından bir ana sınıf olarak miras alınabilir ve türetilmiş sınıfların soyut sınıftaki tüm üye işlevleri uygulaması gerekir. Soyut uygulama senaryosu nedir? Veri indirmek için birçok komut dosyası eklentisi yaptım. Farklı veri kaynakları farklı komut dosyaları kullanır. Tüm bu komut dosyaları aynı ada sahip yöntemler gerektirir. Şu anda soyut sınıflar kullanışlı oluyor.
> > > abc içe aktar > > > A sınıfı (nesne, metasınıf = abc.ABCMeta): @ abc.abstractmethod def a (öz): geçmek @ abc.abstractmethod def b (öz): geçmek > > > C sınıfı (A): def a (öz): baskı ("a") > > > c = C Geri izleme (en son çağrı son): Dosya " < Pyshell # 127 > ", 1. satır, içinde < modül > c = C TypeError: Soyut yöntemler b ile soyut C sınıfı başlatılamıyorTekli mod
Singleton Pattern (Singleton Pattern) yaygın olarak kullanılan bir yazılım tasarım modelidir.Bu modelin temel amacı, belirli bir sınıfın yalnızca bir örneğinin var olmasını sağlamaktır. Tüm sistemde belirli bir sınıfın yalnızca bir örneğine sahip olmak istediğinizde (bir yazılım yapılandırma sınıfı gibi, yazılımda nerede somutlaştırılmış olursa olsun, her zaman bu tek nesne olacaktır), tekil desen kullanışlı olabilir. Örneğin, Python günlük modülündeki günlük nesnesi veya zaman uyumsuz iletişim çerçevesi Twisted'daki reaktörün tümü tipik tekil modellerdir - ancak aşağıdaki şekilde uygulanmaları gerekmez.
Python, dekoratörleri kullanarak tekli kalıbı kullanabilir:
def Singleton (cls): _instance = {} def _singleton (* args, ** kargs): cls _instance içinde değilse: _instance = cls (* args, ** kargs) return _instance dönüş _singleton @Hayalhanemersin sınıf Yapılandırması (nesne): geçmek cfg1 = Yapılandırma cfg2 = Yapılandırma baskı (cfg1, cfg2'dir)postscript
Şimdiye kadar birkaç konuya değinelim. CSDN bize sadece böyle bir iletişim platformu sağlamakla kalmaz, aynı zamanda sık sık çeşitli teknik değişim faaliyetleri başlatır. Yakın gelecekte, Python acemileriyle GeekTalk sütununda nasıl hızla sağlam ve güçlü bir programcı haline gelebileceğimizi tartışacağım. CSDN ayrıca bu etkinlik için bazı hediyelik eşyalar da sağladı. Eğer ilgileniyorsanız, lütfen katılmak için kodu tarayın:
Telif hakkı bildirimi: Bu makale, CSDN blog yazarı "Tianyuan Prodigal Son" un orijinal makalesidir.
SON