python類和元類

前段時(shí)間在B站上看到python類和元類的視頻講解徘禁,整理了視頻中的代碼诅诱,相信看完后對(duì)類有進(jìn)一步的了解。

1.py

cmd = """
x = 1
print("exec函數(shù)執(zhí)行了")
def func(self):
    pass
"""

class_dict = {}
exec(cmd, {}, class_dict)
print(class_dict)

"""
執(zhí)行結(jié)果如下
exec函數(shù)執(zhí)行了
{'x': 1, 'func': <function func at 0x000002DAC0401E18>}
"""

2.py

class People:
    country = "China"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print("%s is eating" % self.name)


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

3創(chuàng)建類的三個(gè)要素.py

# 創(chuàng)建類有三個(gè)要素:類名 基類 類的名稱空間
# People = type(類名送朱,基類娘荡,類的名稱空間)
class_name = "People"  # 類名
class_bases = (object,)  # 基類
# 類的名稱空間
class_dic = {}
class_body = """
country = "China"
def __init__(self, name, age):
    self.name = name
    self.age = age
def eat(self):
    print("%s is eating" % self.name)
"""

exec(class_body,
     {},
     class_dic, )  # 執(zhí)行exec后,class_dic里面就有類的變量和函數(shù)

# 類的3要素
print(class_name)  # 類名 People
print(class_bases)  # 基類(<class 'object'>,)
# {'country': 'China', '__init__': <function __init__ at 0x00000153DBC11E18>, 'eat': <function eat at 0x00000153DBF898C8>}
print(class_dic)  # 類的名稱空間驶沼,執(zhí)行exec后炮沐,class_dic里面就有類的變量和函數(shù)

# 這樣創(chuàng)建類
People_class = type(class_name, class_bases, class_dic)
print(People_class)  # <class '__main__.People'>

# 使用類
o_p = People_class("jjj", 12)
o_p.eat()  # jjj is eating

4.自定義類.py

# 定義一個(gè)元類
class Mymeta(type):
    # 只有繼承了type類才能稱之為一個(gè)元類,否則就是一個(gè)普通的自定義類
    def __init__(self, class_name, class_bases, class_dic):
        print("self", self)  # 現(xiàn)在是People
        print("class_name", class_name)
        print("class_bases", class_bases)
        print("class_dic", class_dic)
        # 重用父類type的功能
        super(Mymeta, self).__init__(class_name, class_bases, class_dic)


class People(object, metaclass=Mymeta):  # metaclass指定元類
    # People=Mymeta(類名商乎,基類央拖,類的名稱空間
    country = "China"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print("%s is eating" % self.name)


# People的信息會(huì)被送到Meteta元類中去:類名 基類門 類的名稱空間
p = People("kk", 22)
p.eat()
"""
self <class '__main__.People'>
class_name People
class_bases (<class 'object'>,)
class_dic {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': <function People.__init__ at 0x000001E8C9529950>, 'eat': <function People.eat at 0x000001E8C9529840>}
kk is eating
"""

5.控制類的產(chǎn)生過程.py

# 我們可以控制類必選有文檔
class Mymeta(type):
    # 只有繼承了type類才能稱之為一個(gè)元類,否則就是一個(gè)普通的自定義類
    def __init__(self, class_name, class_bases, class_dic):
        if class_dic.get("__doc__") is None or len(
                class_dic.get("__doc__").strip()) == 0:
            raise TypeError("類中必須要有文檔注釋鹉戚,并且文檔注釋不能為空")
        if not class_name.istitle():
            raise TypeError("類名首字母必須大寫")
        # 重用父類type的功能
        super(Mymeta, self).__init__(class_name, class_bases, class_dic)


try:
    class People(object, metaclass=Mymeta):
        country = "China"

        def __init__(self, name, age):
            self.name = name
            self.age = age

        def eat(self):
            print("%s is eating" % self.name)
except Exception as e:
    print(e)  # 類中必須要有文檔注釋鲜戒,并且文檔注釋不能為空

try:
    class people(object, metaclass=Mymeta):  # metaclass指定元類
        """
        # 有注釋了,但類名是小寫
        """
        country = "China"

        def __init__(self, name, age):
            self.name = name
            self.age = age

        def eat(self):
            print("%s is eating" % self.name)
except Exception as e:
    print(e)  # 類名首字母必須大寫

6__call__方法.py

class Foo:
    def __call__(self, *args, **kwargs):
        print(args)
        print(kwargs)
        print("__call__實(shí)現(xiàn)了抹凳,實(shí)例化對(duì)象可以加括號(hào)調(diào)用了")


obj = Foo()
obj("xiaojun", age=18)
"""
('xiaojun',)
{'age': 18}
__call__實(shí)現(xiàn)了遏餐,實(shí)例化對(duì)象可以加括號(hào)調(diào)用了
"""

7__new__方法.py

# __new__方法
class People:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __new__(cls, name, age):
        # 約束年齡
        if 0 < age < 150:
            # return object.__new__(cls)
            return super(People, cls).__new__(cls)
        else:
            return None


b = People("x", 10)
print(b)  # <__main__.People object at 0x000001732F7177B8>
p = People("x", 150)
print(p)  # None

8利用new init控制類實(shí)例化產(chǎn)生.py

# 利用new init控制類實(shí)例化產(chǎn)生
class Mymeta(type):

    def __call__(self, *args, **kwargs):
        print(self)  # <class '__main__.People'> ,self是People
        print(args)  # ('name1',)
        print(kwargs)  # {'age': 12}
        # 1赢底,先造出一個(gè)People的空對(duì)象失都,申請內(nèi)存空間
        # __new__方法接受的參數(shù)雖然也是和__init__一樣,但是__init__是在類實(shí)例創(chuàng)建之后調(diào)用幸冻,而__new__方式正是創(chuàng)建這個(gè)類實(shí)例之前調(diào)用
        obj = self.__new__(self)  # 雖然和下面同樣是People粹庞,但是People沒有,找到的__new__是父類的
        # 2洽损,為該空對(duì)象初始化獨(dú)有的屬性
        self.__init__(obj, *args, **kwargs)
        # 3, 返回一個(gè)初始化好的對(duì)象
        obj.name2 = "haha"
        return obj


"""
類的調(diào)用庞溜,即類實(shí)例化就是元類的調(diào)用過程,可以通過元類Mymeta的__call__方法控制
1碑定,先造出一個(gè)People的空對(duì)象
2流码,為該空對(duì)象初始化獨(dú)有的屬性
3又官,返回一個(gè)初始化好的對(duì)象
"""


class People(object, metaclass=Mymeta):
    country = "China"

    def __init__(self, name1, age):
        self.name1 = name1
        self.age = age

    def eat(self):
        print("%s is eating" % self.name1)


p = People("name1", age=12)
p.eat()  # name1 is eating
print(p.name2)  # haha

9,使用元類修改屬性為隱藏屬性.py

class Mymeta(type):

    def __init__(self, class_name, class_bases, class_dic):
        super(Mymeta, self).__init__(class_name, class_bases, class_dic)

    def __call__(self, *args, **kwargs):
        # 加上邏輯漫试,控制Foo的調(diào)用過程六敬,即Foo對(duì)象的產(chǎn)生過程
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)

        # 修改屬性為隱藏屬性
        obj.__dict__ = {
            '_%s__%s' % (self.__name__, k): v
            for k, v in obj.__dict__.items()
        }
        return obj


class Foo(object, metaclass=Mymeta):
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


obj = Foo("nick", 18, "male")
print(obj.__dict__)
# {'_Foo__name': 'nick', '_Foo__age': 18, '_Foo__sex': 'male'}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市驾荣,隨后出現(xiàn)的幾起案子外构,更是在濱河造成了極大的恐慌,老刑警劉巖播掷,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件典勇,死亡現(xiàn)場離奇詭異,居然都是意外死亡叮趴,警方通過查閱死者的電腦和手機(jī)割笙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來眯亦,“玉大人伤溉,你說我怎么就攤上這事∑蘼剩” “怎么了乱顾?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宫静。 經(jīng)常有香客問我走净,道長,這世上最難降的妖魔是什么孤里? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任伏伯,我火速辦了婚禮,結(jié)果婚禮上捌袜,老公的妹妹穿的比我還像新娘说搅。我一直安慰自己,他們只是感情好虏等,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布弄唧。 她就那樣靜靜地躺著,像睡著了一般霍衫。 火紅的嫁衣襯著肌膚如雪候引。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天敦跌,我揣著相機(jī)與錄音澄干,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛傻寂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播携兵,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼疾掰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了徐紧?” 一聲冷哼從身側(cè)響起静檬,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎并级,沒想到半個(gè)月后拂檩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘲碧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年稻励,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片愈涩。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡望抽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出履婉,到底是詐尸還是另有隱情煤篙,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布毁腿,位于F島的核電站辑奈,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏已烤。R本人自食惡果不足惜鸠窗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胯究。 院中可真熱鬧塌鸯,春花似錦、人聲如沸唐片。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽费韭。三九已至茧球,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間星持,已是汗流浹背抢埋。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人揪垄。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓穷吮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親饥努。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捡鱼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359