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

Bu blogdaki popüler yayınlar

Python Programlama Diline Giriş III

Python Uygulamaları

HTML Giriş