python类和元类

前段时间在B站上看到python类和元类的视频讲解,整理了视频中的代码,相信看完后对类有进一步的了解。

1.py

cmd = """
x = 1
print("exec函数执行了")
def func(self):
    pass
"""

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

"""
执行结果如下
exec函数执行了
{'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创建类的三个要素.py

# 创建类有三个要素:类名 基类 类的名称空间
# 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, )  # 执行exec后,class_dic里面就有类的变量和函数

# 类的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)  # 类的名称空间,执行exec后,class_dic里面就有类的变量和函数

# 这样创建类
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

# 定义一个元类
class Mymeta(type):
    # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    def __init__(self, class_name, class_bases, class_dic):
        print("self", self)  # 现在是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的信息会被送到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.控制类的产生过程.py

# 我们可以控制类必选有文档
class Mymeta(type):
    # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    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__实现了,实例化对象可以加括号调用了")


obj = Foo()
obj("xiaojun", age=18)
"""
('xiaojun',)
{'age': 18}
__call__实现了,实例化对象可以加括号调用了
"""

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控制类实例化产生.py

# 利用new init控制类实例化产生
class Mymeta(type):

    def __call__(self, *args, **kwargs):
        print(self)  # <class '__main__.People'> ,self是People
        print(args)  # ('name1',)
        print(kwargs)  # {'age': 12}
        # 1,先造出一个People的空对象,申请内存空间
        # __new__方法接受的参数虽然也是和__init__一样,但是__init__是在类实例创建之后调用,而__new__方式正是创建这个类实例之前调用
        obj = self.__new__(self)  # 虽然和下面同样是People,但是People没有,找到的__new__是父类的
        # 2,为该空对象初始化独有的属性
        self.__init__(obj, *args, **kwargs)
        # 3, 返回一个初始化好的对象
        obj.name2 = "haha"
        return obj


"""
类的调用,即类实例化就是元类的调用过程,可以通过元类Mymeta的__call__方法控制
1,先造出一个People的空对象
2,为该空对象初始化独有的属性
3,返回一个初始化好的对象
"""


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的调用过程,即Foo对象的产生过程
        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'}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335