وبلاگ رسانگار
با ما حرفه ای باشید

سرور مجازی NVMe

متاکلاس های پایتون و فرابرنامه نویسی

0 19
زمان لازم برای مطالعه: 8 دقیقه


تصور کنید می‌توانید برنامه‌های رایانه‌ای داشته باشید که کد شما را برای شما نوشته باشند. ممکن است، اما ماشین ها نمی نویسند همه کد شما برای شما

این تکنیک به نام فرابرنامه نویسی، در میان توسعه دهندگان چارچوب کد محبوب است. به این ترتیب تولید کد و ویژگی‌های هوشمند را در بسیاری از چارچوب‌ها و کتابخانه‌های محبوب دریافت می‌کنید Ruby روی ریل یا TensorFlow.

زبان های برنامه نویسی کاربردی مانند Elixir، Clojure و Ruby به دلیل قابلیت های فرابرنامه نویسی خود مورد توجه قرار گرفته اند. در این راهنما، ما به شما نشان می دهیم که چگونه می توانید از قدرت فرابرنامه نویسی در پایتون بهره ببرید. مثال‌های کد برای پایتون 3 نوشته شده‌اند، اما با برخی تنظیمات برای پایتون 2 کار می‌کنند.

پایتون یک زبان شی گرا است که کار با کلاس ها را آسان می کند.

متابرنامه نویسی در پایتون متکی است روی نوع جدیدی از کلاس که به نام the متاکلاس. این نوع کلاس، به طور خلاصه، دستورالعمل‌های مربوط به تولید کد پشت صحنه را دارد که می‌خواهید هنگام اجرای کد دیگری انجام شود.

ویکیپدیا متاکلاس ها را به خوبی خلاصه می کند:

در برنامه نویسی شی گرا، متاکلاس کلاسی است که نمونه های آن کلاس ها هستند

وقتی یک کلاس را تعریف می کنیم، اشیاء آن کلاس با استفاده از کلاس به عنوان طرح اولیه ایجاد می شوند.

اما خود کلاس چطور؟ نقشه خود کلاس چیست؟

اینجاست که یک متاکلاس وارد می شود. یک متاکلاس طرح اولیه خود کلاس است، درست مانند یک کلاس، طرح اولیه نمونه هایی از آن کلاس است. متاکلاس کلاسی است که ویژگی های کلاس های دیگر را تعریف می کند.

با یک متاکلاس، می توانیم ویژگی هایی را تعریف کنیم که باید به کلاس های جدیدی که در کد ما تعریف شده اند اضافه شوند.

به عنوان مثال، نمونه کد متاکلاس زیر a را اضافه می کند hello ویژگی هر کلاسی که از این متاکلاس به عنوان الگوی خود استفاده می کند. این بدان معناست که کلاس‌های جدیدی که نمونه‌هایی از این متاکلاس هستند دارای a هستند hello دارایی بدون نیاز به تعریف خود.






class HelloMeta(type):
    
    def hello(cls):
        print("greetings from %s, a HelloMeta type class" % (type(cls())))

    
    def __call__(self, *args, **kwargs):
        
        cls = type.__call__(self, *args)

        
        setattr(cls, "hello", self.hello)

        
        return cls


class TryHello(object, metaclass=HelloMeta):
    def greet(self):
        self.hello()




greeter = TryHello()
greeter.greet()

نتیجه اجرای این کد جدید است TryHello کلاس قادر است print درودی که می گوید:

greetings from <class '__main__.TryHello'>, a HelloMeta type class

متد مسئول این چاپ در اعلان کلاس اعلام نشده است. بلکه متاکلاس که هست HelloMeta در این حالت، کدی را در زمان اجرا تولید می کند که به طور خودکار متد را به کلاس اضافه می کند.

برای مشاهده عملی آن، در صورت تمایل کد را در پایتون کپی و جایگذاری کنید console. همچنین برای درک بهتر آنچه در هر قسمت از کد انجام داده ایم، نظرات را بخوانید. ما یک شی جدید به نام داریم greeter، که نمونه ای از TryHello کلاس با این حال، ما می توانیم تماس بگیریم TryHello‘s self.hello روش حتی اگر چنین روشی در آن تعریف نشده باشد TryHello اعلامیه کلاس

به جای دریافت خطا برای فراخوانی متدی که وجود ندارد، TryHello به دلیل استفاده از این روش به طور خودکار به آن اضافه می شود HelloMeta کلاس به عنوان متاکلاس آن.

متاکلاس‌ها به ما توانایی نوشتن کدی را می‌دهند که نه فقط داده‌ها، بلکه کدهای دیگر را تبدیل می‌کند، مثلاً یک کلاس را در زمانی که نمونه‌سازی می‌شود، تبدیل می‌کند. در مثال بالا، متاکلاس ما یک متد جدید را به طور خودکار به کلاس های جدید اضافه می کند که برای استفاده از متاکلاس خود به عنوان متاکلاس خود تعریف می کنیم.

این نمونه ای از فرابرنامه نویسی است. فرابرنامه‌نویسی صرفاً نوشتن کدی است که با متاکلاس‌ها و تکنیک‌های مرتبط کار می‌کند تا شکلی از تبدیل کد را در پس‌زمینه انجام دهد.

نکته زیبای فرابرنامه‌نویسی این است که به جای خروجی کد منبع، فقط اجرای آن کد را به ما باز می‌گرداند. کاربر نهایی برنامه ما از اتفاق “جادویی” در پس زمینه بی خبر است.

به چارچوب‌های نرم‌افزاری فکر کنید که در پس‌زمینه کد تولید می‌کنند تا مطمئن شوید که شما به‌عنوان یک برنامه‌نویس باید کد کمتری برای همه چیز بنویسید. در اینجا چند نمونه عالی وجود دارد:

خارج از پایتون، کتابخانه های محبوب دیگری مانند Ruby روی ریل (Ruby) و تقویت کنید(C++) نمونه‌هایی از مواردی است که متابرنامه‌نویسی توسط نویسندگان چارچوب برای تولید کد و مراقبت از چیزهای موجود در پس‌زمینه استفاده می‌شود.

نتیجه APIهای کاربر نهایی ساده شده است که کارهای زیادی را برای برنامه نویسی که در چارچوب کدنویسی می کند خودکار می کند.

مراقبت از انجام این سادگی در پشت صحنه، فرابرنامه‌نویسی زیادی است که در کد منبع فریمورک گنجانده شده است.

پیشنهاد می‌کنیم بخوانید:  چالش های کدنویسی پایتون برای توسعه دهندگان مبتدی – کد و توضیحات

برای درک روش کار متاکلاس های پایتون، باید با مفهوم انواع در پایتون خیلی راحت باشید.

یک نوع به سادگی نامگذاری داده یا شی برای یک شی در پایتون است.

پیدا کردن نوع یک شی

با استفاده از Python REPL، بیایید یک شی رشته ساده ایجاد کنیم و نوع آن را به صورت زیر بررسی کنیم:

>>> day = "Sunday"
>>> print("The type of variable day is %s" % (type(day)))
The type of variable day is <type 'str'>

همانطور که انتظار دارید، ما یک نسخه چاپی از متغیر دریافت می کنیم day از نوع است str، که از نوع رشته ای است. شما می توانید نوع هر شی را فقط با استفاده از داخلی پیدا کنید type تابع با یک آرگومان شی.

پیدا کردن نوع کلاس

بنابراین، یک رشته مانند "Sunday" یا "hello" از نوع است str، اما چه؟ str خودش؟ نوع آن چیست str کلاس؟

دوباره پایتون را تایپ کنید console:

>>> type(str)
<type 'type'>

این بار، ما یک پرینت دریافت می کنیم که str از نوع است type.

نوع و نوع نوع

اما چه در مورد type خودش؟ چیست typeنوع؟

>>> type(type)
<type 'type'>

نتیجه، یک بار دیگر، “تایپ” است. بنابراین ما آن را پیدا می کنیم type نه تنها متاکلاس طبقاتی مانند int، متاکلاس خودش هم هست!

روش های ویژه ای که توسط متاکلاس ها استفاده می شود

در این مرحله ممکن است کمی مرور نظریه کمک کند. به یاد داشته باشید که متاکلاس کلاسی است که نمونه های آن خود کلاس هستند و نه فقط اشیاء ساده.

در پایتون 3 می‌توانید با عبور از Masterclass مورد نظر به تعریف کلاس جدید، یک متاکلاس به ایجاد یک کلاس جدید اختصاص دهید.

این type type به عنوان متاکلاس پیش‌فرض در پایتون، روش‌های خاصی را تعریف می‌کند که متاکلاس‌های جدید می‌توانند برای پیاده‌سازی رفتار تولید کد منحصربه‌فرد، آنها را لغو کنند. در اینجا مروری کوتاه بر این روش های “جادویی” موجود است روی یک متاکلاس:

  • __new__: این روش نامیده می شود روی متاکلاس قبل از یک نمونه از کلاس مبتنی بر روی متاکلاس ایجاد می شود
  • __init__: این متد برای تنظیم مقادیر پس از ایجاد instance/object فراخوانی می شود
  • __prepare__: فضای نام کلاس را در یک نقشه برداری که ویژگی ها را ذخیره می کند، تعریف می کند
  • __call__: این متد زمانی فراخوانی می شود که از سازنده کلاس جدید برای ایجاد یک شی استفاده شود

این‌ها روش‌هایی هستند که باید در متاکلاس سفارشی خود را نادیده بگیرید تا رفتار کلاس‌های شما متفاوت از رفتار کلاس‌های شما باشد type، که متاکلاس پیش فرض است.

بیایید قبل از استفاده از تمرین فرابرنامه‌نویسی متاکلاس یک قدم به عقب برگردیم. یکی از کاربردهای رایج فرابرنامه نویسی در پایتون، استفاده از دکوراتورها است.

دکوراتور تابعی است که اجرای یک تابع را تغییر می دهد. به عبارت دیگر، تابعی را به عنوان ورودی می گیرد و تابع دیگری را برمی گرداند.

به عنوان مثال، در اینجا یک دکوراتور وجود دارد که هر عملکردی را انجام می دهد، و نام تابع را قبل از اجرای عملکرد اصلی به طور معمول چاپ می کند. این می تواند برای ثبت تماس های تابع مفید باشد، به عنوان مثال:



from functools import wraps


def notifyfunc(fn):
    """prints out the function name before executing it"""
    @wraps(fn)
    def composite(*args, **kwargs):
        print("Executing '%s'" % fn.__name__)
        
        rt = fn(*args, **kwargs)
        return rt
    
    return composite


@notifyfunc
def multiply(a, b):
    product = a * b
    return product

شما می توانید کد را کپی و در یک Python REPL جایگذاری کنید. نکته تمیز در مورد استفاده از دکوراتور این است که تابع ترکیبی به جای تابع ورودی اجرا می شود. نتیجه کد بالا این است که تابع ضرب قبل از اجرای محاسبات خود را در حال اجرا اعلام می کند:

>>> multiply(5, 6)
Executing 'multiply'
30
>>>
>>> multiply(89, 5)
Executing 'multiply'
445

به طور خلاصه، دکوراتورها به همان رفتار تبدیل کد متاکلاس ها دست می یابند، اما بسیار ساده تر هستند. شما می خواهید از دکوراتورها در جایی که نیاز به اعمال فرابرنامه نویسی رایج در اطراف کد خود دارید استفاده کنید. به عنوان مثال، می توانید یک دکوراتور بنویسید که همه تماس های پایگاه داده را ثبت کند.

متاکلاس ها می توانند ویژگی های کلاس ها را جایگزین یا تغییر دهند. آنها قدرت دارند hook قبل از ایجاد یک شی جدید یا بعد از ایجاد شی جدید. نتیجه انعطاف پذیری بیشتر در مورد آنچه می توانید از آنها استفاده کنید است.

در زیر، ما یک متاکلاس ایجاد می کنیم که به همان نتیجه دکوراتور از مثال قبلی می رسد.

برای مقایسه این دو، باید هر دو مثال را در کنار هم اجرا کنید و سپس کد منبع مشروح شده را دنبال کنید. توجه داشته باشید که اگر REPL شما قالب بندی کد را حفظ می کند، می توانید کد را کپی کرده و مستقیماً در REPL خود جایگذاری کنید.


import types



def notify(fn, *args, **kwargs):

    def fncomposite(*args, **kwargs):
        
        print("running %s" % fn.__name__)
        rt = fn(*args, **kwargs)
        return rt
    
    return fncomposite



class Notifies(type):

    def __new__(cls, name, bases, attr):
        
        
        
        for name, value in attr.items():
            if type(value) is types.FunctionType or type(value) is types.MethodType:
                attr(name) = notify(value)

        return super(Notifies, cls).__new__(cls, name, bases, attr)


class Math(metaclass=Notifies):
    def multiply(a, b):
        product = a * b
        print(product)
        return product

Math.multiply(5, 6)





class Shouter(metaclass=Notifies):
    def intro(self):
        print("I shout!")

s = Shouter()
s.intro()



کلاس هایی که از ما استفاده می کنند Notifies به عنوان مثال متاکلاس Shouter و Math، در زمان ایجاد، روش‌های آن‌ها با نسخه‌های پیشرفته جایگزین می‌شوند که ابتدا از طریق a به ما اطلاع می‌دهند print بیانیه نام روشی که اکنون در حال اجرا است. این مشابه رفتاری است که ما قبل از استفاده از یک عملکرد تزئینی اجرا کردیم.

پیشنهاد می‌کنیم بخوانید:  آخرین N عنصر را از List/Array دریافت کنید

موارد استفاده رایج برای فرابرنامه‌نویسی شامل کنترل نمونه‌های کلاس است.

مثلا، تک قلوها در بسیاری از کتابخانه های کد استفاده می شود. یک کلاس singleton ایجاد نمونه را کنترل می کند به طوری که حداکثر یک نمونه از کلاس در برنامه وجود دارد.

کلاس نهایی نمونه دیگری از کنترل استفاده از کلاس است. با کلاس نهایی، کلاس اجازه ایجاد زیر کلاس‌ها را نمی‌دهد. کلاس‌های نهایی در برخی از چارچوب‌ها برای امنیت استفاده می‌شوند و اطمینان می‌دهند که کلاس ویژگی‌های اصلی خود را حفظ می‌کند.

در زیر، پیاده‌سازی یک کلاس نهایی را با استفاده از یک متاکلاس ارائه می‌کنیم تا کلاس را از ارث بردن کلاس توسط دیگری محدود کنیم.




class Final(type):
    def __new__(cls, name, bases, attr):
        
        
        
        type_arr = (type(x) for x in bases)
        for i in type_arr:
            if i is Final:
                raise RuntimeError("You cannot subclass a Final class")
        return super(Final, cls).__new__(cls, name, bases, attr)




class Cop(metaclass=Final):
    def exit():
        print("Exiting...")
        quit()


class FakeCop(Cop):
    def scam():
        print("This is a hold up!")

cop1 = Cop()
fakecop1 = FakeCop()


class Goat(metaclass=Final):
    location = "Goatland"


class BillyGoat(Goat):
    location = "Billyland"

در کد، ما اعلان‌های کلاس را برای تلاش برای زیر کلاس a قرار داده‌ایم Final کلاس این اعلامیه ها شکست می خورند، و در نتیجه استثناهایی ایجاد می شود. استفاده از یک متاکلاس که کلاس های فرعی آن را محدود می کند، ما را قادر می سازد تا کلاس های نهایی را در پایگاه کد خود پیاده سازی کنیم.

پروفایلرها برای بررسی میزان استفاده از منابع در یک سیستم محاسباتی استفاده می شود. یک نمایه ساز می تواند مواردی مانند میزان استفاده از حافظه، سرعت پردازش و سایر معیارهای فنی را ردیابی کند.

ما می توانیم از متاکلاس برای پیگیری زمان اجرای کد استفاده کنیم. مثال کد ما یک نمایه ساز کامل نیست، بلکه اثباتی بر مفهوم این است که چگونه می توانید فرابرنامه نویسی را برای عملکردهای پروفایلر انجام دهید.


import types


import time

class Timer:
    def __init__(self, func=time.perf_counter):
        self.elapsed = 0.0
        self._func = func
        self._start = None

    def start(self):
        if self._start is not None:
            raise RuntimeError('Already started')
        self._start = self._func()

    def stop(self):
        if self._start is None:
            raise RuntimeError('Not started')
        end = self._func()
        self.elapsed += end - self._start
        self._start = None

    def reset(self):
        self.elapsed = 0.0

    @property
    def running(self):
        return self._start is not None

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, *args):
        self.stop()









def timefunc(fn, *args, **kwargs):

    def fncomposite(*args, **kwargs):
        timer = Timer()
        timer.start()
        rt = fn(*args, **kwargs)
        timer.stop()
        print("Executing %s took %s seconds." % (fn.__name__, timer.elapsed))
        return rt
    
    return fncomposite



class Timed(type):

    def __new__(cls, name, bases, attr):
        
        
        
        for name, value in attr.items():
            if type(value) is types.FunctionType or type(value) is types.MethodType:
                attr(name) = timefunc(value)

        return super(Timed, cls).__new__(cls, name, bases, attr)





class Math(metaclass=Timed):

    def multiply(a, b):
        product = a * b
        print(product)
        return product

Math.multiply(5, 6)


class Shouter(metaclass=Timed):

    def intro(self):
        print("I shout!")

s = Shouter()
s.intro()


def divide(a, b):
    result = a / b
    print(result)
    return result

div = timefunc(divide)
div(9, 3)

همانطور که می بینید، ما توانستیم یک را ایجاد کنیم Timed متاکلاسی که کلاس های خود را بازنویسی می کند روی-پرواز. هر زمان که یک کلاس جدید که از Timed متاکلاس اعلام شده است، متدهای آن بازنویسی می شوند تا توسط کلاس ابزار تایمر ما زمان بندی شوند. هر زمان که محاسبات را با استفاده از a اجرا می کنیم Timed کلاس، زمان‌بندی را به‌طور خودکار برای خودمان انجام می‌دهیم، بدون نیاز به انجام کار اضافی.

اگر در حال نوشتن کدها و ابزارهایی هستید که توسط توسعه دهندگان دیگر مانند فریمورک های وب یا دیباگرها استفاده می شود، متابرنامه یک ابزار عالی است. با تولید کد و فرابرنامه‌نویسی، می‌توانید زندگی را برای برنامه‌نویسانی که از کتابخانه‌های کد شما استفاده می‌کنند، آسان کنید.

متاکلاس ها و فرابرنامه نویسی قدرت زیادی دارند. نکته منفی این است که فرابرنامه‌نویسی می‌تواند نسبتاً پیچیده شود. در بسیاری از موارد، استفاده از دکوراتورها راه ساده تری را برای دستیابی به یک راه حل زیبا فراهم می کند. زمانی باید از متاکلاس ها استفاده کرد که شرایط به جای سادگی، عمومیت را طلب می کند.

برای استفاده موثر از متاکلاس ها پیشنهاد می کنیم خواندن در مقام رسمی متاکلاس های پایتون 3 مستندات.

(برچسب‌ها به ترجمه)# python



منتشر شده در 1403-01-28 07:39:04

امتیاز شما به این مطلب
دیدگاه شما در خصوص مطلب چیست ؟

آدرس ایمیل شما منتشر نخواهد شد.

لطفا دیدگاه خود را با احترام به دیدگاه های دیگران و با توجه به محتوای مطلب درج کنید