Ana içeriğe atla

Python Dekoratörleri Nasıl Kullanılır (Fonksiyon ve Sınıf Tabanlı Örneklerle)

Uygulamalı örneklerle Python dekoratörlerini öğrenin. Kapanımları, fonksiyon ve sınıf tabanlı dekoratörleri anlayın ve yeniden kullanılabilir, zarif kod yazın.
Güncel 16 Nis 2026  · 11 dk. oku

Dekoratörler, Python’da fonksiyonların ve metotların kodunu değiştirmeden davranışlarını değiştirmenize veya genişletmenize olanak tanıyan güçlü ve zarif bir özelliktir.

Dekoratör, mevcut bir nesneye yapısını değiştirmeden yeni işlevler eklemeye olanak tanıyan bir Python tasarım kalıbıdır. Genellikle fonksiyonlara uygulanırlar ve fonksiyonların davranışını zenginleştirmede veya değiştirmede kritik bir rol oynarlar. Geleneksel olarak, dekoratörler süslemek istediğiniz fonksiyonun tanımının önüne yerleştirilir. Bu eğitimde, dekoratörleri Python fonksiyonlarında nasıl etkili bir şekilde kullanacağınızı göstereceğiz.

Özet

  • Dekoratörler, orijinal kodu değiştirmeden fonksiyon davranışını değiştirmenizi veya genişletmenizi sağlar
  • Dekoratörleri temiz bir şekilde uygulamak için @decorator_name sözdizimini kullanın
  • Dekoratör yazarken fonksiyon meta verilerini korumak için her zaman functools.wraps kullanın
  • Sınıf tabanlı dekoratörler, fonksiyon çağrıları arasında durum tutabilen davranışlar sağlar
  • Yaygın kullanım alanları arasında önbellekleme (@lru_cache), günlük kaydı, kimlik doğrulama ve girdi doğrulama bulunur

Birinci Sınıf Nesneler Olarak Fonksiyonlar

Python’daki fonksiyonlar birinci sınıf vatandaşlardır. Bu, argüman olarak geçirilebilme, bir fonksiyondan döndürülebilme, değiştirilebilme ve bir değişkene atanabilme gibi işlemleri destekledikleri anlamına gelir. Bu özellik, fonksiyonların Python’da diğer nesneler gibi ele alınmasına olanak tanıdığı için programlamada daha fazla esneklik sağlar.

Bu dersteki tüm örnek kodları hızlıca kendiniz çalıştırmak için Python’un önceden kurulu olduğu ve tüm kod örneklerini içeren bir DataLab çalışma kitabını ücretsiz oluşturabilirsiniz. Dekoratörler üzerine daha fazla pratik için bu uygulamalı DataCamp alıştırmasına göz atın.

Fonksiyonları değişkenlere atamak

Başlangıç olarak, her çağrıldığında bir sayıya bir ekleyecek bir fonksiyon yazalım. Daha sonra bu fonksiyonu bir değişkene atayacak ve fonksiyonu bu değişken üzerinden çağıracağız.

def plus_one(number):
    return number + 1

add_one = plus_one
add_one(5)
6

Fonksiyonların içinde başka fonksiyonlar tanımlamak 

Fonksiyonların içinde başka fonksiyonlar tanımlamak Python’da güçlü bir özelliktir—ve dekoratörler inşa etmek için gereklidir. Bir diğer temel fikre bakalım: fonksiyonları argüman olarak geçirmek. Bu, bizi dekoratör yazmaya bir adım daha yaklaştıracak.

def plus_one(number):
    def add_one(number):
        return number + 1


    result = add_one(number)
    return result
plus_one(4)
5

Fonksiyonları diğer fonksiyonlara argüman olarak geçirmek

Fonksiyonlar, diğer fonksiyonlara parametre olarak da geçirilebilir. Aşağıda bunu örneklendirelim.

def plus_one(number):
    return number + 1

def function_call(function):
    number_to_add = 5
    return function(number_to_add)

function_call(plus_one)
6

Diğer fonksiyonları döndüren fonksiyonlar

Bir fonksiyon, başka bir fonksiyon da üretebilir. Bunu aşağıda bir örnekle göstereceğiz.

def hello_function():
    def say_hi():
        return "Hi"
    return say_hi
hello = hello_function()
hello()
'Hi'

İç Fonksiyonlar ve Kapanımlar

Python, iç içe fonksiyonların kapsayan fonksiyonun dış kapsamına erişmesine izin verir. Bu, dekoratörlerde kapanım (closure) olarak bilinen kritik bir kavramdır.

Python’da kapanım, oluşturulduğu ortamı—o ortam artık etkin olmasa bile—hatırlayan bir fonksiyondur. Bu, bir iç fonksiyonun kapsayıcı kapsamındaki değişkenleri “üzerine kapatabileceği” ve kullanmaya devam edebileceği anlamına gelir.

Dekoratörleri anlamak için kapanımlar esastır; çünkü dekoratörler, içteki sarmalayıcı fonksiyonun kapsayıcı dekoratör fonksiyonunun durumuna erişebilmesine ve bunu değiştirebilmesine dayanır.

Bir kapanım örneği:

def outer_function(message):
    def inner_function():
        print(f"Message from closure: {message}")
    return inner_function

closure_function = outer_function("Hello, closures!")
closure_function()
# Output: Message from closure: Hello, closures!

Bu örnekte:

  • inner_function, kapsayan kapsamındaki bir değişken olan message’a eriştiği için bir kapanımdır (outer_function).
  • outer_function çalışmasını tamamlamış olsa bile, inner_function message’a erişimini sürdürür.

Bir dekoratör oluşturduğunuzda, sarmalayıcı fonksiyon (dekoratörün içindeki) bir kapanımdır. Süslenen fonksiyona ve dekoratör fonksiyonunda tanımlanan ek duruma veya argümanlara erişimini korur. Örneğin:

def simple_decorator(func):
    def wrapper():
        print("Before the function call")
        func()
        print("After the function call")
    return wrapper

@simple_decorator
def greet():
    print("Hello!")

greet()
# Output:
# Before the function call
# Hello!
# After the function call

Burada, wrapper bir kapanımdır; greet fonksiyonunu “hatırlar” ve çalıştırılmasından önce ve sonra davranış ekler.

İlk Dekoratörünüzü Oluşturma

Artık kapanımları—bir fonksiyonun kapsayan kapsamdan değişkenleri hatırlama yeteneğini—anladığınıza göre, ilk gerçek dekoratörümüzü oluşturmaya hazırız. Dekoratörlerin perde arkasında çalışmasını sağlayan sihirli unsur kapanımlardır.

Şimdi bir cümleyi büyük harfe dönüştürecek basit bir dekoratör oluşturalım. Bunu, kapalı bir fonksiyonun içinde bir sarmalayıcı tanımlayarak yaparız. Gördüğünüz gibi, daha önce oluşturduğumuz “fonksiyon içinde fonksiyon” yapısına oldukça benzer.

def uppercase_decorator(function):
    def wrapper():
        func = function()
        make_uppercase = func.upper()
        return make_uppercase

    return wrapper

Dekoratörümüz bir fonksiyonu argüman olarak aldığı için, yeni bir fonksiyon tanımlayıp bunu dekoratöre geçireceğiz. Daha önce bir fonksiyonu bir değişkene atayabileceğimizi öğrenmiştik. Bu numarayı dekoratör fonksiyonumuzu çağırmak için kullanacağız.

def say_hi():
    return 'hello there'

decorate = uppercase_decorator(say_hi)
decorate()
'HELLO THERE'

@ sözdizimini kullanmak

Ancak Python, dekoratörleri uygulamamız için çok daha kolay bir yol sağlar. Süslemek istediğimiz fonksiyonun başına @ sembolünü koymamız yeterlidir. Bunu aşağıda pratikte gösterelim.

@uppercase_decorator
def say_hi():
    return 'hello there'

say_hi()
'HELLO THERE'

Bir Fonksiyona Birden Fazla Dekoratör Uygulamak

Tek bir dekoratör için @ sözdizimini kullanmaya alıştıktan sonra, işi bir adım ileri götürüp aynı fonksiyon üzerinde birden fazla dekoratörü istifleyebilirsiniz. Yalnız unutmayın: sıra önemlidir! 

Aşağıda, cümleyi bir listeye bölen başka bir dekoratör tanımlayacağız. Ardından uppercase_decorator ve split_string dekoratörlerini tek bir fonksiyona uygulayacağız.

import functools
def split_string(function):
    @functools.wraps(function)
    def wrapper():
        func = function()
        splitted_string = func.split()
        return splitted_string

    return wrapper 
@split_string
@uppercase_decorator
def say_hi():
    return 'hello there'
say_hi()
['HELLO', 'THERE']

Yukarıdaki çıktıda, dekoratörlerin alttan üste doğru uygulandığını görüyoruz. Sırayı değiştirsek bir hata görürdük; çünkü listelerin upper niteliği yoktur. Cümle önce büyük harfe çevrilmiş, sonra bir listeye bölünmüştür.

Not: Dekoratörleri istiflerken, orijinal fonksiyonun meta verilerinin istifleme boyunca korunmasını sağlamak için functools.wraps kullanmak yaygın bir uygulamadır. Bu, dekoratif fonksiyonun özelliklerini hata ayıklarken anlamayı ve tutarlılığı korumayı kolaylaştırır.

Dekoratörlerde Argüman Kabul Etmek

Şu ana kadar yalnızca bir fonksiyonu saran dekoratörler gördük. Peki ya dekoratörün kendisini yapılandırmak—örneğin parametre geçirmek—isterseniz? İşte burada dekoratör üreticileri (factory) devreye girer.

def decorator_with_arguments(function):
    def wrapper_accepting_arguments(arg1, arg2):
        print("My arguments are: {0}, {1}".format(arg1,arg2))
        function(arg1, arg2)
    return wrapper_accepting_arguments


@decorator_with_arguments
def cities(city_one, city_two):
    print("Cities I love are {0} and {1}".format(city_one, city_two))

cities("Nairobi", "Accra")

My arguments are: Nairobi, Accra Cities I love are Nairobi and Accra

Not: Dekoratördeki argüman sayısının (bu örnekte
arg1, arg2) sarılan fonksiyondaki argüman sayısıyla (bu örnekte cities) eşleştiğinden emin olmak önemlidir. Bu uyum, hataları önlemek ve argümanlı dekoratörlerde doğru çalışmayı sağlamak için kritik öneme sahiptir.

*args ve **kwargs ile Genel Amaçlı Dekoratörler

Herhangi bir fonksiyona uygulanabilecek genel amaçlı bir dekoratör tanımlamak için *args ve **kwargs kullanırız. *args ve **kwargs, tüm konumsal ve anahtar kelime argümanlarını toplayıp sırasıyla *args ve **kwargs değişkenlerinde saklar. Bu sayede fonksiyon çağrılarında istediğimiz kadar argüman geçebiliriz.

def a_decorator_passing_arbitrary_arguments(function_to_decorate):
    def a_wrapper_accepting_arbitrary_arguments(*args,**kwargs):
        print('The positional arguments are', args)
        print('The keyword arguments are', kwargs)
        function_to_decorate(*args)
    return a_wrapper_accepting_arbitrary_arguments

@a_decorator_passing_arbitrary_arguments
def function_with_no_argument():
    print("No arguments here.")

function_with_no_argument()
The positional arguments are ()
The keyword arguments are {}
No arguments here.

Dekoratörü konumsal argümanlarla nasıl kullanacağımızı görelim.

@a_decorator_passing_arbitrary_arguments
def function_with_arguments(a, b, c):
    print(a, b, c)

function_with_arguments(1,2,3)
The positional arguments are (1, 2, 3)
The keyword arguments are {}
1 2 3

Bir dekore edilmiş fonksiyona anahtar kelime argümanlarını şöyle geçebilirsiniz:

@a_decorator_passing_arbitrary_arguments
def function_with_keyword_arguments():
    print("This has shown keyword arguments")

function_with_keyword_arguments(first_name="Derrick", last_name="Mwiti")
The positional arguments are ()
The keyword arguments are {'first_name': 'Derrick', 'last_name': 'Mwiti'}
This has shown keyword arguments

Not: Dekoratörde **kwargs kullanımı, anahtar kelime argümanlarının işlenmesine olanak tanır. Bu da genel amaçlı dekoratörü esnek kılar ve fonksiyon çağrıları sırasında çeşitli argüman türlerini karşılayabilmesini sağlar.

Argümanları Dekoratörlere Geçirmek

Şimdi de argümanları doğrudan dekoratörün kendisine nasıl geçeceğimizi görelim. Bunu başarmak için, argüman kabul eden bir dekoratör üreticisi tanımlar, ardından onun içinde bir dekoratör tanımlarız. Daha önce olduğu gibi dekoratörün içinde de bir sarmalayıcı fonksiyon tanımlarız.

def decorator_maker_with_arguments(decorator_arg1, decorator_arg2, decorator_arg3):
    def decorator(func):
        def wrapper(function_arg1, function_arg2, function_arg3) :
            "This is the wrapper function"
            print("The wrapper can access all the variables\n"
                  "\t- from the decorator maker: {0} {1} {2}\n"
                  "\t- from the function call: {3} {4} {5}\n"
                  "and pass them to the decorated function"
                  .format(decorator_arg1, decorator_arg2,decorator_arg3,
                          function_arg1, function_arg2,function_arg3))
            return func(function_arg1, function_arg2,function_arg3)

        return wrapper

    return decorator

pandas = "Pandas"
@decorator_maker_with_arguments(pandas, "Numpy","Scikit-learn")
def decorated_function_with_arguments(function_arg1, function_arg2,function_arg3):
    print("This is the decorated function and it only knows about its arguments: {0}"
           " {1}" " {2}".format(function_arg1, function_arg2,function_arg3))

decorated_function_with_arguments(pandas, "Science", "Tools")
The wrapper can access all the variables
    - from the decorator maker: Pandas Numpy Scikit-learn
    - from the function call: Pandas Science Tools
and pass them to the decorated function
This is the decorated function, and it only knows about its arguments: Pandas Science Tools

Dekoratörleri Hata Ayıklama

Gördüğümüz gibi dekoratörler fonksiyonları sarar. Orijinal fonksiyon adı, docstring’i ve parametre listesi sarmalayıcı kapanım tarafından gizlenir: Örneğin decorated_function_with_arguments meta verilerine erişmeye çalıştığımızda, sarmalayıcının meta verilerini görürüz. Bu durum, hata ayıklamayı zorlaştırır.

decorated_function_with_arguments.__name__
'wrapper'
decorated_function_with_arguments.__doc__
'This is the wrapper function'

Bu sorunu çözmek için Python functools.wraps adlı bir dekoratör sağlar. Bu dekoratör, süslenmemiş fonksiyondaki kaybolan meta verileri dekore edilmiş kapanıma kopyalar. Bunu nasıl yapacağımızı gösterelim.

import functools

def uppercase_decorator(func):
    @functools.wraps(func)
    def wrapper():
        return func().upper()
    return wrapper
@uppercase_decorator
def say_hi():
    "This will say hi"
    return 'hello there'

say_hi()
'HELLO THERE'

Artık say_hi’nin meta verilerini kontrol ettiğimizde, sarmalayıcıyı değil, orijinal fonksiyonu doğru şekilde yansıttığını görürüz.

say_hi.__name__
'say_hi'
say_hi.__doc__
'This will say hi'

Dekoratör tanımlarken her zaman functools.wraps kullanmak tavsiye edilir ve iyi bir uygulamadır. Hata ayıklamada sizi birçok baş ağrısından kurtarır.

Sınıf Tabanlı Dekoratörler

Fonksiyon tabanlı dekoratörler yaygın olsa da, Python sınıf tabanlı dekoratörler oluşturmanıza da izin verir; bu da özellikle karmaşık kullanım senaryolarında daha fazla esneklik ve sürdürülebilirlik sağlar. Python’da nesne yönelimli programlamaya yeniyseniz, temellere göz atmak bu bölümü daha iyi anlamanıza yardımcı olacaktır. Sınıf tabanlı bir dekoratör, bir fonksiyon gibi davranmasını sağlayan bir __call__ metoduna sahip bir sınıftır.

class UppercaseDecorator:
    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        result = self.function(*args, **kwargs)
        return result.upper()

@UppercaseDecorator
def greet():
    return "hello there"

print(greet())
# Output: HELLO THERE

Nasıl çalışır:

  1. __init__ metodu, dekore edilecek fonksiyonla dekoratörü başlatır.
  2. __call__ metodu, dekore edilmiş fonksiyon çağrıldığında devreye girer ve dekoratörün davranışı değiştirmesine olanak tanır.

Sınıf tabanlı dekoratörlerin avantajları:

  • Durum tutan dekoratörler: Sınıf tabanlı dekoratörler, örnek değişkenlerini kullanarak durum tutabilir; fonksiyon tabanlı dekoratörlerde ise bu, kapanımlar veya global değişkenler gerektirir.
  • Okunabilirlik: Karmaşık dekoratörler için mantığı bir sınıf içinde kapsüllemek kodu daha düzenli ve anlaşılır kılabilir.

Durum tutan bir dekoratör örneği:

class CallCounter:
    def __init__(self, function):
        self.function = function
        self.count = 0

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"Function {self.function.__name__} has been called {self.count} times.")
        return self.function(*args, **kwargs)

@CallCounter
def say_hello():
    print("Hello!")

say_hello()
say_hello()
# Output:
# Function say_hello has been called 1 times.
# Hello!
# Function say_hello has been called 2 times.
# Hello!

Gerçek Dünya Dekoratör Kullanımı: Önbellekleme

lru_cache dekoratörü, Python’da maliyetli fonksiyon çağrılarının sonuçlarını önbelleğe alan yerleşik bir araçtır. Bu, tekrarlanan girdiler için gereksiz hesaplamalardan kaçınarak performansı artırır.

Örnek:

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n - 1) + fibonacci(n - 2)

print(fibonacci(50))  # Subsequent calls with the same argument are much faster

Dekoratörlerin diğer yaygın kullanımları:

  • Günlük kaydı: Hata ayıklama veya denetim için fonksiyon çağrılarını, argümanları ve dönüş değerlerini izleyin.

  • Kimlik doğrulama: Flask veya Django gibi web uygulamalarında erişim kontrolü uygulayın.

  • Çalışma süresi ölçümü: Performans kritik görevlerde fonksiyon çalışma süresini ölçün ve optimize edin.

  • Yeniden deneme mekanizması: Özellikle ağ işlemlerinde başarısız fonksiyon çağrılarını otomatik olarak yeniden deneyin.

  • Girdi doğrulama: Çalıştırmadan önce fonksiyon argümanlarını doğrulayın.

Python Dekoratörleri Özeti

Dekoratörler, bir fonksiyonun, metodun veya sınıfın işlevselliğini, alt sınıfları doğrudan kullanmak veya süslenen fonksiyonun kaynak kodunu değiştirmek zorunda kalmadan dinamik olarak değiştirir. Python’da dekoratör kullanmak, kodunuzu TEKRAR ETMEYİN (DRY) ilkesine de uygun hale getirir. Dekoratörlerin aşağıdakiler gibi çeşitli kullanım alanları vardır:

  • Flask ve Django gibi Python çatılarında yetkilendirme
  • Günlük kaydı
  • Çalışma süresini ölçme
  • Eşzamanlama

Python dekoratörleri hakkında daha fazla bilgi için Python’un Decorator Library sayfasına göz atın.

FAQs

Dekoratör kullanırken herhangi bir performans hususu var mı?

Evet, dekoratörler ek fonksiyon çağrıları getirdikleri için ek yük oluşturabilir. Performansın kritik olduğu durumlarda, özellikle de dekore edilen fonksiyon sıkça ve performansa duyarlı bir bağlamda çağrılıyorsa, bu ek yükü dikkate almak önemlidir.

Dekoratörler sınıf metotlarıyla da kullanılabilir mi, nasıl?

Evet, dekoratörler sınıf metotlarına da tıpkı normal fonksiyonlar gibi uygulanabilir. Dekoratör, argüman olarak metodu alır ve yeni bir metot veya değiştirilmiş bir sürümünü döndürür. Bu, sıklıkla günlük kaydı, erişim kontrolü veya önkoşulların zorlanması için kullanılır.

Dekoratörler günlükleme amaçları için nasıl kullanılabilir?

Dekoratörler, fonksiyon yürütmesini; çağrıları, argümanları ve dönüş değerlerini bir günlükleme sistemine kaydeden kodla sarmalayarak izlemek için kullanılabilir. Bu, izleme ve hata ayıklamaya yardımcı olur.

Dekoratörlerde @ sembolünün önemi nedir?

Python’daki @ sembolü, bir dekoratörü bir fonksiyona uygulamayı kolaylaştıran sözdizimsel şekerlemedir. Dekoratörü doğrudan fonksiyon tanımının üzerine yazarak kodu daha temiz ve okunabilir hale getirir.

Bir dekoratör bir fonksiyonun dönüş değerini değiştirebilir mi, bu nasıl çalışır?

Evet, bir dekoratör, sarmalayıcı fonksiyonun dönüş ifadesini değiştirerek bir fonksiyonun dönüş değerini değiştirebilir. Örneğin, çıktı veri tipini dönüştürebilir, biçimlendirebilir veya nihai sonucu döndürmeden önce ek işlem yapabilir.

İç içe bir fonksiyon kapsayan fonksiyonun değişkenine eriştiğinde Python değişken kapsamını nasıl ele alır?

Python LEGB (Local, Enclosing, Global, Built-in) kapsam kuralını kullanır. İç içe fonksiyonlar söz konusu olduğunda, içteki fonksiyon kapsayan fonksiyonun kapsamındaki değişkenlere erişebilir; bu da, dıştaki fonksiyon çalışmasını tamamladıktan sonra bile iç fonksiyonun bu değişkenlere erişimini sürdürdüğü kapanımlara olanak tanır.

Kapanım ile dekoratör arasındaki fark nedir?

Kapanım, dış kapsamındaki değişkenleri hatırlayan bir fonksiyondur. Dekoratör ise diğer fonksiyonları sarmak veya geliştirmek için kapanımları kullanan bir fonksiyondur.

functools.wraps’ı ne zaman kullanmalıyım?

Dekoratör yazarken her zaman functools.wraps kullanın. Bu, orijinal fonksiyonun meta verilerini (ad ve docstring gibi) korur; bu da hata ayıklama ve dokümantasyon için faydalıdır.

Dekoratörler argüman kabul edebilir mi?

Evet! Dekoratörleri başka bir fonksiyonla (dekoratör üreticisi) sarmalayarak onlara argüman geçebilirsiniz. Bu, dekoratör davranışını özelleştirmenize olanak tanır.

Sınıf tabanlı dekoratörlerin avantajı nedir?

Sınıf tabanlı dekoratörler, fonksiyon çağrıları arasında durum tutmanıza ve daha karmaşık mantığı nesne yönelimli bir şekilde düzenlemenize olanak tanır.

Dekoratörler yalnızca fonksiyonlar için midir?

Hayır. Dekoratörleri sınıflar ve metotlar üzerinde de kullanabilirsiniz. Flask ve Django gibi çatıların yönlendirmeleri, görünümleri ve modelleri üzerinde yaygın olarak kullanılırlar.

Konular

Python hakkında daha fazla bilgi edinin

Kurs

Python'da Fonksiyonlara Giriş

3 sa
464.1K
Python'da kendi fonksiyonlarınızı yazma sanatının yanı sıra kapsam belirleme ve hata işleme gibi temel kavramları öğrenin.
Ayrıntıları GörRight Arrow
Kursa Başla
Devamını GörRight Arrow