Mayıs 10, 2012
Python ve decorator… Nedir, ne işe yarar?

Python dilindeki decorator’ları anlamadan önce, fonksiyonların Python dilinde “first class citizen” olduklarını bilmek gerekir. “first class citizen” birebir çevirildiğinde, birinci sınıf vatandaş demek. Programlama dilleriyle ilgili kullanıldığında bu deyim, o dildeki bir varlığın, şu özellikleri taşıdığı anlamına gelir;

  • Çalışma anında oluşturulabilir.
  • Parametre olarak geçirilebilir.
  • Fonksiyonlardan döndürülebilir.
  • Bir değişkene atanabilir.

Python’da fonksiyonların birinci sınıf objeler olduğunu anlamak o kadar da zor değil. Python’daki her şey gibi, fonksiyonlar da birer obje. Ve biz, objelerin yukarıdaki tüm özellikleri taşıdıklarını biliyoruz. Dolayısıyla, fonksiyonlar da bu özellikleri taşıyor.

Pythondaki objelerin bir diğer özelliği de, diğer fonksiyonlar içerisinde tanımlanabilmeleri. Örneğin, aşağıdaki kod Python dilinde tamamen normal bir koddur.

def yazdiricifonksiyon(yazi):
	def gereksiz():
		print yazi
	return gereksiz

merhabade = yazdiricifonksiyon("merhaba")
merhabade()
"""
Ekrana şunu basar:
merhaba
"""

Yukarıdaki örnekte, fonksiyonların nasıl birinci sınıf vatandaş olduklarını görüyoruz. İlk satırda tanımladığımız fonksiyon çağırıldığında, kendi içerisinde gereksiz isminde bir fonksiyon oluşturuyor. Daha sonra, bu fonksiyon, yazdiricifonksiyon’un dönüş değeri olarak döndürülüyor. Gördünüz gibi, bu fonksiyonu bir değişkene atayabiliyor ve istediğimizde çağırabiliyoruz.

Python’daki bu özellik sayesinde, şöyle şeyler de yapmak mümkün;

def acikla(fonksiyon):
	print "Su fonksiyonu cagiriyorum: %s" % fonksiyon.__name__
	return fonksiyon()

acikla(gereksiz)
"""
Su fonksiyonu cagiriyorum: gereksiz
"""
def unlemekle(f,*args,**kwargs):
	return f(*args,**kwargs) + "!"

def yazidondur(yazi):
	return yazi

unlemekle(yazidondur,"osman")
"""
'osman!'
"""

Yukarıdaki örneklerden göreceğiniz gibi, argüman olarak fonksiyon alan fonksiyonlar sayesinde, asıl fonksiyon çağrılmadan önce fazladan bir iş yapabilir veya, fonksiyonun dönüş değeri üzerinde düzenleme yapabiliriz.

İşte decorator’lar da, tam bu işi yapmaya yarıyor. Python’da decorator’lar, argüman olarak fonksiyon alıp, sonuçta yine fonksiyon döndüren fonksiyonlara deniyor. Örneğin;

def kalinyaz(f):
	def wrapper():
		return "<b>" + f() + "</b>"
	return wrapper

def osman():
	return "osman"

kalinosman = kalinyaz(osman)
kalinosman()
"""
'<b>osman</b>
"""
osman()
"""
'osman'
"""

Yukarıdaki örnekte, kalinyaz bir decorator. Bu fonksiyon, argüman olarak bir fonksiyon alıp, yine bir fonksiyon döndürüyor. Döndürdüğü fonksiyon çağırıldığında, asıl fonksiyonun dönüş değeri, html <b> tagları arasına alınıyor.

Python bu işi kolaylaştırmak için, bize decorator söz dizimi gibi bir kolaylık da sağlıyor. O da şöyle;

@kalinyaz
def yasar():
	return "yasar"
yasar()
"""
'<b>yasar</b>'
"""

Burada @ işaretiyle, fonksiyona uygulamak istediğimiz decorator’u belirtiyoruz. Bunun yukarıda yaptığımızdan pek bir farkı yok aslında. Tek özelliği daha temiz ve düzenli görünmesi.

Özetle, Python’daki her şey gibi, fonksiyonlar da birer obje ve bu nedenle fonksiyonlar diğer fonksiyonlara argüman olarak verilebilir veya fonksiyonlardan döndürülebilir. Python’un bu özelliğini, fonksiyonlar üzerinde oynamalar yapmak için kullanabiliriz.

Bu yazı giriş niteliğinde olduğu için, decorator’lardan sadece yüzeysel olarak bahsettim. Eğer bu konuyla ilgiliyseniz, Python wiki’nin ilgili sayfasında çeşitli amaçlara yönelik profesyonelce yazılmış birçok decorator bulup inceleyebilirsiniz.

Mayıs 9, 2012
Python yield deyimi nedir? Ne işe yarar?

Yazıya başlamadan önce, kullandığım dil ile ilgili bir açıklamada bulunmam gerek. Her ne kadar bu yazının dili Türkçe olsa da, bazı kelimeleri, özellikle de Türkçe’ye tam olarak geçmemiş, veya Türkçe karşılığı henüz tam olarak yaygınlaşmamış bazı kelime ve terimleri İngilizcede olduğu gibi kullanmaya karar verdim. Birtakım şeyleri Türkçeye çevirmeye zorlamak, hem çok anlamsız oluyor, hem de bu terimleri İngilizce adlarıyla bilenler için kafa karışıklığına neden oluyor. Bu yüzden, yazının geri kalanında, aralara serpiştirilmiş İngilizce kelimeler bulacaksınız.

Python dilindeki yield deyimini anlamak için, generator‘ları bilmek gerekiyor, generator‘ları anlamak için de, iterator ve iterable kavramlarını anlamak gerekiyor. İngilizcede “iterate” kelimesi, tekrar tekrar uygulanmak veya işlenmek anlamına geliyor. Python’daki iterable ve iterator kavramları bu kelimeden türetilmiş. Python’da iter() yerleşik fonksiyona argüman olarak verebildiğimiz objelere iterable diyoruz. iter() fonksiyonu bize bir iterator döndürüyor. Iterator, objenin elemanları ne şekilde tanımlanırsa tanımlansın, bir koleksiyon içindeki tüm elemanlara sırasıyla erişebilmemiz için ortak bir arayüz oluşturan bir mekanizma. Kısacası, elemanları üzerinde sırasıyla gezinebildiğimiz, listeler ve demetler gibi objelere iterable diyoruz. Bu objeler, iter() fonksiyonu ile çağrıldığında, birer iterator döndürüyor, ve bu iterator‘lar bir koleksiyondan sırasıyla eleman almak için kullanılıyor.

Şu kod paçasına bir bakalım:

a = [1,2,3,4,5]
for k in a:
	print k

Bu örnekte, sıradan bir liste ve for döngüsü görüyoruz. Buradaki liste, for döngüsünde kullandığımız herşey gibi, bir iterable. Python’da for döngüsü, önce iterable olarak verilen objeden, döngü sırasında kullanmak için bir iterator elde ediyor. Biz bu aşamayı görmüyoruz, bu aşama, Python’daki for döngülerinin çalışma yapısının bir parçası. Daha sonra, bu iterator elemanlar tükendi sinyali verene kadar, k değişkenini bir sonraki elemana atayıp, döngünün gövdesini çalıştırılıyor. Yani, yukarıdaki for döngüsü ile aşağıdaki kod parçacığı tamamen aynı çalışıyor.

a = [1,2,3,4,5]
b = iter(a)
while True:
	try:
		k = next(b)
	except StopIteration:
		break
	print k

Yukarıdaki örnekte, ikinci satırda listenin elemanlarını sırasıyla elde etmek için bir iterator oluşturup, bunu b değişkenine atadık. Yukarıdaki for döngüsünde, bu işlem for döngüsü tarafından kendiğinden yapılıyordu. Daha sonra, 5. satırda, k’yı iterator’dan gelen bir sonraki elemana atadık. Eğer iterator yeni eleman veremiyorsa, StopIteration durumu oluşturuyor. Bu durumu catch ile yakalayıp, döngüden çıkıyoruz. Iterator’larla ilgili son bir şey; iteratorlar tek kullanımlıktır, bir kere tükendikten sonra, aynı  objenin elemanları içinde tekrar gezinmek için, yeni bir iterator‘a ihtiyacımız var.

Python’daki generator’lar ise, farklı bir çeşit iterable‘dır. Bunların diğer iterable‘lardan farklarından biri, bunların tek kullanımlık olmasıdır. Örneğin, bir listeyi istediğiniz kadar for döngüsünde kullanabilirsiniz, ancak, bir generator‘u yalnız bir kere for döngüsünde kullanabilirsiniz. Bunların bir diğer önemli farkı ise, tüm elemanların hafızada tutulmaması. Generatorlar, sırası gelen elemanı üretip döndürür, daha sonra da bu elemanı unuturlar. Örneğin;

generator = (x*x*x for x in range(5))
for k in generator:
	print k
"""
Ekrana şunu basar:
0
1
8
27
64
"""
for k in generator:
	print k
"""
Ekrana hiçbir şey basılmaz, çünkü generator'u bir kere kullandık ve bitti.
"""	

Yukarıdaki örnekte, ilk satırda bir generator oluşturup, bunu generator isimli bir değişkene atadık. Şimdi bunu, istediğimiz gibi for döngüsünde kullanabiliriz. Burada dikkat edilmesi gereken nokta, 0,1,8 gibi değerlerin, ilk satırda oluşturulmamış olması. Bu değerler, for döngüsünde sıraları geldiklerinde oluşup, işleri bittikten sonra hafızadan siliniyorlar. Genel olarak generatorların olayı bu kadar.

Artık yield deyimini anlamak için, yeterli altyapıya sahibiz. yield deyimi, return deyimi gibi fonksiyonlarda kullanılır, ancak, fonksiyon bir generator döndürür. Şu örneğe bakalım;

def creategeneratorSquare(l):
	for x in l:
		yield x * x
	
generator = creategeneratorSquare([1,2,3,4,5])
for k in generator:
	print k

"""
Ekrana şunu basar:	
1
4
9
16
25
"""

Yukarıdaki kod parçacığında, creategeneratorSquare isimli bir fonksiyon oluşturduk. Bu fonksiyonun, normal fonksiyonlardan farkı, bir generator döndürmesi. Bu fonksiyonu çağrıdığımızda, normal fonksiyonlardan beklediğimiz gibi, fonksiyonun gövdesi çalışmıyor, bunun yerine fonksiyon bir generator döndürüyor. Bu generator for döngüsü içinde kullanıldığında, fonksiyon içinde yazdığımız kod, yield görene kadar çalışıyor. Burada, yield deyimi “x * x” döndürüyor ve beklemeye başlıyor. Daha sonra, 6. satırdaki döngü, bir sonraki elemanı istedikçe, beklemedeki kod bloğu tekrar yield görene kadar çalışıp, yield gördüğünde sıradaki elemanı döndürüyor. Böylece, bu kod bloğu tamamlanıncaya kadar, 6. satırdaki for döngüsü k’ya farklı değerler atayıp, bunları ekrana bastırıyor.

Bir örneğe daha bakalım;

def fibogenerator():
	a,b = 1,1
	while True:
		yield b
		a,b = b, a + b

		
for k in fibogenerator():
	if k > 10000000:
		print k
		break

"""
Ekrana şunu basar:	
14930352
"""

Bu örnekte, biz istedikçe bir sonraki fibonacci sayısını veren bir generator kullanmak istedik. Bunun için, fibogenerator isimli bir fonksiyon yazdık. Bir önceki örnekten farklı olarak, bu sefer generator‘u bir ara değişkende tutmaktansa, doğrudan for döngüsü içinde kullandık. Generator zaten tek kullanımlık olduğu için, bunları bir değişkene atamak çoğu zaman gereksiz. For döngüsünde ise, k 10 milyon’dan büyük olduğunda, k’yı ekrana bas ve döngüden çık dedik. Eğer döngüden çıkmak için herhangi birşey kullanmazsak, bu for döngüsü sonsuza kadar çalışırdı, çünkü, yazdığımız generator doğal yollardan sonlanmıyor.

yield deyimi ilk görüldüğünde kafa karıştırıcı olabilir. Buna rağmen, yield deyimini anlamaya çalışmakta yarar var, çünkü yeri geldiğinde bunu bilmek, diğer yollardan çözemeyeceğiniz problemleri bir çırpıda çözmenize olanak sağlıyor. Python belgelerindeki itertools sayfası yield kullanımıyla ilgili birçok örneğe sahip. Bunları da incelemekte fayda var.

Ocak 23, 2012

Ocak 21, 2012
Sayılarla ArchLinux Paketçileri

Ben doğuştan manyak olduğum için, arada istatistik toplayıp grafik çiziyorum. Bu seferki grafikte, ArchLinux geliştiricilerinin ne kadar paket yapımına katkıda bulunduğunu görebilirsiniz.

Kaynak:

cd /var/abs
find -name 'PKGBUILD' -exec cat '{}' \; | egrep '(Maintainer|Contributor)' | cut -d: -f 2 | sed 's/<.*>//' | sort | uniq -c | sort -nr

Ocak 21, 2012
İki bilinmeyenli denklem çözümleri

Dün Python ile, iki bilinmeyenli denklem çözümleriyle ile birşeyler yazdım. Paylaşayım dedim. Sonuncusunun biraz daha elden geçmesi lazım, ama aşağı yukarı çalışıyor.

# -*- coding: utf-8 -*-
from math import sqrt

def gereksiz(toplam, carpim):
    """
    a + b = toplam
    a * b = carpim
    return a,b
    >>> gereksiz(8,15)
    (3.0, 5.0)
    >>> gereksiz(7,12)
    (3.0, 4.0)
    >>> gereksiz(12,35)
    (5.0, 7.0)
    """
    carpim, toplam = float(carpim), float(toplam)
    try:
        terim1 = sqrt((toplam / 2) ** 2 - carpim)
    except ValueError:
        return (None, None)
    terim2 = toplam / 2
    buyuk = terim1 + terim2
    kucuk = terim2 - terim1
    return (kucuk, buyuk)

def gereksiz2(fark, carpim):
    """
    a - b = fark
    a * b = carpim
    return a,b
    >>> gereksiz2(7,30)
    (3.0, 10.0)
    >>> gereksiz2(2,35)
    (5.0, 7.0)
    >>> gereksiz2(7,78)
    (6.0, 13.0)
    """
    kucuk, buyuk = gereksiz(fark, -carpim)
    try:
        return (buyuk, -kucuk)
    except TypeError:
        return (None, None)

def gereksiz3(toplam, bolum):
    """
    a + b = toplam
    a / b = bolum
    return a,b
    >>> gereksiz3(240,5)
    (200.0, 40.0)
    >>> gereksiz3(6,2)
    (4.0, 2.0)
    >>> gereksiz3(15,4)
    (12.0, 3.0)
    """
    b = float(toplam) / (bolum + 1)
    a = toplam - b
    return (a,b)

def gereksiz4(fark, bolum):
    """
    a - b = fark
    a / b = bolum
    return a,b
    >>> gereksiz4(15,2)
    (30.0, 15.0)
    >>> gereksiz4(4,2)
    (8.0, 4.0)
    >>> gereksiz4(15,4)
    (20.0, 5.0)
    """
    a,b = gereksiz3(fark, -bolum)
    return (a, -b)

def gradient(a,s,p):
    terim1 = sqrt(s - a)
    alttaraf = sqrt((terim1 - (p / a)) ** 2)
    usttaraf_1 = (p / (a ** 2)) - float(1) / (2 * terim1)
    usttaraf_2 = terim1 - (p / a)
    return (usttaraf_1 * usttaraf_2) / alttaraf

def mesafe(a, s, p):
    return abs(sqrt(s - a) - (p / a))

def gereksiz5(s,p,hata=1.0e-15,maxdeneme=100):
    """
    a + b ^ 2 = s
    a * b = p
    için YAKLAŞIK olarak, DENEME YANILMA yoluyla a ve b değerleri bulur.
    işlemler genelde 100 denemeden daha önce bitmeli, eğer çok uzarsa,
    hata değerini artırın.
    """
    a = sqrt(p) / 2
    up_limit = s
    down_limit = -s
    #print "a değerinden başlanıyor: ", a
    m = mesafe(a,s,p)
    prev_m = m
    weight = 1
    counter = 0
    while  m> hata:
        counter += 1
        if counter >= maxdeneme:
            break
        try:
            #print "a=>",a, "hata=>",mesafe(a,s,p)
            grad = gradient(a,s,p)
            #print "gradient:", grad
            a_deneme = a - (1 / (weight * grad))
            m = mesafe(a_deneme,s,p)
            while m > prev_m:
                counter += 1
                if counter >= maxdeneme:
                    break
                a_deneme = a - (1 / (weight * grad))
                m = mesafe(a_deneme,s,p)
                weight *= 2
                #print "weight:",weight, "a:", a_deneme, "hata=>",m
            a = a_deneme
            prev_m = m
        except ValueError:
            print "Valüü erör"
            break
    #print "hata=>",mesafe(a,s,p)
    #print counter,"denemede sonuç bulundu."
    b = p / a
    #return (round(a,2),round(b,2))
    return (a,b)

1:17am  |   URL: http://tmblr.co/ZQSyIwF5BG4R
(Yorumları görüntüle  
Kayıtlı olduğu alan: python matematik algoritma 
Tumblr'da beğenilen gönderiler: Daha fazla beğenilen gönderi »