Python Programlama Diline Giriş IV
Python
Programlama Diline Giriş IV
Merhaba
Arkadaşlar. Bu haftadaki konularımız.
1 Sınıf Nesnelerinin Örnek Özniteliklerinin
Oluşturulması
2 Dunder (Double Underscore) Terimi
3 Sınıf Kullanımına Bir Örnek: Python Standart
Kütüphanesindeki date Sınıfı
4 Sınıf Kullanımına Bir Örnek Daha: Python'ın
Standart Kütüphanesindeki datetime Sınıfı
5 Sınıflar Değiştirilebilir (Mutable) Türlerdir
6 Sınıfın Öznitelikleri ve Nesnenin Örnek
Öznitelikleri
7 Sınıf İsimlerinin Anlamı
8 Sınıflar Arasındaki İlişkiler
9 object Sınıfı
10 Python'da Çoklu Türetme (Multiple Inheritance)
11 Taban ve Türemiş Sınıflarda Aynı İsimli
Elemanların Bulunması Durumu
12 Overload ve Override Kavramları
13 super Fonksiyonu
14 Python'da Kapsülleme (Encapsulation) ve Örnek
Özniteliklerinin Dışarıdan Gizlenmesi (Data Hiding)
15 Python'da Çokbiçimlilik (Polymorphism)
16 Sınıfların static Metotları ve Sınıf Metotları
17 Python'da Dekoratörler
18 Fonksiyon ve Metot Dekoratörleri
19 Sınıf Dekoratörleri
20 Python'da Dosya İşlemleri
Sınıf Nesnelerinin Örnek
Özniteliklerinin Oluşturulması
Bir sınıf nesnesine özgü olan onun bir parçasını
oluşturan nesnelere (elemanlara) "örnek öznitelikleri (instance attribute)"
denilmektedir. Sınıf içerisinde bildirilen değişkenlere ise Python
terminolojisinde "sınıf öznitelikleri dendiğini anımsayınız.
Sınıf içerisinde yaratılan bu değişkenler belli bir
sınıf nesnesinin değil o sınıfın elemanlarıdır. Halbuki örnek öznitelikleri o
sınıf türünden nesnenin parçalarını oluşturmaktadır.
Öznitelikleri
diğer programlama dillerindeki veri elemanlarına (data member)
benzetebilirsiniz. Bu bağlamda örneğin örnek öznitelikleri C++, Java ve C#'taki
static olmayan veri elemanlarına, sınıf öznitelikleri de static veri
elemanlarına işlevsel olarak benzemektedir.
Pekiyi Python'da bir sınıf türünden nesnenin belli
bir özniteliği nasıl oluşturulmaktadır? Python'da diğer dillerdeki gibi işin
başında örnek özenitelikleri (veri elemanları) bildirilmezler. Bir sınıf
türünden değişken ile aşağıdaki gibi nokta operatörü kullanılarak ilk kez atama
yapıldığında o örneğe ilişkin örnek özniteliği oluşturulmuş olur. Bu işlemin
genel biçimi şöyledir:
class Point:
pass
pt = Point()
pt.x = 10 # pt nesnesinin x isimli
bir özniteliğini oluşturduk
pt.y
= 20 # pt nesnesinin y isimli
bir özniteliğini oluşturduk
print("x
= {}, y = {}".format(pt.x,
pt.y))
Burada önce Point sınıfı türünden bir pt nesnesi
yaratılmıştır. Bu kullanılarak pt.x ve pt.y ifadelerine atama yapıldığında bu
nesnenin x ve y öznitelikleri oluşturulmuş olur. Örnek öznitelikleri yaratılan
sınıf nesnesinin parçalarını oluşturmaktadır.
Dunder (Double Underscore) Terimi
Python'da
başında ve sonunda iki alt tire bulunan özel sınıf metotları vardır. Bu
metotların ismi __xxx__ biçimindedir. Söylerken kolaylık olsun diye bu
metotların isimleri "dunder" terimiyle ifade edilir. Bu durumda
örneğin __init__ metoduna "dunder init" metodu denilmektedir.
Sınıf Kullanımına Bir Örnek: Python
Standart Kütüphanesindeki date Sınıfı
Python'ın
standart kütüphanesinde datetime isimli modüldeki date sınıfı tarih işlemlerini
yapmak için bulundurulmuştur. Sınıfın __init__ metodu nesnenin tutacağı gün, ay
ve yıl bilgisini bizden alır. Bizden aldığı bu bilgileri sınıfın day, month
year isimli örnek özniteliklerine yerleştirir. Örneğin:
Sınıf Kullanımına Bir Örnek Daha:
Python'ın Standart Kütüphanesindeki datetime Sınıfı
datetime modülündeki datetime isimli sınıf hem tarih hem de zaman bilgisini tutan ve bunlar üzerinde işlem yapan bir sınıfıtr. Bir datetime nesnesi sırasıyla yıl, ay, gün, saat, dakika, saniye ve mikrosaniye belirtilerek yaratılmaktadır. Yıl, gün ve ay dışındaki parametreler default sıfır değerini almaktadır. Örneğin:
Sınıflar Değiştirilebilir (Mutable)
Türlerdir
Sınıflar değiştirilebilir (mutable) türlerdir. Yani
sınıfın parçalarını oluşturan örnek öznitelikleri (instance attributes) üzerinde
değişiklikler yapabiliriz. Böylece bu örnek öznitelikleri başka nesnelerin
adreslerini tutar hale getirilebilir. Örneğin:
class Sample:
def __init__(self):
self.a = 10
self.b = 20
s = Sample()
print(s.a, s.b)
# 10, 20
s.a = 100
s.b = 200
print(s.a, s.b) # 100, 200
Bu örnekte biz bir Sample nesnesi yarattık. Bu s
nesnesinin örnek özniteliklerinde (yani s'in parçalarında) değişiklikler yaptık.
s bileşik bir nesnedir. Parçalardan (yani özniteliklerden) oluşmaktadır. s'nin
değiştirilebilir (mutable) bir nesne olması s'nin parçaları üzerinde değişiklik
yapılabileceği anlamına gelmektedir.
Sınıfın Öznitelikleri ve Nesnenin
Örnek Öznitelikleri
Sınıf içerisinde oluşturulan değişkenlere
"sınıfın öznitelikleri (class attributes)" denilmektedir. Sınıfın
öznitelikleri o sınıf türünden bir nesnenin elemanı değildir. Bir sınıfın
içerisinde fakat metotların dışında oluşturulan değişkenler o sınıfın
elemanıdır.
Biz sınıf tanımlaması içerisinde oluşturulan
değişkenleri (yani sınıfın özniteliklerini) hem metotlardan hem de dışarıdan
sınıf ismi ve '.' operatörü ile kullanabiliriz. Ancak sınıf tanımlamasının
içerisinde onlara doğrudan da erişebiliriz. Örneğin:
Sınıf İsimlerinin Anlamı
Sınıflar Python'da birer deyim statüsündendir.
Python yorumlayıcısı bir sınıf tanımalamasını gördüğünde type isimli sınıf
türünden bir nesne yaratır. Sınıfın elemanlarını bu sınıf nesnesinin içerisine
yerleştirir. Yani aslında Python'da sınıf isimleri o sınııfn elemanlarının
bulunduğu type isimli bir nesnenin adresini tutmaktadır.
Örneğin:
Bir sınıfın isminin type türünden bir nesneyi gösterdiğine fakat
bir sınıf türünden sınıf türünden bir değişkenin o sınıf türünden bir nesneyi
gösterdiğine dikkat etmeniz gerekiyor. Örneğin:
Sınıflar Arasındaki İlişkiler
Daha önceden belirtildiği gibi bir proje nesne yönelimli olarak
modellenecekse önce proje içerisindeki kavramlar sınıflarla temsil edilir. Daha
sonra o sınıflar türünden nesneler yaratılarak gerçek varlıklar elde edilir.
Sınıflar arasında da birtakım ilişkiler söz konusu olabilmektedir. Örneğin
hastane otomasyonunda Doktor sınıfı ile Hastane sınıfı, Doktor sınıfı ile Hasta
sınıfı arasında ilşkiler vardır.
Sınıflar arasında dört ilişki biçimi tanımlanabilmektedir. Bunlar
İçerme İlişkisi (Composition), Birleşme İlişkisi (Aggregation), Kalıtım
İlişkisi (Inheritance) ve Çağrışım İlişkisi (Association) dir. Şimdi bu ilişki
biçimlerini tek tekinceleyelim:
1) İçerme İlişkisi (Composition): Bir sınıf
türünden nesne başka bir sınıf türünden nesnenin bir parçasını oluşturuyorsa bu
iki sınıf arasında içerme ilişkisi vardır. Örneğin Araba ile Motor sınıfları
arasında, İnsan ile Karaciğer sınıfları arasında içerme ilişkisi vardır. İçerme
ilişkisi için iki koşulun sağlanması gerekir:
1) İçerilen
nesne tek bir nesne tarafından içerilmelidir.
2) İçeren
nesneyle içerilen nesnenin ömürleri yaklaşık aynı olmalıdır.
Tabii bu
ölçütler tipik durumlar için düşünülmelidir. Aksi takdirde biz doğadaki pek çok
olguyu tam olarak modelleyemeyiz. Örneğin İnsan öldüğünde karaciğeri başka bir
insana takılabilmektedir. Fakat bu durum göz ardı edilebilir.
Örneğin Oda ile Duvar sınıfları arasında içerme ilişkisi yoktur.
Çünkü her ne kadar bunların ömürleri aynı ise de o duvar aynı zamanda yandaki
odanın da duvarıdır. Satranç tahtası ile tahtanın kareleri arasında içerme
ilişkisi vardır. Fakat satranç taşları ile kareler arasındaki ilişki içerme
ilişkisi değildir.
Saat ile akrep, yelkovan arasında içerme ilişkisi vardır. Fakat
bilgisayar ile fare arasındaki ilişki içerme ilişkisi değildir. Benzer biçimde
örneğin bir diyalog penceresi ile onun üzerindeki düğmeler arasında içerme
ilişkisi vardır.
2) Birleşme İlişkisi (Aggregation): Birleşme ilişkisinde bir sınıf nesnesi başka türden bir sınıf
nesnesini bünyesine katarak kullanmaktadır. Fakat kullanan nesneyle kullanılan
nesnenin ömürleri aynı olmak zorunda değildir.
Kullanılan nesne başka nesneler tarafından da kullanılıyor
olabilir. Örneğin, Araba sınıfıyla Tekerlek sınıfı arasında, Bilgisayar sınıfı ile
Fare sınıfı arasında, Oda sınıfıyla Duvar sınıfı arasında, Ağaç sınıfıyla
Yaprak sınıfı arasında, Hastane sınıfıyla Doktor sınıfı arasında böyle bir
ilişki vardır. İçerme ilişkisine uymayan pek çok olgu birleşme ilişkisine
uymaktadır.
3) Kalıtım (Türetme) İlişkisi (Inheritance): Türetme mevcut bir sınıfa ona dokunmadan ekleme yapmak anlamına gelmektedir.
Elimizde bir A sınıfı bulunuyor olsun. Biz buna birtakım elemanlar eklemek
isteyelim. Fakat A'nın kaynak kodu elimizde olmayabilir ya da onu bozmak
istemeyebiliriz.
Bu durumda A sınıfından bir B sınıfı türetiriz. Eklemeleri B'ye
yaparız. Böylece B sınıfı hem A sınıfı gibi kullanılır hem de fazlalıklara
sahip olur.
4) Çağrışım İlişkisi (Association): Bu ilişki biçiminde bir sınıf bir sınıfı bünyesine katarak değil,
yüzeysel biçimde, bir ya da birkaç metodunda kullanıyor durumdadır. Örneğin Taksi
ile Müşteri arasında ciddi bir ilişki yoktur. Taksi müşteriyi alır ve bir yere
bırakır.
Halbuki Taksi ile şoförü arasında önemli bir ilişki vardır. İşte
Taksi ile Müşteri ilişkisi çağrışım ilişkisi iken, Taksi ile Şoför arasındaki
ilişki birleşme (aggregation) ilişkisidir. Benzer biçimde Hastane sınıfı
ReklamŞirketi sınıfını yalnızca reklam yaparken kullanmaktadır. Bunların
arasında da çağrışım ilişkisi vardır. Çağrışım ilişikisi UML sınıf diyagramlarında
kullanan sınıftan kullanılan sınıfa çekilen ince bir okla gösterilir.
object Sınıfı
Python'da da tıpkı Java ve C#'ta olduğu gibi her sınıf doğrudan ya
da dolaylı olarak tepedeki bir object isimli sınıftan türetilmiş durumdadır.
Biz bir sınıfı hiçbir sınıftan türetmesek bile Python yorumlayıcısı onun object
sınıfından türetildiğini varsaymaktadır. Örneğin:
class Sample:
pass
bildirimi
ile,
class Sample(object):
pass
bildirimi
eşdeğedir. Yani her zaman türetme şemasının tepesinde object sınıfı vardır.
Pekiyi object sınıfının elemanları nelerdir? Aslında
object sınıfının herkesin faydalanacağı örnek öznitelikleri yoktur. Ancak bazı
işlevsellikleri arka planda sağlayan önemli metotları vardır. Bunlardan
bazıları bazı konularda ele alınacaktır.
Python'da Çoklu Türetme (Multiple
Inheritance)
Bir sınıfın birden fazla taban sınıfa sahip olması
durumuna çoklu türetme (multiple inheritance) denilmektedir. Java ve C# gibi
bazı dillerde çoklu türetmeye izin verilmemiştir. Ancak C++ gibi, Object Pascal
gibi dillerde çoklu türetme özelliği vardır. Python'da da çoklu türetme
kullanılabilmektedir.
Taban ve Türemiş Sınıflarda Aynı
İsimli Elemanların Bulunması Durumu
Hem taban hem de türemiş sınıfta aynı isimli örnek
öznitelikleri ve metotlarının bulunduğu bir durumda biz türemiş sınıf türünden
bir değişkenle bu öznitelikleri ya da metotları kullanırsak ne olacaktır? Önce
aynı isimli örnek özniteliklerin bulunması durumuna bakalım.
Python'da diğer pek çok dilde olduğu gibi taban
sınıfın veri elemanlarıyla türemiş sınıfın veri elemanları farklı bir blok olarak
tutulmamaktadır. Aslında Python'da türemiş sınıf nesnesinin bir taban sınıf
kısmı yoktur.
Türemiş sınıf nesnesi öznitelik anlamında taban
sınıf nesnesini kapsıyor durumda da değildir. Bu yüzden taban sınıfta biz bir
örnek özniteliği yarattığımızda bu yaratımı yaptığımız metot hangi türden
değişkenle çağrılmışsa zaten o örnek özniteliği de o değişkenin bir parçası
olur. Örneğin taban sınıf metodu türemiş sınıf türünden bir değişkenle
çağrılmışsa taban sınıftaki öznitelikler türemiş sınıf nesnesinin öznitelikleri
olacaktır. Örneğin:
Overload ve Override Kavramları
Nesne Yönelimli Programlama tekniğinde (NYPT)
birbirine fonetik olarak benzeyen iki önemli kavram vardır: "overload"
ve "override". Bu iki kavram da fonksiyonlar ve metotlar için
kullanılmaktadır. "Overload" terimi "aynı isimli farklı
parametrik yapılara ilişkin fonksiyonların ya da metotların aynı faaliyet alanı
içerisinde bulunması" durumuna denilmektedir. Yani örneğin C++, Java ve C#
gibi dillerde aynı sınıf içerisinde aynı isimli birden fazla metot (fonksiyon)
bulunabilmektedir. Ancak bunların parametrik yapılarının farklı olması
gerekmektedir.
Python'da bu anlamda
bir overload kavramı yoktur. Yani aynı isimli birden fazla fonksiyon ya da
metot ne olursa olsun beraber bulunamazlar. (Tabii farklı faaliyet alanlarında,
örneğin farklı sınıflarda bulunabilirler.) Python'da zaten fonksiyonlar ve
metotlar diğer değişkenler gibi birer referans belirtmektedir. Yani fonksiyon
ya da metot isimleri aslında bu fonksiyon ya da metotları içeren nesnelerin
adreslerini tutan değişkenlerdir. Örneğin:
Python'da
biz istersek sınıfa daha sonra metot da ekleyebiliriz. Örneğin:
class Sample:
def foo(self):
print('foo')
def tar(self):
print('bar')
Sample.bar = tar
s = Sample()
s.foo()
s.bar()
Sample.x = 100
print(Sample.x)
Burada Sample.bar ifadesine bir fonksiyon nesnesinin
adresi atanmıştır. Bu atama Sample sınıfı için bir sınıf özniteliği oluşturmaktadır.
Örneğimizde benzer biçimde Sample.x ifadesine atama yapılarak sınıfın x isimli
bir özniteliği de oluşturulmuştur.
"Override" terimi taban sınıftaki bir
metot ile aynı isimli türemiş sınıfta bir metodun bulunması durumunu anlatmaktadır.
"Override" mekanizması özellikle çok biçimlilik (polymorphism) için
kullanılır.
Çok biçimlilik sayesinde her sınıf belli bir işlevi
kendine göre diğerlerinden az çok farklı biçimde yerine getirebilmektedir.
Override kavramı Python'da var olan bir kavramdır. Çünkü Python'da da farklı
sınıflar içerisinde aynı isimli metotlar bulunabilmeketedir.
super Fonksiyonu
super built-in bir fonksiyondur. Aslında bu fonksiyonun
ismi uygun verilmemiştir. İşlevine bakıldığında bu fonksiyonun isminin
"super" yerine "next" gibi bir şey olması daha uygundur
(next isimli built-in başka bir fonksiyon daha vardır.) Çünkü super sözcüğü
NYPT aynı zamanda taban sınıf çağrışımı da yapmaktadır.
super fonksiyonun argümansız ve argümanlı kullanım
biçimi vardır. Argümanlı kullanımda fonksiyon iki argümanla kullanılır. Birinci
argüman MRO sırasında aramanın başlama yerini belirten bir sınıf ismidir.
İkinci argüman da nesnenin çağrılmasında
kullanılacak değişkeni belirtir. Bu durumda arama MRO sırasına göre birinci
argümanda belirtilen sınıftan sonraki sınıftan başlatılır.
Aslında argümansız kullanım bu kullanımın özel bir
biçimidir. (Tabii aslında iki ayrı super fonksiyonu yoktur. Zaten bunun
Python'da mümkün olamayacağını daha önce belirtmiştik. Aslında super
fonksiyonunun iki parametresi default değer almaktadır.)
İki argümanlı kullanımının genel biçimi şöyledir:
super(<sınıf ismi>,
<değişken>).<fonksiyon ismi>(...)
Burada arama birince argümanla belirtilen sınıftan
sonraki sınıfan başlatılır. İkinci argüman ise bu fonksiyonun çağrılmasında
kullanılacak değişkeni belirtmektedir. Yani örneğin:
super(D,
d).foo()
çağrısının
eşdeğeri şöyledir:
d.foo()
Ancak
buradaki foo MRO sırasına göre D'den sonraki sınıfın foo metodudur. Örneğin:
super
fonksiyonu hangi sınıfta çağrılmışsa arama MRO sırasına göre o sınıftan sonraki
sınıftan başlatılmaktadır. Örneğin:
class A:
def foo(self):
print('A.foo')
class B(A):
def foo(self):
print('B.foo')
super().foo()
class C(A):
def foo(self):
print('C.foo')
super().foo()
class D(B, C):
pass
print(D.__mro__)
d = D()
d.foo()
Python'da Kapsülleme (Encapsulation)
ve Örnek Özniteliklerinin Dışarıdan Gizlenmesi (Data Hiding)
Bilindiği gibi NYPT’de bir olgunun bir sınıf ile
temsil edilip o sınıfın dışarıyı ilgilendirmeyen elemanlarının dışarıdan gizlenmesine
"kapsülleme (encapsulation)" ve veri elemanlarının dışarıdan
gizlenmesine de "veri elemanlarının gizlenmesi (data hiding")
denilmektedir. Pek çok dilde bunu sağlamak için sınıfların "private"
biçiminde dışarıya gizlenen bölümüleri vardır. Pekiyi Python'da bu kavramların
kullanılması nasıldır?
Python'da sınıfların diğer pek çok nesne yönelimli
programlama dillerinde olduğu gibi "private", "protected"
ve "public" gibi bölümleri yoktur. Yani Python'da zaten default
olarak sınıfın tüm elemanları "public" gibidir. Herhangi bir elemanı
dışarıdan gizlemenin etkin bir yolu da yoktur.
Her ne kadar Python'da elemanları dışarıdan
gizlemenin kesin bir yolu yoksa da bu konuda birkaç küçük tavsiye bulunmaktadır.
Eğer bir özniteliğin ya da metodun ismi _ (single underscore) ile başlatılarak
isimlendirilmişse Python dünyasında bu öznitelikler "private" eleman
olarak değerlendirilmektedir.
Gerçi _xxx biçimindeki özniteliklere dışarıdan yine
isteyenler erişebiliyorsa da kodu anlamlandıran kişiler bunları private eleman
gibi ele almaktadır. Başka bir deyişle biz bir elemanın dışarıdan erişilmesini
mantık olarak istemiyorsak onu başına _ karakteri getirerek isimlendirmeliyiz.
Böyle isimleri gören programcılar bu değişkenleri
dışarıdan kullanmak konusunda isteksiz davranacaktır. Fakat bu konuda
yorumlayıcının bir zorlaması söz konusu olmayacaktır. (Yani programcı bunu dışarıdan
kullanmak isterse yine kullanabilir.)
Ayrıca bir de Pyton'da sınıf elemanlarının __
(double underscore) ile başlatılarak isimlendirmesi de vardır. Böyle değişkenlere
dışarıdan ilgili sınıf türünden değişken ve. operatörü ile erişilemez.
Ancak bu erişim yasağı da aslında bu değişkenin
dışarıdan kullanımını tamamen ortadan kaldırmamaktadır. Şöyle ki: __xxx
biçiminde isimlendirilmiş sınıf elemanları dışarıdan yine _<sınıf
ismi>__<eleman ismi> biçiminde kullanılabilmektedir. Daha açık bir
örnek vermek gerekirse X sınıfının __x isimli bir elemanı dışarıdan __x ismiyle
kullanılamaz. Ancak _X__x ismiyle kullanılabilir. İşte __ (double underscore)
ile isimlendirme değişkenin dışarıdan kullanılmasını kısmen (fakat tamamen değil)
engellemektedir. Örneğin:
class Sample:
def __init__(self, a):
self._a = a
def disp(self):
print(self._a)
def __foo(self):
print('Sample.__foo')
s = Sample(10)
s.disp()
s._a = 20 # kötü teknik, _ ile
başlatılan değişkenler dışarıdan kullanılmamalıdır
s._Sample__foo()
Python'da Çokbiçimlilik
(Polymorphism)
Çokbiçimlilik biyolojiden aktarılmış bir terimdir.
Biyolojide çokbiçimlilik canlıların çeşitli doku ve organlarının onların yaşam
koşullarına göre temel işlevleri aynı kalmak üzere farklılaşmasına
denilmektedir.
Örneğin kulak
pek çok canlıda vardır ve temel işlevi "duymak"tır. Ancak her canlı
bu duyma eylemini biraz farklı gerçekeltirmektedir. Yazılımda çokbiçimlilik
türden bağımsız kod parçalarının oluşturulması için kullanılan bir tekniktir.
Başka bir deyişle türünü bilmeden nesne üzerinde
işlem yapmayı sağlar. Çokbiçimlilik sınıflarla ilgili bir kavramdır.
Çokbiçimliliğin uygulanması için farklı sınıfların bulunyor olması gerekir.
Sınıfların static Metotları ve Sınıf
Metotları
Bazı fonksiyonlar bir sınıfın konusuyla ilgili
işlemler yaparlar ancak herhangi bir sınıf örnek özniteliğini (instance attirbute)
kullanmazlar. Yani bunların yalnızca mantıksal bakımdan sınıf ile ilişkileri
vardır. Örneğin Date isimli bir sınıf tarih işlemleri yapıyor olsun. Bu sınıfın
day, month ve year isimli örnek özniteliklerinin olduğunu düşünelim:
class Date:
def __init__(self, day,
month, year):
self.day =
day
self.month =
month
self.year = year
Şimdi biz belli bir yılın artık yıl olup olmadığını
tespit eden bir fonksiyon yazmak isteyelim. Bu fonksiyonun aslında tarih
işlemleriyle yalnızca mantıksal bir ilgisi vardır. Böyle bir fonksiyon global
düzeyde yazılabilir. Ancak bu mantıksal ilgiden dolayı bu fonksiyonun Date
sınıfı içerisinde bir metot biçiminde oluşturulması tercih edilir.
İşte böylece bir sınıfa dahil olan fakat o sınıfın
hiçbir örnek özniteliğini kullanmayan bir metotla karşılaşmış oluruz. Böyle
metotlar diğer pek çok nesne yönelimli programlama dilinde "static
metot" olarak isimlendirilmektedir.
Python'da Dekoratörler
Python'da nesne yönelimli programla tekniğindeki
dekoratör kalıbı özel bir sentaksla dilin içerisine entegre edilmiştir. Dekoratörler
"fonksiyon ve metot dekoratörleri" ve "sınıf dekoratörleri"
olmak üzere ikiye ayrılmaktadır. Dekoratörleri belirtmek için "@"
karakteri kullanılır. "@" karakterine bitişik olan isme dekoratör
denilmektedir. Örneğin:
@foo
@classmethod
Birer
dekoratördür.
Fonksiyon ve Metot Dekoratörleri
Daha önceden de belirtildiği gibi Python'da
fonksiyonlar, metotlar ve sınıflar aslında sıradan birer değişken ismidir. Bunlar
fonksiyon nesnelerinin, metot nesnelerinin ve type nesnelerinin adreslerini
tutan birer referanstır.
Bu nedenle Python'da
aynı fonksiyon ya da metodu ikinci kez bildirmek adeta bu değişkene başka bir
değer atamak gibidir ve tamamen normal bir durumdur. Örneğin:
def foo():
print('foo')
foo()
def foo():
print('other foo')
foo()
Python'da
fonksiyon dekoratörü oluşturmak için "@" sembolünün yanına bitişik
olarak bir fonksiyon ismi getirilmelidir. Örneğin:
@foo
def bar():
print('bar')
Sınıf Dekoratörleri
Foksiyonlar
ve metotlar gibi sınıflar da aynı mantık çerçevesinde dekore edilebilmektedir. Örneğin:
def foo(c):
print('foo')
return c
@foo
class Sample:
def disp(self):
print('disp')
# Sample = foo(Sample)
s = Sample()
s.disp()
Burada aslında Sample ismi yine aynı sınıf bilgilerini
göstermektedir. Ancak bir foo çağırması da yapılmıştır. Biz istersek her sınıf
nesnesi yaratılacağı zaman bir kodun çalışmasını da sağlayabiliriz. Bu işlem
yine iç bir fonksiyon kullanılarak ya da bir sınıf kullanılarak yapılabilir.
Örneğin:
Python'da Dosya İşlemleri
İçerisinde bilgilerin bulunduğu ikincil belleklerde tanımlanmış
bölgelere "dosya (file)" denilmektedir. Dosyaların isimleri ve
özellikleri vardır. Dosya işlemleri en aşağı düzeyde işletim sistemi tarafından
ele alınarak yapılmaktadır.
Programlama dillerinde dosyalar üzerinde işlem yapan fonksiyonlar
ya da sınıflar aslında eninde sonunda işletim sisteminin sistem
fonksiyonlarından faydalanmaktadır. Python'da dosya işlemleri file isimli bir
sınıf kullanılarak gerçekleştirilmektedir.
Modern işletim sistemlerinin çoğu ikincil bellekleri dizinler
(directories) biçiminde organize etmektedir. Dizinler içerisinde dosyalar
olabileceği gibi başka dizinler de olabilmektedir. Bir dosyanın yerini belirten
yazısal ifadeye "yol ifadesi (path)" denilmektedir. Yol ifadesi
dosyanın hangi dizinin içerisindeki hangi dizinde olduğunu gösteren bir yazıdır.
Yol ifadelerindeki dizin geçişleri Windows sistemlerinde '\' karakteri ile
UNIX/Linux sistemlerinde '/' karakteri ile belirtilmektedir. Hiçbir dizinin
içerisinde bulunmayan en dıştaki dizine "kök dizin (root directory)"
denilmektedir.
Windows sistemlerinde ayrıca bir de "sürücü (drive)"
kavramı vardır. Her sürücünün ayrı bir kökü bulunmaktadır. Ancak UNIX/Linux
sistemlerinde sürücü kavramı yoktur. Bu nedenle örneğin bir Linux sistemlerinde
bir flash belleği bilgisayara taktığımızda onun kök dizini bir dizin altında
görünmektedir. Bu işleme UNIX/Linux dünyasında "mount" etme
denilmektedir.
Yol ifadeleri "göreli (relative)" ve "mutlak
(absolute)" olmak üzere ikiye ayrılmaktadır. Yol ifadelerinin ilk
karakterleri '\' ya da '/' ise buna mutlak yol ifadesi denir. Mutlak yol
ifadeleri kök dizinden itibaren yer belirtmektedir. Örneğin:
“C:\Users\mryaz\Desktop\İtp\Python\ilk_dosyam.txt”
Yorumlar
Yorum Gönder