“Hiç uğraşamam…”

twitter.com/brsyuksel

Metaclass

Ve metaclass’lar. Örnek kodlara, açıklayıcı belgelere ve Guido van Rossum tarafından yazılıp Fred L. Drake, Jr. tarafından düzenlenmiş bir HOWTO Metaclasses kitabına rastlanmasa da aslında gayet basit bir konu. İlk bakışta mantığını anlamak güç gelebilir ancak üstüne gittiğinizde gerçekten kolay ve kullanışlı olduğunu fark edeceksiniz.

Nedir Metaclass’lar? Metaclass’lar basitçe açıklamak gerekirse “bir sınıfın sınıfıdır”. Bir sınıf, metaclass olacak şekilde tanımlanmış bir sınıfı metaclass olarak alıyorsa, o sınıfın örneğidir. Metaclass’lar genel olarak kapsayıcı (wrapper) olarak kullanılırlar. Bu size biraz Descriptor mantığını hatırlatabilir ancak farkını örnek kodlarda göreceksiniz.

Metaclass’ları tanımlarken, taban sınıf ( baseclass, superclass ) “type” olmalı. Bunun dışında tabii diğer tanımlanmış Metaclass’lar da olabilir. Her sınıf gibi Metaclass’larda da ilk önce __new__() ve sonrasında __init__() metodları çağrılır. Metaclass’larda fark olarak bu çağrılardan sonra __call__() metodu çağrılmaktadır. Bu çağrıların parametreleri şu şekilde:

__new__(metacls,name,bases,dict)
metacls: Metaclass olarak tanımlanmış sınıf. Hatırlarsanız __new__() metoduna giden ilk parametre örneği oluşturulacak sınıfın kendisiydi.
name: Metaclass’ı kullanan sınıfın ismi. String bir değer.
bases: Metaclass’ı kullanan sınıfın kullandığı/türetildiği taban sınıflar.
dict: Metaclass’ı kullanan sınıfın niteliklerini barındıran sözlük.

__init__(self,name,bases,dict)
self: Biliyorsunuz, Metaclass’ı kullanan sınıf aynı zamanda Metaclass’ın bir örneği olduğu için ilk parametre o.
name, bases ve dict parametreleri __new__ metoduna gönderilen parametrelerle aynı.

__call__(self[,arg1,arg2,arg3...])
Sanırım burda parametreleri açıklamaya pek de gerek yok :)

Örnek bir Metaclass tanımlayıp kullanalım.

  1. class Meta(type):
  2.         def __new__(meta,name,bases,dict):
  3.                 print "__new__", meta, name, bases, dict #bu ciktilari almak anlamaniz acisindan yararli olacak
  4.                 return super(Meta,meta).__new__(meta,name,bases,dict) #type(name,bases,dict) ile ayni gorevi gordugunu fark etmissinizdir.
  5.  
  6.         def __init__(self,name,bases,dict):
  7.                 print "__init__", self, name, bases, dict #burda selfin ve new’de kullanilan meta’nin farkini goreceksiniz.
  8.  
  9.         def __call__(self,*args,**kwargs):
  10.                 print "__call__", self, args, kwargs
  11.  
  12. class Sinif(object):
  13.         __metaclass__ = Meta #artik Sinif isimli sinifimiz, ayni zamanda Meta isimli sinifin ornegi
  14.  
  15. Ornek = Sinif()

Şimdi adım adım bakacak olursak:
İlk olarak söylediğim gibi __new__ metodu çağrılıyor. Giden parametreler sırasıyla:
<class ‘__main__.Meta’> Sinif (<type ‘object’>,) {‘__module__’: ‘__main__’, ‘__metaclass__’: <class ‘__main__.Meta’>}
Ve __new__ metodu bize verilen parametreler ile bir örnek, bir nesne oluşturup döndürüyor.

İkinci adımda ise __init__ metodu çağrılıyor. Burda da giden parametreler sırasıyla şu şekilde:
<class ‘__main__.Sinif’> Sinif (<type ‘object’>,) {‘__module__’: ‘__main__’, ‘__metaclass__’: <class ‘__main__.Meta’>}
Gördüğünüz gibi __init__ metodunun gelen parametreleri ekrana bastırmak başka bir işlemi yok.

Son olarak ise __call__ metodu çağrılıyor. İşte Sinif’in Meta sınıfının örneği olduğunu bize gösterecek çağrı. Sınıf Özellikleri ve Yeni Stil Sınıflar yazımda bahsettiğim __call__ metodu kullanımını hatırlayın, sınıf örneğinin çağrılabilir fonksiyon gibi davranmasını sağlıyordu. Örnek vermek gerekirse

  1. class Sinif(object):
  2.         def __call__(self,yazi):
  3.                 print yazi
  4.  
  5. ornek = Sinif() #Sinifi orneklendirdik.
  6. ornek("deneme") #cikti: "deneme"

__call__ metodunun Metaclass kullanımında yarattığı etki de aynı. Metaclass’ı kullanan sınıf, orneklendirildiği anda tanımlıysa __new__ ve sonrasında __init__ metodları çağrılırken, bir yandan da Metaclass sınıfının örneği olduğu için Metaclass’da tanımlanmışsa __call__ metodunu çağırıyor. Farkı anlamak için Meta ve Sinif orneklerinin bulunduğu örnek kodda “Sinif(‘deneme’)” vb. değişiklikler yapabilirsiniz.

Bitti. Kaynaklara bir göz atın derim. Özellikle descintro’da yer alan autoprop ve autosuper örnekleri çok ilginizi çekecek ( o kadar kullanışlılar ki, Pisi‘nin kaynak kodlarında “Guido’s cool metaclass examples. fair use. ahahah. I find these quite handy. Use them : )” açıklama satırlarıyla kendilerine rastladım. Burada ) Ayrıca metaclass’ların önceki yapıda nasıl kullanıldığını öğrenmek de faydalı olacaktır.

http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses
http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python
http://gnosis.cx/publish/programming/metaclass_1.html
http://en.wikibooks.org/wiki/Python_Programming/MetaClasses
http://www.voidspace.org.uk/python/articles/metaclasses.shtml
http://effbot.org/zone/metaclass-plugins.htm
http://pastebin.com/pBL5H6Dn ( Gene Singleton, bu sefer Metaclass olarak, “Thinking in Python” kitabından, “The pattern concept” başlığı altında )

Ve…
http://en.wikipedia.org/wiki/Metaclass
http://en.wikipedia.org/wiki/Metaobject_protocol
http://www.eksisozluk.com/show.asp?t=aspect+oriented+programming
http://en.wikipedia.org/wiki/Aspect_Oriented_Programming
Dahası da size kalmış…

Metaclass konusuna değinmiş olduğuma göre tasarım desenlerine geçmeden önce aklıma gelen bilumum gereksiz programlamaya zaman ayırarak fena bir şekilde eğlenip cozutabilirim.

Tags: ,
Posted in Python · Temmuz 15th, 2010 · Comments (0)

No comments yet

Leave a Reply

Bağlantılar

Etiketler

çember özel yöntem isimleri apache2screen apache2screen.deb bele kuvvet bi_rle4 brute-force classic classes classmethod descriptors getanurse ic.lnx icontacts ileri c programlama image imagedraw kaba kuvvet kelime tahmin libnotify math math.cos math.sin matruşka matryoshka memory leak mesafe metaclass mysqli new-style classes oauth php5 property pynotify Python singleton special method names staticmethod steganografi steganography super twittell TwittellOAuth wchar yeni stil sınıflar __mro__

Meta