Tutorial Material

Metadasturlash (metaprogramming)

Share to
Python metaprogramming

Metadasturlash (metaprogramming) — dastur kodni ma'lumot sifatida ko'ra oladigan yondashuv. Ya'ni dastur boshqa kodni o'qishi, yaratishi, tahlil qilishi, o'zgartirishi, hatto ish paytida o'zini ham modifikatsiya qilishi mumkin. Qisqacha: kod yozadigan kod.

Python'da bu juda chuqur va murakkab mavzu, lekin to'g'ri ishlatilsa juda kuchli. Python metadasturlashining asosiy elementlaridan biri — metaclass.

1. Class nima?

Metaclass'ni tushunishdan oldin eslab qoling: Python'da class ham obyekt. Siz class yozganingizda, Python uni bajaradi va xotirada class obyekti yaratadi.

class ObjectCreator:
    pass

my_obj = ObjectCreator()
print(my_obj) # Instance of ObjectCreator

print(ObjectCreator) # ObjectCreator itself is an object!

Class obyekt bo'lgani uchun:

2. "Sehrli" type() funksiyasi

Odatda type()ni ma'lumot turini ko'rish uchun ishlatamiz:

print(type(1)) # <class 'int'>

Lekin type() yordamida class'larni dinamik yaratish ham mumkin.

Sintaksis: type(name, bases, attrs)

# Oddiy usul
class Monkey:
    def eat(self):
        print("Eating banana")

# Metaprogramming usuli (aynan bir xil!)
def eat_function(self):
    print("Eating banana")

DynamicMonkey = type('DynamicMonkey', (), {'eat': eat_function})

m = DynamicMonkey()
m.eat() # Natija: Eating banana

3. Metaclass

Metaclass — class'larni yaratadigan "factory".

Python'da standart metaclass — type.

class MyClass:
    pass

print(type(MyClass)) # <class 'type'>

Custom metaclass yaratish

Class qanday yaratilishini nazorat qilish uchun o'zingiz metaclass yozishingiz mumkin. Bu ko'pincha class atributlarini tekshirish yoki qat'iy API yaratishda (masalan, Django modellari) ishlatiladi.

Metaclass yaratish uchun typedan meros oling. Class ta'rifida metaclass= argumentidan foydalanamiz.

Misol: barcha atribut nomlarini Uppercase qilish

class UpperAttrMeta(type):
    # __new__ __init__ dan oldin chaqiriladi
    def __new__(upperattr_metaclass, future_class_name, 
                future_class_parents, future_class_attr):
        
        # Katta harfli kalitlar bilan yangi atribut lug'ati yaratish
        uppercase_attr = {}
        for name, val in future_class_attr.items():
            if not name.startswith('__'): # Magic metodlarni o'zgartirmaymiz
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val
        
        # Class yaratish uchun type.__new__ ni chaqirish
        return type(future_class_name, future_class_parents, uppercase_attr)

# Metaclass ishlatish
class Foo(metaclass=UpperAttrMeta):
    bar = 'bip'

print(hasattr(Foo, 'bar')) # False (chunki BAR ga o'zgardi)
print(hasattr(Foo, 'BAR')) # True
print(Foo.BAR) # 'bip'

4. Dinamik atributga murojaat

Metaprogramming faqat klasslar haqida emas — atributlarni ish vaqtida nom bo'yicha o'qish va o'rnatish ham mumkin, buning uchun built-in getattr(), setattr() va hasattr() ishlatiladi:

class Config:
    pass

cfg = Config()
setattr(cfg, "debug", True)        # satr nomi bilan atribut o'rnatish

print(getattr(cfg, "debug"))       # True
print(getattr(cfg, "verbose", False))  # False  (bo'lmaganda standart qiymat)
print(hasattr(cfg, "debug"))       # True

__getattr__ hook'i atribut odatiy yo'l bilan topilmaganda chaqiriladi, bu klassga istalgan nomga dinamik javob berish imkonini beradi:

class Echo:
    def __getattr__(self, name):
        return f"You asked for '{name}'"

e = Echo()
print(e.anything)   # You asked for 'anything'
print(e.foo)        # You asked for 'foo'

5. Yengilroq muqobil: __init_subclass__

To'liq metaclass'lar kamdan-kam kerak bo'ladi. Faqat class subclass qilinganda reaksiya bildirmoqchi bo'lsangiz, __init_subclass__ ancha soddaroq:

class Plugin:
    registry = []

    def __init_subclass__(cls, **kwargs):
        super().__init_subclass__(**kwargs)
        Plugin.registry.append(cls.__name__)

class Audio(Plugin):
    pass

class Video(Plugin):
    pass

print(Plugin.registry)   # ['Audio', 'Video']

6. Metaclass qachon kerak?

Javob: deyarli hech qachon, agar freymvork (framework) qurmayotgan bo'lsangiz.

"Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't." - Tim Peters (Python Guru)

Lekin mavzuni tushunish Python qanday ishlashini chuqurroq anglashga yordam beradi.

Xulosa