মূল কন্টেন্টে যান
মডিউল 9 · 4-এর পাঠ 4কোর্সে 36/36~14 min
মডিউল পাঠ (4/4)

ডেকোরেটর: ফাংশন যা ফাংশন পরিবর্তন করে

একটি ডেকোরেটর একটি ফাংশন যা অন্য একটি ফাংশন নেয় এবং একটি প্রদান করে এর "সজ্জিত" সংস্করণ। এটি আচরণ যোগ করার একটি শক্তিশালী উপায় (লগিং, টাইমিং, ক্যাশিং, পুনরায় চেষ্টা, বৈধতা) এর শরীর স্পর্শ না করে মূল ফাংশন।

মান হিসাবে ফাংশন

পাইথনে, ফাংশনগুলি হল অবজেক্ট: আপনি তাদের পাস করতে পারেন, তাদের ফেরত দিতে পারেন, তাদের বরাদ্দ করতে পারেন।

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 কীওয়ার্ড আর্গুমেন্ট। তারা যাক আপনি কোন ফাংশন সঙ্গে কাজ করে যে wrappers লিখুন.

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)` মূল্যায়ন করুন।

সম্পাদক লোড হচ্ছে...
ইঙ্গিত দেখান

র‍্যাপারটি func কল করে এবং 2 দ্বারা গুণিত ফলাফল প্রদান করে।

সমাধান 3 প্রচেষ্টার পরে উপলব্ধ

ব্যায়াম পর্যালোচনা করুন

ব্যায়াম#python.m9.l4.e2
প্রচেষ্টা: 0লোড হচ্ছে...

একটি পুনরাবৃত্ত 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)`.

সম্পাদক লোড হচ্ছে...
ইঙ্গিত দেখান

র‍্যাপারটি func(*args, **kwargs) কল করে এবং ফলাফলটিকে 2 দ্বারা গুণ করে।

সমাধান 3 প্রচেষ্টার পরে উপলব্ধ