亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

Metaclass tersuai

Sekarang, kita sudah tahu apa itu metaclass. Jadi, dari awal hingga akhir, kita masih tidak tahu apa kegunaan metaclass. Baru belajar tentang metaclass. Sebelum memahami penggunaannya, mari kita fahami dahulu cara menyesuaikan metaclass. Kerana hanya dengan memahami cara menyesuaikannya, anda boleh memahami fungsinya dengan lebih baik.

Mula-mula, mari kita fahami atribut __metaclass__

metaclass, secara literal diterjemahkan sebagai metaclass, penjelasan mudahnya ialah:

Selepas kita mentakrifkan kelas, kita boleh mencipta contoh berdasarkan kelas ini, jadi: tentukan kelas dahulu, Kemudian buat contoh.

Tetapi bagaimana jika kita ingin membuat kelas? Kemudian anda mesti mencipta kelas berdasarkan metaclass, jadi: tentukan metaclass dahulu, dan kemudian buat kelas.

Sambungannya ialah: tentukan dahulu metaclass, kemudian anda boleh mencipta kelas, dan akhirnya mencipta contoh.

Jadi, metaclass membolehkan anda membuat kelas atau mengubah suai kelas. Dengan kata lain, anda boleh menganggap kelas sebagai "contoh" yang dibuat oleh metaclass.

class MyObject(object):
    __metaclass__ = something…
[…]

Jika ditulis seperti ini, Python akan menggunakan metaclass untuk mencipta kelas MyObject. Apabila anda menulis kelas MyObject(objek), objek kelas MyObject belum lagi dicipta dalam ingatan. Python akan mencari atribut __metaclass__ dalam definisi kelas Jika ia dijumpai, Python akan menggunakannya untuk mencipta kelas MyObject Jika ia tidak dijumpai, ia akan menggunakan fungsi jenis terbina dalam untuk mencipta kelas. Jika anda masih tidak memahaminya, lihat carta alir di bawah:

c7dd72cd3c802993425a3b6516a97e2.png

Contoh lain:

class Foo(Bar):
    pass

Apakah proses penghakimannya?

Tentukan dahulu sama ada Foo mempunyai atribut __metaclass__? Jika ada, Python akan mencipta objek kelas bernama Foo dalam ingatan melalui __metaclass__ (perhatikan bahawa ini adalah objek kelas). Jika Python tidak menjumpai __metaclass__, ia akan terus mencari atribut __metaclass__ dalam Bar (kelas induk) dan cuba melakukan operasi yang sama seperti sebelumnya. Jika Python tidak dapat mencari __metaclass__ dalam mana-mana kelas induk, ia mencari __metaclass__ dalam hierarki modul dan cuba melakukan perkara yang sama. Jika __metaclass__ masih tidak ditemui, Python akan menggunakan jenis terbina dalam untuk mencipta objek kelas.

Malah, __metaclass__ mentakrifkan kelakuan kelas. Sama seperti cara kelas mentakrifkan gelagat contoh, metaclass mentakrifkan gelagat kelas. Boleh dikatakan bahawa kelas adalah contoh metaclass.

Kini, pada asasnya kami memahami atribut __metaclass__, tetapi kami belum bercakap tentang cara menggunakan atribut ini, atau apakah yang boleh diletakkan dalam atribut ini?

Jawapannya ialah: anda boleh membuat kelas. Jadi apa yang boleh digunakan untuk membuat kelas? jenis, atau apa-apa sahaja yang menggunakan jenis atau jenis subkelas.

Tujuan utama metaclass adalah untuk menukar kelas secara automatik apabila ia dicipta. Biasanya, anda akan melakukan sesuatu seperti ini untuk API, di mana anda ingin mencipta kelas yang sesuai dengan konteks semasa. Bayangkan contoh bodoh di mana anda memutuskan bahawa semua atribut kelas dalam modul anda hendaklah dalam huruf besar. Terdapat beberapa cara untuk melakukan ini, tetapi salah satunya adalah dengan menetapkan __metaclass__ pada tahap modul. Menggunakan kaedah ini, semua kelas dalam modul ini akan dibuat melalui metaclass ini Kita hanya perlu memberitahu metaclass untuk menukar semua atribut kepada huruf besar dan semuanya akan baik-baik saja.

Nasib baik __metaclass__ sebenarnya boleh dipanggil sewenang-wenangnya, tak perlu kelas formal. Jadi, mari kita mulakan dengan fungsi mudah sebagai contoh.

# 元類會自動將你通常傳給‘type’的參數(shù)作為自己的參數(shù)傳入
def upper_attr(future_class_name, future_class_parents, future_class_attr):
    '''返回一個類對象,將屬性都轉(zhuǎn)為大寫形式'''
    #  選擇所有不以'__'開頭的屬性
    attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
# 將它們轉(zhuǎn)為大寫形式
uppercase_attr = dict((name.upper(), value) for name, value in attrs)
 
# 通過'type'來做類對象的創(chuàng)建
return type(future_class_name, future_class_parents, uppercase_attr)
 
__metaclass__ = upper_attr  
#  這會作用到這個模塊中的所有類
 
class Foo(object):
    # 我們也可以只在這里定義__metaclass__,這樣就只會作用于這個類中
    bar = 'bip'
print hasattr(Foo, 'bar')
# 輸出: False
print hasattr(Foo, 'BAR')
# 輸出:True
 
f = Foo()
print f.BAR
# 輸出:'bip'
用 class 當做元類的做法:
# 請記住,'type'實際上是一個類,就像'str'和'int'一樣
# 所以,你可以從type繼承
class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被調(diào)用的特殊方法
    # __new__是用來創(chuàng)建對象并返回之的方法
    # 而__init__只是用來將傳入的參數(shù)初始化給對象
    # 你很少用到__new__,除非你希望能夠控制對象的創(chuàng)建
    # 這里,創(chuàng)建的對象是類,我們希望能夠自定義它,所以我們這里改寫__new__
    # 如果你希望的話,你也可以在__init__中做些事情
    # 還有一些高級的用法會涉及到改寫__call__特殊方法,但是我們這里不用
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return type(future_class_name, future_class_parents, uppercase_attr)

Namun, pendekatan ini sebenarnya bukan OOP. Kami memanggil taip secara langsung dan kami tidak mengatasi kaedah __new__ kelas induk. Sekarang mari kita lakukan seperti ini:

class UpperAttrMetaclass(type):
    def __new__(upperattr_metaclass, future_class_name, future_class_parents, future_class_attr):
        attrs = ((name, value) for name, value in future_class_attr.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
 
        # 復用type.__new__方法
        # 這就是基本的OOP編程,沒什么魔法
        return type.__new__(upperattr_metaclass, future_class_name, future_class_parents, uppercase_attr)

Anda mungkin perasan bahawa terdapat parameter tambahan upperattr_metaclass, tiada apa yang istimewa mengenainya. Argumen pertama kepada kaedah kelas sentiasa mewakili contoh semasa, sama seperti argumen diri dalam kaedah kelas biasa. Sudah tentu, demi kejelasan, saya telah membuat nama di sini lebih panjang. Tetapi sama seperti diri, semua parameter mempunyai nama tradisional mereka. Jadi dalam kod pengeluaran sebenar metaclass akan kelihatan seperti ini:

class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')
        uppercase_attr  = dict((name.upper(), value) for name, value in attrs)
        return type.__new__(cls, name, bases, uppercase_attr)

Kita juga boleh menjadikannya lebih jelas sedikit jika kita menggunakan kaedah super, yang memudahkan pewarisan (ya, anda boleh mempunyai metaclass , mewarisi daripada metaclass, mewarisi daripada jenis)

class UpperAttrMetaclass(type):
    def __new__(cls, name, bases, dct):
        attrs = ((name, value) for name, value in dct.items() if not name.startswith('__'))
        uppercase_attr = dict((name.upper(), value) for name, value in attrs)
        return super(UpperAttrMetaclass, cls).__new__(cls, name, bases, uppercase_attr)

Biasanya kami menggunakan metaclass untuk melakukan beberapa perkara yang tidak jelas, bergantung pada introspeksi, mengawal warisan, dll. Sesungguhnya, ia amat berguna untuk menggunakan metaclass untuk melakukan beberapa "sihir gelap" dan dengan itu mencipta beberapa perkara yang rumit. Tetapi setakat metaclass itu sendiri, mereka sebenarnya sangat mudah:

Memintas penciptaan kelas

Ubah suai kelas

Kembalikan kelas yang diubah suai

Meneruskan pembelajaran