Python da decorator
Tags: python, programming, uz
Published: 2023-01-25 04:36:37

Decorator larni tushunishdan avval Python da closure funksiyalar ko'rib chiqamiz.
```python
def hello(name):
    # ichki funksiya
    def get_name():
        return f"Hello, {name}!"

    # ichki funksiyani qaytarish
    return get_name


hello_func = hello("Sarvar")
print(hello_func())  # Hello, Sarvar!
```
Closure bu ichma-ich funksiyada tashqi funksiya o'zgaruvchilarini ichki funksiyada foydalanish mumkin bo'ladi.
Quyida ikkita sonni ko'paytiradigan closure yaratamiz.
```python
def multiplier(n):
    def mul(x):
        return x * n

    return mul


# Multiplier of 3
mul_three = multiplier(3)

# Multiplier of 5
mul_five = multiplier(5)

print(mul_three(9))  # 27
print(mul_five(3))  # 15
print(mul_five(mul_three(2)))  # 30
```
Decorator yaratishimiz da ham closure orqali amalga oshiramiz.
Decorator orqali boshqa funksiyada ishlatilgan holda uning xususiyatini o'zgartirishimiz mumkin bo'ladi.
![Decorators](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/a2xn92ufdo6ahg74zjlu.jpg)
Manba: [Medium](https://miro.medium.com/max/720/1*nphtlrDbU-l1Tlfsp_nlvg.webp)

Decorator funksiya argument sifatida funksiya qabul qiladi.
```python
def make_decorator(func):
    def inner():
        # Ichki funksiya orqali func xususiyatlarini o'zgartirishimiz mumkin
        print("Dekorator ishlayapti")

        func()

    # Ichki funksiya qaytariladi
    return inner


def my_func():
    print("Dekorator uchun ishlatiladigan funksiya")


decorated_func = make_decorator(my_func)
decorated_func()

# Dekorator ishlayapti
# Dekorator uchun ishlatiladigan funksiya
```
Decorator funksiya `@` orqali ishlatiladi.
```python
@make_decorator
def my_func():
    print("Dekorator uchun ishlatiladigan funksiya")


my_func()

# Dekorator ishlayapti
# Dekorator uchun ishlatiladigan funksiya
```
Funksiyani argumentlar orqali decoratorda ishlatishni ko'rib chiqamiz.
2 ta sonni bo'ladigan `divider(a, b)` funksiya yaratamiz.
```python
def divider(a, b):
    return a / b


print(divider(10, 5))  # 2.0
print(divider(10, 0))  # ZeroDivisionError: division by zero
```
`b` o'zgaruvchiga 0 qiymat beriladigan bo'lsa `ZeroDevisionError` xatolik qaytaradi, buni oldini olish uchun decorator funksiya yaratamiz.
```python
def divide_decorator(func):
    def divide_inner(a, b):
        try:
            return func(a, b)
        except ZeroDivisionError:
            print("Nolga bo'lish mumkin emas!")

    return divide_inner


@divide_decorator
def divider(a, b):
    return a / b


print(divider(10, 5))  # 2.0
print(divider(10, 0))  # Nolga bo'lish mumkin emas!
```
Bitta funksiyada bir nechta decorator ishlatishimiz ham mumkin, bunda birinchisidan boshlab decoratorlar ishlab keladi.
```python
def divide_decorator(func):
    def divide_inner(a, b):
        try:
            return func(a, b)
        except ZeroDivisionError:
            print("Nolga bo'lish mumkin emas!")

    return divide_inner


def increment_arg_if_second_zero(func):
    def inner(a, b):
        if b == 0:
            b += 1
        return func(a, b)

    return inner


@increment_arg_if_second_zero
@divide_decorator
def divider(a, b):
    return a / b


print(divider(10, 5))  # 2.0
print(divider(10, 0))  # 10.0
``` 

Keyingi qismlarda decorator lar bo'yicha murakkab funksiyalarni ko'rib chiqamiz.