Decorators ve @ ne işe yarar?

import math
import time

def calculate_time(func):
	def inner(*args, **kwargs):
		start = time.time()
		time.sleep(1)
		func(*args, **kwargs)
		finish = time.time()
		print("Fonksiyon", func.__name__, str(finish - start), "saniye sürdü.")
	return inner

@calculate_time
def usalma(a, b):
	print(math.pow(a,b))

@calculate_time
def faktoriyel(num):
	print(math.factorial(num))

usalma(4, 9)
faktoriyel(7)
  1. Burada @calculate_timein açılımı nedir?
  2. decorators’un kullanım amacını anladım gibi ama tam olarak nedir?

burada calculate_time decorator’ı kullanılan methodun bitiş zamanını hesaplıyor
calculate_time methodu tanımlanıyor, altına inner methodu tanımlanıyor inner methodda başlangıç zamanı start değişkenine atanıyor, 1 saniye bekliyor, fonksiyonu çağırıyor (usalma, faktoriyel methodlarında kullanılmış ama başka herhangi bir methodda da kullanılabilir), daha sonra bitiş zamanını printliyor.

import math
import time

def calculate_time(func):
	def inner(*args, **kwargs):
		start = time.time()
		time.sleep(1)
		finish = time.time()
		print("Fonksiyon", func, str(finish - start), "saniye sürdü.")
	return inner()

def usalma(a, b):
	print(math.pow(a,b))
	return usalma.__name__

def faktoriyel(num):
	print(math.factorial(num))
	return faktoriyel.__name__

deneme = calculate_time(faktoriyel(3))
usalma_deneme = calculate_time(usalma(5, 2))

usalma
deneme

Yukanıda attığım kodun alternatifi bu mudur? Yoksa daha mantıklı bir yolu var mı?

Su sekilde calismali:

usalma_decorated = calculate_time(usalma)
faktoriyel_decorated = calculate_time(faktoriyel)

Bu yanlis, inner’i cagirmayip dondurmemiz lazim. inner’in func’u cagirmasi lazim; ilk ornek dogruydu.

def stopwatch(function, request = None):
    def inner(request):
        print(15, request)
        start = datetime.now()
        stop = datetime.now()
        timedown = (stop - start)
        if request == 0:
            return start
        elif request == 1:
            return stop
        else:
            return timedown.microseconds
    return inner

def text():
    print("BC1428")
i = stopwatch(text)
print(i)

Hocam öyle yapınca da inner’e girmiyor.

def stopwatch(function, request):
    def inner():
        start = datetime.now()
        stop = datetime.now()
        timedown = (stop - start)
        if request == 0:
            return start
        elif request == 1:
            return stop
        elif request == 100:
            return [start, stop, timedown.microseconds]
        else:
            return timedown.microseconds
    return inner


def text():
    print("BC1428")
used = stopwatch(text, 100)
print(used())

Sanırım oldu, bunda bir eksiklik, yanlışlık var mı hocam?

i’yi cagirmiyorsun.

Bu cok karisik:
function kullanilmiyor?
request parametresi niye stopwatch’a ait?
start ile stop ayni deger?

En yukaridaki (sorudaki) en dogrusu hala.

Hocam bu daha doğru oldu sanırım

def stopwatch(function):

    def inner(request=None):
        start = datetime.now()
        function()
        stop = datetime.now()
        timedown = (stop - start)
        if request == 0:
            return start
        elif request == 1:
            return stop
        elif request == 100:
            return [start, stop, timedown.seconds]
        else:
            return timedown.microseconds

    return inner


def text():
    return print("BC1428")

k = stopwatch(text)
print(k(100))

Tamamı burada hocam

Evet :wink: olmus! :+1:

Aa bi dakka.

request function’a gidecek zannediyordum. stopwatch'tan alinacak bilginin karakteristigi, degil mi?

O zaman stopwatch'ta olmasi dogruydu, kafam karismis, benim hatam.

inner'in butun olayi function'i taklit etmek cunku. Dekoratoru ozel bir fonksiyon icin yaziyor ve yazma amacimiz bu fonksiyonun parametreleriyle oynamak degilse, inner hemen her zaman (*args, **kwargs) olacak ve function'i her zaman (*args, **kwargs) ile cagiracak. (Butun argumanlari alip oldugu gibi function'a paslamak icin. Hata varsa da function versin…)

Hatta inner'in function'i daha iyi taklit edebilmesi icin bir fonksiyon var: inner yerine (functools.wraps(function))(inner) dondurunce help(k) filan yazildiginda inner yerine function'in dokumentasyonu cikiyor, dekorator tamamen transparan oluyor.

(wraps aslinda dekorator ama konu recurse etmesin diye boyle yazdim)

Yani hocam attığım örneklerin ilki ve sonuncusu doğrudur. Diğerlerinde de request uygundur ama yapı olarak functionu çağırmadığım için yanlıştır. Doğru mu anladım :slight_smile:

Su soru cevaplanmamis ama cevabinin “evet” oldugunu varsayarsak, sondan ikincinin function’i cagirani.

import functools
import datetime

def stopwatch(function, request):
    @functools.wraps(function)
    def inner(*args, **kwargs):
        start = datetime.datetime.now()
        function(*args, **kwargs)
        stop = datetime.datetime.now()
        timedown = (stop - start)
        if request == 0:
            return start
        elif request == 1:
            return stop
        elif request == 100:
            return [start, stop, timedown.microseconds]
        else:
            return timedown.microseconds
    return inner

def text():
    print("BC1428")
used = stopwatch(text, 100)
help(used)
print(used())

veya

import functools
import datetime

def stopwatch(request):
	def outer(function):
		@functools.wraps(function)
		def inner(*args, **kwargs):
			start = datetime.datetime.now()
			function(*args, **kwargs)
			stop = datetime.datetime.now()
			timedown = (stop - start)
			if request == 0:
				return start
			elif request == 1:
				return stop
			elif request == 100:
				return [start, stop, timedown.microseconds]
			else:
				return timedown.microseconds
		return inner
	return outer

@stopwatch(100)
def text():
    print("BC1428")

help(text)
print(text())