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.

1 Beğeni
1 Beğeni
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.

1 Beğeni
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.

1 Beğeni

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:

1 Beğeni

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.

1 Beğeni

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)

1 Beğeni

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())
1 Beğeni