Fatih Erikli python - django develöper

Underscore.js ile hayatınızı kolaylaştıracak fonksiyonel programlama araçları

Underscore.js javascript ile fonksiyonel programlamayı kolaylaştırmak amaçlı geliştirilen bir kütüphanedir. Backbone.js‘in de geliştiricisi olan DocumentCloud tarafından yürütülen bir projedir. Hatta underscore.js için backbone dökümantasyonunda -hard dependency- olarak belirtilmekte. Yani backbone.js’yi kullanırken projenize underscore.js’i de dahil etmek zorundasınız.

Underscore.js üzerinde çeşitli liste, nesne ve fonksiyon araçları bulunmakta. Bunların içinden en hoşuma gidenlerini buraya yazacağım.

All & Any

Bu fonksiyonlar python’da da built-in olarak bulunmakta. Bazen gerçekten çok faydalı olabiliyor.

All fonksiyonu verdiğiniz listenin içindeki değerleri bakarak boolean kontrolü yapmakta. Eğer hepsi True ise fonksiyon True olarak dönüş yapar, değil ise False. Any ise listenin içinde en az bir tane True değer varsa True döndürmekte.

_.all([1,true,false], _.identity); // false
_.all([1, true, true], _.identity); // true
_.any([1, true, false], _.identity); // true

_.identity sizi yanıltmasın. Verdiğiniz değerin aynısını geri döndüren bir fonksiyondur. Bunun yerine kendi fonksiyonunuzu yazıp gelen parametreye göre boolean bir değer döndürebilirsiniz.

Pluck
Map fonksiyonunun bir kısa yolu diyebiliriz. Diyelim ki içinde objeler olan bir listeniz var ve bu liste içindenki objelerden sadece bir özellik alarak yeni bir liste oluşturmak istiyorsunuz. Bunu ilk önce map, sonra da pluck ile yapalım;

var buddies = [ 
   {name: 'fatih', location: 'istanbul'},
   {name: 'ramazan', location: 'istanbul'},
   {name: 'yigit', location: 'istanbul'},
]
_.map(buddies, function (item) { return item.name });
>> ["fatih", "ramazan", "yigit"]
_.pluck(buddies, 'name');
>> ["fatih", "ramazan", "yigit"]

Gördüğünüz gibi map ile isimleri almak için ayrıdan bir fonksiyon yazdık. Pluck tam olarak bunun kısayolu. Ayrıdan bir fonksiyon yazmadan direk bir obje içinden attribute alarak liste oluşturabilmektesiniz. 

Ayrıca bunu python’da operator.attrgetter metoduyla yapabilmekteyiz.

Shuffle
Adından da anlaşılacağı üzere verdiğiniz listeyi randomize eden bir fonksiyondur. Fisher–Yates shuffle algoritmasına göre sıralamaktaymış.

_.shuffle(["fatih", "ramazan", "yigit"]);
>> ["ramazan", "fatih", "yigit"]

Bunlar liste ya da javascript’teki terimiyle Array fonksiyonlarıydı. Şimdi ise biraz daha fonksiyonel programlama temelli olanlarından bahsedeceğim.

Memoize

Bir optimizasyon pattern’ı olan Memoization‘ı kolaylaştıran bir fonksiyondur. Basit bir şekilde açıklayacak olursak; diyelim ki bir hesaplama fonksiyonunuz var. En klasik örneklerinden fibonacci. Memoize edilen bir fonksiyonda verdiğiniz parametreye göre hesaplama bir kere yapılır, belleğe alınır ve bir daha bu fonksiyonu aynı parametre ile çağırdığınızda tekrar hesaplamak yerinde direk bellektekini size döndürür. Bu işlemin adı Lazy Evaluation‘dır.

var calculate = function (number) {
    console.log('calculating...');
    return number * number;
}
var lazy_calculate = _.memoize(calculate);
lazy_calculate(10);
>> calculating...
>> 100
lazy_calculate(10);
>> 100
lazy_calculate(10);
>> 100
lazy_calculate(20);
>> calculating...
>> 400
lazy_calculate(20);
>> 400 

Bu fonksiyonun aynısını Django üzerinde django.utils.functional paketinde bulabilirsiniz.

Debounce
Debouncing işlemini muhakkak ki herkes kendi yöntemleriyle yapmıştır. Açıklamak birazcık güç olacak; debounced yaptığınız bir fonksiyon çağırılmadan önce bir süre bekler. Bu süreyi siz belirlersiniz, örneğin 2 saniye. Eğer 2 saniye boyunca tekrar çağırılırsa bu süre sıfırlanır.

Peki neden böyle bir şey yapayım ki diye soracak olursanız şöyle bir örnek verebilirim.

Diyelim ki otomatik tamamlama özelliği olan bir arama kutusu yapıyorsunuz. Kullanıcı her tuşa bastığında bir ajax isteği gönderip uygun sonuçları getiriyorsunuz. Eğer burada ajax isteği yaparken debouncing işlemini yapmazsanız kullanıcı 8 karakterli bir kelime yazdığında sunucuya tam 8 adet ajax isteği göndermek durumunda kalırsınız.

Bu problemi debouncing işlemi ile aşabilirsiniz. Debouncing yaptığınızda kullanıcının her yazdığı harf ile birlikte sunucuya istek yapmak yerine kullanıcının yazacağı kelime bittiğinde 2 saniye gibi bir süre bekleterek istek sayısını 1’e indirebilirsiniz.

Bir örnek yapalım;

var request = function () {
   console.log("hello, this response from server");
}
var debounced_request = _.debounce(request, 2000);
debounced_request();
debounced_request();
debounced_request();
debounced_request();
// sonra 4 istek yapmamıza rağmen 2 saniye sonra 1 adet yanıt gelecek.
>> 'hello, this response from server'

Bu işlem ile ilgili Don’t spam your server ve Debouncing javascript methods makalelerini okumanızı tavsiye edebilirim.

Throttle
Bu fonksiyon debouncing işlemine benzemektedir. Throttling işlemini bir fonksiyonun kullanımının zaman ile kısıtlanılması gerektiği yerlerde kullanmaktayız. Debounced edilmiş bir fonksiyon peş peşe çağırıldığında aradaki süre sizin belirlediğiniz süreden kısa ise belirttiğiniz sürenin dolmasını bekler.

Örnek verecek olursak; bir refresh butonunuz var. Kullanıcı buraya tıkladığında sayfada bir bölüm refresh oluyor. Eğer buna kısıtlama getirmezseniz kullanıcı bu butona 30 kere peş peşe bastığında 30 tane istek ard arda yapılır. Bunu throttle ile aşabilirsiniz.

var request = function () {
   console.log("hello, this response from server");
}
var throttled_request = _.debounce(request, 2000);
throttled_request();
>> 'hello, this response from server'
// 1 sn. bekliyoruz
throttled_request();
// cevap 1. sn sonra geliyor. çünkü throttle ederken 2 saniye süre verdik.
>> 'hello, this response from server'

Bind

Bu fonksiyon ECMAScript 5’ten itibaren artık built-in olarak Javascript’te bulunmakta. Ancak cross-browser bir javascript kodu yazmak istiyorsanız Underscore.js üzerinden kullanmanız daha faydalı olabilir.

Diyelim ki  şöyle bir fonksiyonunuz var;

var hello = function () {
   return "hello, " + this.name;
}
hello();
>> 'hello undefined'
window.name = 'fatih';
hello();
>> 'hello fatih'

Gördüğünüz gibi ilk önce name öğesini istediğimizde undefined cevabını aldık. Global olarak tanımladığımız bir fonksiyonun scope’u window’dur. Window objesinde name tanımı olmadığı için yoktu. Tanımladıktan sonra fonksiyondan beklediğimiz cevabı alabildik.

Karışık bir örnek oldu. Çünkü javascript’teki this keyword’u diğer dillerdeki this keyword’üne hiç benzemiyor.

Bunun gibi durumlarda fonksiyonları call ya da apply ile çağırarak scope’unu değiştirebilmekteyiz. Call ve apply arasındaki fark call’un parametreleri fonksiyon parametresi olarak, apply’ın ise liste şeklinde almasıdır.

Bind fonksiyonu bu işlemi daha da kolaylaştırmakta. Size apply işlemini yapan bir fonksiyon döndürmektedir. 

var hello = function () {
   return "hello, " + this.name;
}
hello();
>> 'hello undefined'
hello.apply({ name: 'fatih' });
>> 'hello fatih'
var binded_hello = _.bind(hello, { name: 'fatih' });
binded_hello(); 
>> 'hello fatih'

Gündelik hayattan başka bir örnek daha vermek istiyorum. Mesela backbone projelerini incelediyseniz bind ve bindAll fonksiyonlarının çok çok kullanıldığını görmüşsünüzdür. Çünkü bu işlemi yapmadan iç içe fonksiyonlar yazdığınızda this ile objeyi alıp başka bir değişkene atamak durumunda kalıyoruz. Örneğin var self = this; gibi. Bu da bir hayli pis bir yöntem.

Gündelik hayattan bir örnek demiştik;

var request = { 
   'result_text' : 'congratulations',
   'post' : function () {
      // callback fonksiyonuna scope atamasi yapiyoruz.
      $.post('/send', _.bind(function (response) {
           console.log(this.result_text);
      }, this));
      // bu sayede callback fonksiyonunda result objesini kullanabileceğiz.
   }
}

Burada apply ya da call kullanamazdık, çünkü callback fonksiyonunu biz değil jquery’nin get methodu çağırmakta. Bind kullanmak en mantıklı çözüm.

Ayrıca bu süpersonik çok amaçlı fonksiyon ile currying işlemi de yapabilmekteyiz. Currying bir fonksiyonun parametrelerini önceden vererek başka bir fonksiyon oluşturmaktır.

var people = function (country, name) {
   return 'hello ' + country + ', hello ' + name;
}
people('turkey', 'fatih');
>> 'hello turkey, hello fatih'
var turkey_people = _.bind(people, {}, 'turkey');
turkey_people('fatih');
>> 'hello turkey, hello fatih'

Sadece bind fonksiyonunu için underscore.js’yi yüklemek istemiyorsanız şu snippet’i kullanabilirsiniz;
https://github.com/taylanpince/jquery-class/blob/master/src/bind.js  

Ayrıca Python Istanbul buluşmasında console.log’u bind etme konusunda beni beni aydınlattığı için Burak Yiğit Kaya‘ya teşekkürlerimi sunarım :)
Bir de  kendisinin twitter üzerinden yazdığı bir öneri üzerine şuna da değinmek istiyorum;

ECMAScript 5 ile Underscore.js üzerinde de göreceğiniz forEach, map, reduce, reduceRight, some, filter, every gibi bazı array fonksiyonları native bir şekilde gelmekte. Underscore.js bunların kontrolünü yapıp eğer browser destekliyorsa native olanı kullanmaktadır.

Önerebileceğim Underscore.js kaynakları

Diğerleri

Developer’lar için Türkçe podcast

Uğur Özyılmazel‘in hazırladığı çok taze ve çok iyi başlamış bir podcast. Bugün (pazartesi) ikinci bölümü yayınlandı. Bölümün adının 001 olması sizi yanıltmasın. İlk bölüm 000’dı. Podcast’e giriş niteliğinde bir bölümdü.

Podcast’i dinlemek için devpod adındaki soundcloud hesabını takip edebilirsiniz. Ayrıca Itunes üzerinden de dinleyebilirsiniz.

http://soundcloud.com/podcastmaster/sets/devpod
http://itunes.apple.com/tr/podcast/devpod/id529938071

Eğer siz de benim gibi bir tumblr fanıysanız, tumblr üzerinden de takip edebilirsiniz;
http://devpod.tumblr.com/ 

Bu bölümde benim blogum hakkında da biraz bahsetmiş, buradan kendisine teşekkürlerimi sunuyorum. Blog post’larımın okunduğunu görmek gerçekten sevindirici. Bundan sonra daha sık yazarım artık :)

Bunun gibi girişimler gerçekten çok heyecan verici oluyor. Özellikle bölümün sonunda bahsedilen development içerikli türkçe blog’ların tanıtımının hem herkes için çok faydalı hem de blog yazmaya teşvik edici bir şey olacağını düşünüyorum.

Takipteyiz :)


Python İstanbul Mayıs buluşmasından notlar

Bu ay da çok hareketli ve güzel geçen bir Python İstanbul buluşmasını 20 Python severin katılımıyla gerçekleştirdik. Geçen ay olduğu gibi bu buluşmada da Hipo ofisinde toplandık. Cumartesi günümüz python severlerle burada bir kahvaltı ile başladı, muhabbet ve sunumlarla devam etti. Gerçekten cumartesi günümü çok iyi değerlendirdim diyebilirim. 

Bu toplantıda 3 sunum yapıldı, sunumlardan birisini de benimdi. Sunumlar sırası ile şöyle yapıldı;

  • Pyİst geçmişi ve yön haritası (Metin Amiroff)
  • Celery ve RabbitMQ (ben)
  • PyPy & Just-in-time (JIT) compilation (Berker Peksağ)

Celery Sunumu
Sunumda bir AMQP protokolü implementation’ı olan RabbitMQ‘yu ve bunu message broker olarak kullanabilen Celery‘nin bize getirdiği kolaylıklardan bahsettik. Sunum için ayrıca bir de demo application hazırlama fırsatı olmuştu. Bununla birlikte bir de Onur Çelebi Connect 4 oyunu için hazırladığı algoritmanın Celery halini hazırlayıp bizlere sundu. 

Celery sunumuna şuradan ulaşabilirsiniz;
http://fatiherikli.com/pyist/pyist-celery.pdf

Demo uygulamayı incelemek isterseniz de;
https://github.com/fatiherikli/downforeveryoneorjustme

Onur Çelebi’nin hazırladığı demo application’a da ulaşır ulaşmaz buraya linkini koyacağım.

PyPy sunumu
Berker Peksağ hazırladığı sunumda ise PyPy‘ın sağladıkları, PyPy alternatifleri ve development sürecini anlattı. Ayrıca PyPy’ın getirdiği avantajlardan ziyade dezavantajlarına da değindi. Hoş bir sunum olmuş gerçekten. PyPy hakında değişik bilgiler edindim. Kendisine buradan teşekkürlerimi sunuyorum :)
Sunuma aşağıdaki linkten ulaşabilirsiniz;
http://berkerpeksag.github.com/slides/pypy-101-pyist/pypy-101-pyist.pdf


Python’cuların kedi sevdası
Buluşma sadece sunumlardan ibaret değildi. Hatta sunumdan çok vakti hoş sohbet, geyik ve Nerd muhabbetiyle geçirdik :)
Bunun dışında toplantıda bütün Python’cuların gönlünü kazanan minik bir misafirimiz daha vardı. Daha doğrusu pek misafir denmez, ev sahibi demek daha doğru olur. Ona herkes hipo kedi diyor. Gerçi pek rahat durmadı ama olsun, toplantıya neşe kattı diyebiliriz. Ayrıca hipo kedi sayesinde community’deki kedi severleri de tespit etmiş olduk. 

Yine bir ay sonraki toplantıyı dört gözle bekliyorum. Haziranda bir Hack Day yapılması planlanıyor. Python ile uğraşan ya da merak salan herkese kaçırmamalarını tavsiye ederim :)

PyQuery: Python ile jQuery tadında html parse edin

En sevdiğim kütüphanelerden bir tanesini daha sizinle paylaşmak üzereyim :)

PyQuery elinizdeki html veriyi jQuery seçicileriyle ve fonksiyonlarıyla işlemenizi sağlıyor. Aşağıdaki gibi kullanabilirsiniz; 

>>> from pyquery import PyQuery 
>>> j = PyQuery(url="http://fatiherikli.com")
>>> j("title").html()
'Fatih Erikli'
>>> j("p").length
4
>>> j("p").eq(0).parent()
[<div.post>]
>>> print j(".post").find("h3").html()
short bio

Kurulumu:

pip install pyquery

Dökümantasyona aşağıdaki linkten ulaşabilirsiniz;
http://packages.python.org/pyquery/api.html  


Backbone.js, Django ve Tastypie üçlüsü ile bir scrum board uygulaması

Backbone javascript ile mvc (model-view-controller) iskeleti üzerinde genişleyebilir (scalable) uygulama geliştirmenizi sağlayan bir kütüphanedir. Underscore.js ve jQuery ile birlikte kullanılmaktadır.

Uzun zamandır backbone ile scrum board tarzı bir şey yapasım vardı. En sonunda yaptım, ve kodlarını github üzerinde açtım. Aşağıdaki linkten inceleyebilirsiniz;

http://scrumboard.herokuapp.com/

Heroku üzerinde free olarak yayınladığım için biraz yavaş olabilir. O yüzden siz en iyisi aşağıdaki gibi bilgisayarınıza kurupta çalıştırın :)

$ git clone git://github.com/fatiherikli/scrumboard.git
$ cd scrumboard
$ pip install -r requirements.txt 
$ python scrumboard/manage.py runserver 

scrumboard/static/js/app dizini altındaki controllers.js, views.js ve models.js dosyalarını inceleyebilirsiniz.

Ayrıca kodlara aşağıdaki linkten ulaşabilirsiniz. Hatta hoşunuza gider ve forklarsanız geliştirmeye birlikte devam edebiliriz :)

https://github.com/fatiherikli/scrumboard

Python’da fonksiyonel programlama ve bir Internal DSL örneği

Fonksiyonel programlama dilleri sadece fonksiyon kullanarak program geliştirmeye olanak tanır. Ayrıca fonksiyonların istenen değeri döndürmekten başka bir görevi de olmaz. Şurada daha da açıklayıcı bir tanım bulabilirsiniz.

Python fonksiyonel bir programlama dili değildir ancak fonksiyonel programlamaya özgü bazı özellikleri desteklemektedir. 

Python üzerinde fonksiyonlar birer first-class objelerdir. Bu sayede fonksiyonu istediğiniz gibi saklayabilir, başka bir fonksiyon parametresi olarak alabilir, parametreleri üzerinde oynayabilirsiniz. Python’da built-in olarak high-order functions olarak bilinen verilen fonksiyon olarak parametre alan ve olarak başka bir fonksiyon veya verdiğiniz fonksiyone özgü sonuç döndüren fonksiyonlar bulunmaktadır.

Aşağıda bir kaç tane teknik ve python’da üzerinde html kod üretebilmek için bir Internal (embedded) DSL örneği verdim.

Lambda

Lambda ile isimsiz fonksiyon (anonymous function) tanımlayabilmektesiniz. Bu size fonksiyonlarınızı çok daha kısa ve tek satırda oluşturmanıza olanak tanır. 

wrap_tags = lambda x, c : '<%s>%s</%s>' % (x, c, x)
print wrap_tags('strong', 'heey') # <strong>heey</strong> 

Bu fonksiyonu aşağıdaki gibi de yazabilirdiniz. İki fonksiyonun sonucu da aynıdır. Farkı ise Lambda ile tek satırda yazabiliyor olmanız.

def wrap_tags(x, c):
    return '<%s>%s' % (x, c, x)

Closures

Closures bir fonksiyonun içinde verilen değere göre döndürülen başka fonksiyonlardır. Yukarıdaki örneğimizde wrap_tags adında fonksiyon yazdık. Bu fonksiyon bize verdiğimiz tag’a ve text’e göre html kodu yazdırıyor. fonksiyonu aşağıdaki gibi closure olarak kullanalım.

def tag_factory(tag):
    def inner(code):
        return wrap_tags(tag, code)
    return inner

Bu fonksiyonun lambda şekli;

tag_factory = lambda tag : lambda code : wrap_tags(tag,  code)

tag_factory fonksiyonumuz tag parametresi almakta ve bu taga göre wrap_tags işlemini yaptıran bir fonksiyonun döndürmekte. Bu fonksiyonu aşağıdaki gibi kullanabiliriz.

print tag_factory('html')(
        tag_factory('head')(
            tag_factory('title')('SELAAM')
        )
      )
# result is <html><head><title>SELAAM</title></head></html> 


Partial

functools kütüphanesindeki bu araç ile bir fonksiyonu önceden belirlediğiniz parametrelerle çağırıp kullanabilirsiniz. Bu işlemin adı currying‘dir. Örnek olarak yukarıdaki closure örneğini partial methodu ile gerçekleştirelim.

from functools import partial
wrap_tags = lambda x, c : '<%s>%s</%s>' % (x, c, x)
HTML = partial(wrap_tags, 'html') BODY = partial(wrap_tags, 'body') HEAD = partial(wrap_tags, 'head') STRONG = partial(wrap_gas, 'strong')
UL = partial(wrap_tags, 'ul') LI = partial(wrap_tags, 'li') print HTML( BODY( UL( LI('Selamlar') ) ) )

Reduce

Yukarıdaki örneğimizde basitçe python üzerinde html kod üretmek için mini bir Internal DSL yazdık :) Ancak bir eksiği var. Html fonksiyonları yalnız bir adet parametre alıyor. Yani yukarıdaki örnekte iki adet ya da daha fazla liste öğesi içeren bir liste çıkaramıyoruz. Bunu reduce ile aşabiliriz. 

Reduce bir dizideki elemanların tümünü tek tek belirttiğiniz fonksiyona verip tüm elemanlarla ilgili bir sonuç çıkarmanızı sağlayan araçtır. Reduce’a ilk vereceğiniz parametre iki adet parametre alan bir fonksiyon, ikincisi bir liste, üçüncüsü de sonucun başlangıç (initial) değeridir. Reduce işlemi folding olarakta bilinmektedir.

Basir bir örnek yapalım;

from operator import add
print reduce(add, range(1,10))

operator.add fonksiyonu python’daki toplama işlemidir. İki adet parametre alır ve bunları toplar. Bunu biliyoruz :) biz bu fonksiyonu reduce parametresi olarak kullanıp 1’den 10’a kadar olan sayıların toplamını aldırdık.

Şimdi DSL örneğimize geri dönelim. wrap_tags fonksiyonumuzu aşağıdaki gibi değiştirelim.

from operator import concat
wrap_tags = lambda x, *c : '<%s>%s</%s>' % (x, reduce(concat, c), x)

Çıktı aşağıdaki gibidir;

print DIV(STRONG('heey '), 'selam')
# <div><strong>heey</strong> selam</div> 

operator modülündeki concat python’daki string birleştirme işleminin fonksiyonudur. Reduce üzerinde bu fonksiyonu ilk parametre, *c ile aldığımız kod listesini de ikinci parametre olarak verdik. Ve problemimiz çözüldü. Bunu string fonksiyonu olan join ile aşabilirdik ama konumuz bu değil. Maksat örnek olsun :)

Biraz daha geliştirelim. Fonksiyonuza keyword arguments olarak html tag’ının parametrelerini aldıralım. Bu işlemi yapmak için ise bir başka fonksiyonel programlama aracı olan map’i kullanacağız.

Map

İki adet parametre alır. Birinci parametre fonksiyondur. İkincisi ise listedir. Map listeki her elemanı verdiğiniz fonksiyon’dan geçirir ve size tekrar liste döndürür. Aşağıdaki örnekle daha iyi anlaşılacaktır. 

print map(lambda x : x*x, range(1,10))
# [1, 4, 9, 16, 25, 36, 49, 64, 81]  

Parametre olarak verdiğimiz fonksiyon verilen sayının karesini döndürmekte. Gördüğünüz üzere 1’den 10’a kadar olan sayıların karesi liste şeklinde elimizde artık. Şimdi tekrar DSL örneğimize geçelim. Html tagları için parametre örneğini yapalım. Bu işlemi lambda yerine klasik fonksiyon ile yapalım.

def parameters(**p):
    def _build_parameters(parameter):
        key, value = parameter
        return ' %s="%s"' % (key, value)
    return reduce(concat, map(_build_parameters, p.items() ) , '')

wrap_tags = lambda x, *c, **p : '<%s%s>%s</%s>' % (x, parameters(**p), reduce(concat, c), x)

Bu fonksiyonun lambda şekli ise;

parameters = lambda **p : \
             reduce(concat,
                # build parameters from dict with mapping.
                map(lambda k: ' %s="%s"' % (k[0], k[1]) , p.items() ),
                '') # empty string for reduce initial.

Artık keyword-arguments olarak html parametreleri belirtebiliyoruz;

print DIV('selamlar', id='container', style='font-size:15px')
# <div style="font-size:15px" id="container">selamlar</div>

Html tag’ının parametreleri bize keyword-arguments olarak Dictionary şeklinde gelmekte. Biz bu dictionary objesini items metoduyla (key, value) şeklinde tuple içeren bir listeye dönüştürdük. Key parametremiz, value ise parametremizin değeri. Biz listedeki parametrelerimizi html’e uygun olacak şekilde döndürüp Reduce ile düz bir string haline getirdik.

Filter

Bu işleme DSL’de ihtiyaç duymadık ancak çok kullanışlı fonksiyonlardan bir tanesidir. Map ve Reduce’deki gibi ilk parametre fonksiyon, ikincisi de liste olacak şekilde kullanmaktasınız. Fonksiyonunuz boolean (true/false) bir değer döndürmelidir. Filter işlemi verdiğiniz bu fonksiyona göre listenizde filtreleme yapacaktır. Aşağıdaki örnekle çok daha iyi anlaşılacaktır.

print filter(lambda x : x % 2 == 0, range(1,10))
# [2, 4, 6, 8]

Bir sayının 2’ye bölünüp bölümediğini kontrol eden bir fonksiyon yazdık. Ve bu fonksiyone göre sonucu False dönenleri filtreledik.

Ve son olarak DSL örneğini tam olarak vereyim. Ancak bir şey belirtmek istiyorum;

Dikkat. Ofiste denemeyin !

Aşağıdaki örneği tamamen fantazi olsun diye veriyorum :) Zira aşağıdaki gibi partial’ı partial olarak çağıran, lambda kullanıcam diye ortaya anlaşılmaz karman çorman bir kod çıkaran, yerden tasarruf olsun diye değişkenleri packing şeklinde tanımlayan bir iş arkadaşım olsa herhalde boğardım ben. Fonksiyonlar arasında hoplayıp zıplamak ne kadar eğlenceli olsa da abartmamak gerekir. pep-8’e ve diğer kod standartlara küfür niyetinde bir kod yazdık :) 

# -*- coding:utf-8 -*-
from functools import partial
from operator import concat

parameters = lambda **p : \
             reduce(concat,
                # build parameters from dict with mapping.
                map(lambda k: ' %s="%s"' % (k[0].replace('_',''), k[1]) , p.items() ),
                '') # empty string for reduce initial.

wrap_tags = lambda x, *c, **p : \
            '<%s%s>%s</%s>' % (
                x, # open tags
                parameters(**p), # tag parameters
                reduce(concat, c), # content
                x)  # close tags

HTML, HEAD, TITLE, BODY, H1, UL, LI, FOOTER, DIV = map(\        
    partial(partial, wrap_tags),
    ['html', 'head', 'title', 'body', 'h1', 'ul', 'li', 'footer', 'div']
)


print HTML(
        HEAD(
            TITLE('Python üzerinde fonksiyonel programlama')
        ),
        BODY(
            H1('Fonksiyel programlama nedir ?', style="margin:0px;", id="title"),
            UL(
                LI('Lambda Calculus', _class="first"),
                LI('High-order Functions'),
                LI('Functions as First-class Objects'),
                LI('Closures'),
                LI('Currying', _class="last"),
            )
        ),
        FOOTER(
            DIV("Her hakkı saklıdır.", id="footer")
        )
     )

Evet, fonksiyonel programlama araçları sayesinde tüm kodumuzda sadece iki adet ismi olan fonksiyon tanımladık. Fonksiyonel programlama dillerindeki esneklik olmasa da python’da gayet tatlı bir şey çıkardık :)

Aşağıdaki bağlantıları da incelemenizi tavsiye ederim.

http://c2.com/cgi/wiki?FunctionalProgramming
http://en.wikipedia.org/wiki/Functional_programming
http://www.slideshare.net/adambyrtek/functional-programming-with-python-516744
http://www.slideshare.net/newmedio/introduction-to-functional-programming
http://burcudogan.com/2009/03/08/functional-programing-for-beginners/

Django’da admin üzerinde çalışırken hayatınızı kolaylaştıracak iki decorator

def allow_tags(func):
"""
Bir ModelAdmin uzerinde yazdiginiz fonksiyonun html olarak cikti verebilmesini saglar.
"""
func.allow_tags = True return func def short_description(description):
"""
ModelAdmin uzerinde yazdiginiz fonksiyonlara short_description atamasi yapar.
""" def wrap(func):
func.short_description = description return func return wrap

Şu şekilde kullanabilirsiniz;

class FooBarAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'my_method')

@allow_tags
@short_description('Benim bold kolonum')
def my_method(self, obj):
return '<strong>selamm !</strong>' 

Heroku’daki uygulamanız için SQL konsolu

Aşağıdaki plugin sayesinde konsol üzerinden heroku uygulamanızın veritabanında sql sorguları çalıştırabilir ve sonuçlarını görebilirsiniz.

https://github.com/ddollar/heroku-sql-console

Kurulum

Heroku projenizin dizinine gidin ve şu şekilde plugin’i ekleyin.

heroku plugins:install git://github.com/ddollar/heroku-sql-console.git

Plugin’i yüklediniz. Konsola da şöyle erişebilirsiniz.

$ heroku sql
SQL> select count(*) from users;
+-------+ | count | +-------+ | 13 | +-------+ 

Python üzerinde Design Patterns (Tasarım Desenleri) örnekleri

Bu blog post’unda kendi projelerimde ya da çalıştığım şirkette development sürecinde kullandığımız design pattern’ları ve bu konudaki python’un avantajlarına değineceğim.

Design Patterns
Bu kavramın henüz türkçesi bulunmadı :) Genelde tasarım örüntüleri ya da tasarım desenleri denmekte.

Design pattern’lar development sürecinde sıkça rastlanan problemleri çözmek için kullanılan desenlerdir. Bunların bir -desen- olmasının sebebi problemi çözmekten ziyade probleme object-oriented’ın temel felsefelerinden olan reusable (yeniden kullanılabilir) çözümler getirmektir. 

Gang of Four (dörtlü çete) olarak bilinen 4 kafadar 1994 yılında Design Patterns: Elements of Reusable Object-Oriented Software isimli kitaplarında 3 farklı kategoride 23 farklı tasarım deseni derlemiştir. Bu kategoriler;

  • Creational patterns: Objelerin oluşturulması ile ilgili desenlerdir
  • Structural patterns: Sınıflar arasındaki bağlantıları gevşek tutmak ve projenin genişletebilmesini sağlayan desenlerdir.
  • Behavioral patterns: Sınıflar ya da objeler arasında composition ya da inheritance kullanılarak iletişim kurmak için kullanılan desenlerdir.

Desen örnekleri vermeden design pattern ve object-oriented prensiplerine göre bir kaç şeyden bahsetmek istiyorum.

  • Design pattern’lar ezberlenmemelidir. Bütün desenleri inceledikten sonra zaten ortaya çıkan problem sizi design pattern kullanmaya itecektir.
  • Design pattern’ların kullanımı abartılmamalıdır. Problem sizi zaten gerekli yerlerde design pattern kullanmaya itecektir. Zira çözümünüz bir anti-pattern‘e dönüşebilir.
  • Kullandığınız platformu ya da programlama dilininin getirtiği avantajları tam anlamıyla bilmeden bir deseni uygulamamak gerekir.
  • Her sınıfın sadece tek bir sorumluluğu olmalıdır. Bunu desen örneklerinde bolca göreceksiniz. Başka sorumluluklar ayrı sınıflara dağıtılmalıdır. Bu yol inheritance değil, composition olmalıdır. Aksi takdirde object-oriented kasıcam diye ileride kodlara dönüp baktığınızda bir god-object görebilirsiniz :)
  • Burada listelediğim bir kaç desen size yetmeyecektir. Blog post’unun altında bu konu ile ilgili bolca link yazdım. Ayrıca django, pika, sqlalchemy, tornado gibi tonlarca open-source yazılımların kaynak kodlarını okumanızı tavsiye ederim. Desen yuvalarıdır onlar :) buradaki kuru örnekler yerine onları okumak daha faydalı olacaktır.

3. maddeyi biraz daha açıklamak istiyorum. Örnek olarak python’da zaten built-in gelen iterator pattern’ini kendimiz yazmamız aptalca olur. Diğer bir örnek ise örnek python’da fonksiyonların first-class objeler olmasıdır. Yani fonksiyonları istediğimiz saklayabilir, çalışma zamanında olarak programın akışına göre değiştirebiliriz. Bu bize çoğu pattern’i uygularken inanılmaz kolaylıklar sağlamaktadır. Wikipedia’daki strategy pattern‘in açıklamasında bunu görebilirsiniz.

Python üzerinde en sık kullanılan 8 pattern’in örneğini vereceğim. Bu 8 pattern’in 8 pattern olmasının sebebi tamamen zannımca, kendi gözlemlerimdir.

  • Creational Patterns 
    • Singleton Pattern
    • Factory Pattern
  • Structural patterns
    • Decorator Pattern
    • Proxy Pattern
  • Behavioral patterns
    • Iterator Pattern
    • Observer Pattern
    • Strategy Pattern
    • Null-object Pattern

Singleton Pattern

Bu desende bir class’ın sadece bir tane instance’ı olması gerekmektedir. En çok kullanılan ve en basit desenlerden biridir. Amacı aynı işi yapan bir sürü instance’ın bellekte ayrı ayrı yer işgal etmesi yerine tek bir instance üzerinden iş yapmasını sağlamaktır. Genellikle database’ bağlanmak gibi bir kere yapılması gereken yerlerde kullanılır. 

def singleton(klass):
    if not hasattr(klass, 'instance'):
        klass.instance = klass()
    return klass.instance

class Connection(object):
    def __init__(self):
        print "init..." # sadece bir kez calismali.

a = singleton(Connection)
b = singleton(Connection)
print a is b # True


Factory Pattern

Factory pattern’i programın akışına göre belirlediğiniz sınıf ya da objeleri getiren fabrika olarak düşünebilirsiniz. Örneğin kullanılan database türüne göre bir database client’i getirmek için kullanılabilir. Ya da eğer makina linux ise şu modülü, windows işe şu modülü yükle gibi…

Django üzerinde formset’lerle işlem yaparken kullandığımız formset_factory, modelformset_factory birer factory pattern’ına örnektir;

def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
                    can_delete=False, max_num=None):    
    attrs = { 
'form' : form,
'extra' : extra, 'can_order' : can_order,
'can_delete': can_delete, 'max_num' : max_num
} return type(form.__name__ + 'FormSet', (formset,), attrs)

Bu desende çağırırken verdiğiniz forma göre ve belirlediğiniz miktara göre form içeren bir FormSet sınıfı döndürülmektedir. Daha da basit bir örnek verecek olursak; tumblr gibi bir servis üzerindeki post tiplerine göre bize model döndüren bir factory method yazalım. 

def post_model_factory(model):
    return {
        'dialog' : Dialog,
        'quote'  : Quote,
        'link'   : Link,
        'video'  : Video,
        'audio'  : Audio,
    }.get(model) or Post # eger bulunmazsa, default olarak Post modeli donduruluyor.


Decorator Pattern

Decorator pattern’i bir sınıfa onu türetmeden ya da temel yapısında değişiklik yapmadan çalışma zamanında ek özellikler eklememizi sağlayan bir desendir. 

Aslında Singleton Pattern örneğinde bir decorator pattern’i uyguladık. Singleton olmasını istediğimiz sınıf üzerinde birazcık oynama yaptık. Decorator pattern’i yaptığımız işlemin ta kendisidir

def singleton(klass):
    if not hasattr(klass, 'instance'):
        klass.instance = klass()
    return klass.instance

class Connection(object): def __init__(self): print "init..." # sadece bir kez calismali.

connection = singleton(Connection)

Ayrıca bildiğiniz üzere python’da built-in olarak decorator desteği var. Örneğin singleton pattern örneğini şu şekilde yapabilirdik.

def singleton(klass):
    if not hasattr(klass, 'instance'):
        klass.instance = klass()
    return klass.instance

@singleton # Connection artik bir class degil, instance.
class Connection(object): def __init__(self): print "init..." # sadece bir kez calismali.


Proxy Pattern

Proxy Pattern orijinal class’a dokunmadan, başka bir class oluşturup yeni özellikler eklememizi sağlayan bir desendir. Bunun için en iyi örnek olarak django’daki proxy model’leri gösterebilirim.

Django dökümantasyonundan bir örnek vermek istiyorum;

from django.contrib.auth.models import User
class MyUser(User):
    class Meta:
        proxy = True

    def do_something(self):
        pass


Iterator Pattern

Bu pattern python üzerinde built-in olarak gelmektedir. Iterator Pattern bir listedeki elemanların içerisinde dolaşmak, sonraki ve önceki elemanı bulmamızı sağlar. Bu liste sonsuz bir liste olabilir. Örneğin fibonacci serisinin tüm değerlerini bir listeye atamazsınız, ama iterator ile yaptığınızda sadece bir sonraki fibonacci sayısını istediğinizde size o sayıyı hesaplar ve getirir. 

En basit şekilde bir iterator deseni;

def iterator():
    yield "hey"
    yield "selam"
    yield "naber"

for item in iterator(): print item

Bir örnek yapacak olursak; bir model’deki kayıtlar üzerinde hesaplama yapıp sonuçlarından bir liste oluşturmak gerekmekte.

Kötü örnek;

def orders():
    result = []
    for item in Orders.objects.all():
        result.append(item.calculate()) # uzun suren bir islem
    return result 

Bu şekilde listenin oluşabilmesi için bütün kayıtların hesaplanması ve listeye eklenmesi gerekiyor. Ama bize sadece ilk 10 kaydın hesaplamaları gerekli. Fail :)
Bunu aşağıdaki gibi yapmamız gerekiyor;

def orders():    
    for item in Orders.objects.all():
        yield item.calculate() # uzun suren bir islem  

Ayrıca iterator’lerin aşağıdaki gibi bir kullanımı da mümkündür. Satchmo‘nun cart modelinden örnek veriyorum;

class Cart(models.Model):    
    site = models.ForeignKey(Site, verbose_name=_('Site'))
    desc = models.CharField(_("Description"), blank=True, null=True, max_length=10)
    date_time_created = models.DateTimeField(_("Creation Date"))
    customer = models.ForeignKey(Contact, blank=True, null=True, verbose_name=_('Customer'))

    objects = CartManager()

    # her hangi bir sinifa asagidaki gibi iteration ekleyebiliyoruz.
    def __iter__(self):
        return iter(self.cartitem_set.all())
# ... 

Bu sayede sepete ait ürünleri aşağıdaki kolayca alabiliyoruz.

cart = Cart.objects.from_request(request)
for item in cart:
print item # artik item bir CartItem instance'ı...


Observer Pattern

Publish/subscribe olarakta bilinmektedir. Temel anlamda sınıflarımıza event, yani olay atamamızı sağlayan desenlerdir. Bu desende bir objenin durumunun değişmesi durumunda, dinlemekte olan belirlediğiniz gözlemcilere haber gitmektedir.

Django’daki signal dispatcher kullanımı observer pattern’ine bir örnektir. Django’daki signals kullanımı ilgili bir örnek veriyorum;

def create_user_profile(sender, instance, created, **kwargs):
    if created:
       profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)


Strategy Pattern

Strategy pattern’i bir işin yapılmasının yöntemini çalışma zamanında belirlemenizi sağlar. Benim en sevdiğim desendir :)  Örneğin bir servisiniz için bir importer yazacaksınız diyelim. Yazacağınız sınıfta verileri import ettiğiniz ve nereden import edeleceği kısımlarının ayrı tutulması gerekir. Import ettiğiniz servis bir rss ya da tamamen standart dışı bir xml olabilir. Bu gibi durumlarda komple import servisiniz yerine, import edeceğiniz yere özel strategy sınıfı düzenleyip o şekilde import etmeniz gerekir. 

Pika‘nın connection sınıfında bu deseni görebiliriz.

# ReconnectionStrategy super sinifi bos bir interface sinifidir.
class NullReconnectionStrategy(ReconnectionStrategy): pass
class SimpleReconnectionStrategy(ReconnectionStrategy): can_reconnect = True def __init__(self, initial_retry_delay=1.0, multiplier=2.0, max_delay=30.0, jitter=0.5): # implement edilen yerler onemli degil, kirptim.
class Connection(object): def __init__(self, parameters=None, on_open_callback=None, reconnection_strategy=None):
# ... self.reconnection = reconnection_strategy or NullReconnectionStrategy()
# ...

Connection sinifinda re-connection işleminin strategy olarak alındığını görüyoruz. Burada yapılan işlemin adı composition‘dur. Connection sınıfında re-connection işlemlerinin yapılması yerine re-connection işlemi yapılacak yerlerde buradaki tanım üzerinden yapılacaktır.

Ayrıca zorunda olmadıkça buradaki gibi uzun uzun strategy tanımları yapmamıza gerek yok. Zaten python’daki fonksiyonlar first-class objelerdir. Birazcık pitonik olmak lazım :) Aşağıdaki örnekle daha iyi anlaşılacağını umuyorum.

def urllib_strategy(url):
    import urllib2
    return urllib2.urlopen(url).read()

def requests_strategy(url):
    import requests
    return requests.get(url).content

def get_html_source(url, opener_strategy=urllib_strategy): # default urllib_strategy
    return opener_strategy(url)

print get_html_source("http://fatiherikli.com")
print get_html_source("http://fatiherikli.com",
                      opener_strategy=requests_strategy)
print get_html_source("http://fatiherikli.com",
                      opener_strategy=lambda url : "fake html source.")

Bu deseni çoğu yerde görebilirsiniz. Bir örnek daha; Django’daki User application’ının view’larındaki login view’ında bu pattern uygulanmış durumda.

def login(request, template_name='registration/login.html',
          redirect_field_name=REDIRECT_FIELD_NAME,
          authentication_form=AuthenticationForm):
    redirect_to = request.REQUEST.get(redirect_field_name, '')
    form = authentication_form(data=request.POST)
# ... 

Gördüğünüz üzere AuthenticationForm ‘u view’da parametre olarak almaktadır. Varsayılan olarak kendi formunu kullanıyor, ancak siz view’ı çağırırken urls.py’nizde kendi login formunuzu verebilmektesiniz.


Null Object Pattern

Null object pattern’i olmayan bir obje üzerinde işlem yaparken programın hata vermemesini sağlamaktır. Ayrıca bu desen sayesinde gereksiz null kontrollerinden kurtulmuş oluyoruz.

Bunun örneğini yine django üzerinden vereceğim. Bildiğiniz üzere django bize request.user dediğimizde bize aşağıdaki User sınıfını döndürmekte; 

class User(models.Model)
# ...
def is_anonymous(self):
return False def is_authenticated(self): return True
# ... 

Gördüğünüz üzere User sınıfında is_authenticated ve is_anonymous method’ları direk true-false döndürecek şekilde implement edilmiş. Bunun sebebi eğer kullanıcı login olmuşsa bu sınıf kullanılacak, login olmamış ise aşağıdaki AnonymousUser sınfı kullanılmasıdır. AnonymousUser sınıfında is_anonymous ve is_authenticated methodları tam ders durumda olacaktır. 

class AnonymousUser(object):
    id = None
    username = ''
    is_staff = False
    is_active = False
    is_superuser = False    
# ... def __unicode__(self): return 'AnonymousUser' def is_anonymous(self): return True def is_authenticated(self): return False
# ... 

Gördüğünüz gibi bu sınıfta bir model instance’ı taklit edilmiş durumda. Bu sayede request.user.is_authenticated dediğimizde None type bla bla hatasını almadan kullanıcının login olup olmadığını anlayabiliyoruz.

Ayrıca bu desenin örneğini strategy pattern’inin örneklerinde verdiğim pika kütüphanesinin NullReconnectionStrategy sınıfında da görebilirsiniz. 

Bu desenin başka bir örneğini satchmo’nun cart modelinde görebilirsiniz. 

class NullCart(object):
    desc = None
    date_time_created = None
    customer = None
    total = Decimal("0")
    numItems = 0

    def add_item(self, *args, **kwargs):
        pass

    def remove_item(self, *args, **kwargs):
        pass

    def empty(self):
        pass

    def __str__(self):
        return "NullCart (empty)"

    def __iter__(self):
        return iter([])

    def __len__(self):
        return 0

    def save(self):
        pass

Bağlantılar

http://en.wikipedia.org/wiki/Software_design_pattern

http://www.python.org/workshops/1997-10/proceedings/savikko.html

http://sourcemaking.com/design_patterns

http://www.javacamp.org/designPattern/

http://c2.com/cgi/wiki?DesignPatterns

http://www.blackwasp.co.uk/GofPatterns.aspx

Ayrıca türkçe olarak python üzerinde design pattern’lerle ilgili Yaşar Arabacı‘nın bir yazısı bulunmakta;
http://yasararabaci.tumblr.com/post/14873752371

Sunumlar

http://www.slideshare.net/guest46da5428/application-of-…

http://www.slideshare.net/saurabh.net/design-patterns…

Python konsolunda en son evaluate edilen değere ulaşmak

Bildiğiniz üzere Python konsolu üzerinde bir expression yazdığınızda size sonucunu döndürmekte. Eğer sonuç üzerinde bir işlem yapmak isterseniz onu bir değişkene atamanız gerekir normal şartlarda. Ama bazen işe yaramayabiliyor. Örneğin httplib kütüphanesindeki getresponse metodunu bir kere çağırmak durumundasınız.

Her neyse, python konsolunda en son evulate edilen değere _ (underscore) diyerek ulaşabilmekteyiz. Örnek;

>>> from myads.adserver.models import Advertisement
>>> Advertisement.objects.get(title='Adsense')
<Advertisement: Adsense>
>>> _
<Advertisement: Adsense>
>>> _.__class__
<class 'myads.adserver.models.Advertisement'>
>>> _.__class__
<class 'django.db.models.base.ModelBase'>
>>> _.__class__
<type 'type'>

Ayrıca IPython kullanıyorsanız aşağıdaki gibi bir kullanımlar da mümkün;

In [1]: 9 * 9
Out[1]: 81
In [2]: 9 * 9 * 9
Out[2]: 729
In [3]: 9 * 9 * 9 * 9
Out[3]: 6561
In [4]: _1 # ilk output
Out[4]: 81
In [5]: _2 # ikincisi
Out[5]: 729
In [6]: _3 # felan
Out[6]: 6561
In [7]: _oh # output history
Out[7]: {1: 81, 2: 729, 3: 6561, 4: 81, 5: 729, 6: 6561}
In[8]: __ # son output'tan onceki output
Out[8]: 6561
In[9]: _i1 # ilk girilen input'un unicode hali
Out[9]: u'9 * 9\n'
In [10]: _.__class__? # son output'un class'ının dokumantasyonu
Type:           type
Base Class:     <type 'type'>    
String Form:    <type 'unicode'>  
Namespace:      Interactive
Docstring:      bla bla bla...

Blog post’unun konusu IPython’a dönüşmeden burada keseyim. 

Kolay gelsin :)