مرکزی مواد پر جائیں
ماڈیول 9 · سبق 4 از 4کورس میں 36/36~14 min
ماڈیول اسباق (4/4)

ڈیکوریٹر: فنکشنز جو فنکشنز کو تبدیل کرتے ہیں۔

A ڈیکوریٹر ایک فنکشن ہے جو ایک اور فنکشن لیتا ہے اور a واپس کرتا ہے۔ اس کا "سجا ہوا" ورژن۔ یہ رویے کو شامل کرنے کا ایک طاقتور طریقہ ہے۔ (لاگنگ، ٹائمنگ، کیشنگ، دوبارہ کوشش، توثیق) کے باڈی کو چھوئے بغیر اصل فنکشن.

اقدار کے طور پر کام کرتا ہے۔

Python میں، فنکشنز آبجیکٹ ہیں: آپ انہیں پاس کر سکتے ہیں، انہیں واپس کر سکتے ہیں، انہیں تفویض کر سکتے ہیں۔

Python
def saluta():
    print("ciao")

f = saluta   # NIENTE parentesi: assegno la funzione
f()          # 'ciao'

ایک کم سے کم ڈیکوریٹر

Python
def log(func):
    def wrapper(*args, **kwargs):
        print(f"chiamo {func.__name__}")
        risultato = func(*args, **kwargs)
        print(f"ho finito {func.__name__}")
        return risultato
    return wrapper

def somma(a, b):
    return a + b

somma = log(somma)   # ora somma è "wrapper"
somma(2, 3)
# chiamo somma
# ho finito somma
# 5

@decorator نحو

اسائنمنٹ somma = log(somma) کو @ کے ساتھ زیادہ خوبصورتی سے لکھا گیا ہے:

Python
@log
def somma(a, b):
    return a + b

یہ بالکل وہی چیز ہے۔ @log اوپر کی تعریف اس کے مساوی ہے: "جیسے ہی اس فنکشن کی وضاحت ہو جائے، اسے log(function) سے بدل دیں۔"

*args, **kwargs: کوئی بھی دستخط قبول کریں۔

Python
def wrapper(*args, **kwargs):
    return func(*args, **kwargs)

*args پوزیشن کے دلائل جمع کرتا ہے، **kwargs کلیدی الفاظ کے دلائل۔ انہوں نے اجازت دی۔ آپ ریپر لکھتے ہیں جو کسی بھی فنکشن کے ساتھ کام کرتے ہیں۔

functools.wraps: میٹا ڈیٹا کو محفوظ کریں۔

wraps کے بغیر، سجا ہوا فنکشن __name__، __doc__، اشارے کھو دیتا ہے:

Python
from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        ...
        return func(*args, **kwargs)
    return wrapper

مثال: @timeit

Python
from functools import wraps
import time

def timeit(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        t0 = time.perf_counter()
        risultato = func(*args, **kwargs)
        dt = time.perf_counter() - t0
        print(f"{func.__name__} ha impiegato {dt*1000:.2f} ms")
        return risultato
    return wrapper

@timeit
def somma_grande():
    return sum(range(10**6))

somma_grande()

stdlib سے ڈیکوریٹر

Python
from functools import lru_cache

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

fib(100)  # istantaneo grazie alla cache
  • @lru_cache — خالص فنکشن کے نتائج کو یاد کرتا ہے۔
  • @property — ایک طریقہ کو بطور وصف ظاہر کرتا ہے (OOP ماڈیول میں دیکھا گیا ہے)۔
  • @staticmethod, @classmethod — تبدیل کریں کہ self کو کیسے منتقل کیا جاتا ہے۔

دلائل کے ساتھ سجانے والے

سجانے والے بھی دلائل قبول کر سکتے ہیں۔ اس کو نافذ کرنے کے لیے، آپ کو نیسٹڈ فنکشنز کی تین سطحیں لکھنی ہوں گی: سب سے باہر کا فنکشن ڈیکوریٹر کے آرگومنٹس وصول کرتا ہے، درمیانی فنکشن ڈیکوریٹڈ فنکشن وصول کرتا ہے، اور سب سے اندرونی فنکشن (wrapper) کالز کے دوران ڈیکوریٹڈ فنکشن کو بھیجے گئے اصل دلائل وصول کرتا ہے۔

خود ہی آزمائیں۔

ورزش#python.m9.l4.e1
کوششیں: 0لوڈ ہو رہا ہے…

ایک ڈیکوریٹر `ڈبل_رزلٹ` لکھیں جو ڈیکوریٹڈ فنکشن کو کال کرے اور اس کا نتیجہ واپس کرے * 2۔ اسے ایک فنکشن `f(x)` پر لاگو کریں جو x + 1 لوٹائے۔ `f(10)` کا اندازہ کریں۔

ایڈیٹر لوڈ ہو رہا ہے…
اشارہ دکھائیں۔

ریپر فنک کو کال کرتا ہے اور 2 سے ضرب دے کر نتیجہ لوٹاتا ہے۔

3 کوششوں کے بعد حل دستیاب ہے۔

ورزش کا جائزہ لیں۔

ورزش#python.m9.l4.e2
کوششیں: 0لوڈ ہو رہا ہے…

recursive fib(n) فنکشن کو تیز کرنے کے لیے functools.lru_cache استعمال کریں۔ fib(30) کی گنتی کریں اور `r` کو تفویض کریں۔ `r` کا اندازہ لگائیں۔

ایڈیٹر لوڈ ہو رہا ہے…
اشارہ دکھائیں۔

@lru_cache(maxsize=None) def کے اوپر۔

3 کوششوں کے بعد حل دستیاب ہے۔

اضافی چیلنج

ورزش#python.m9.l4.e3
کوششیں: 0لوڈ ہو رہا ہے…

Define a decorator `double_result` that doubles (multiplies by 2) the return value of the decorated function. Apply the decorator to the function `def sum_nums(a, b): return a + b`. Finally, evaluate `sum_nums(3, 4)`.

ایڈیٹر لوڈ ہو رہا ہے…
اشارہ دکھائیں۔

ریپر فنک (*args، **kwargs) کو کال کرتا ہے اور نتیجہ کو 2 سے ضرب دیتا ہے۔

3 کوششوں کے بعد حل دستیاب ہے۔