python-元类1

参考文档

note_t

参考代码

preview/demo_metaclass 

使用

demo_type.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# @Time : 2019/5/27 15:41 
# @Author : donghuan 
# @File : demo1_type.py 
# @Software: PyCharm


# step1:
Test2 = type("Test2", (), {})  # 定了一个Test2类
print(Test2)  # <class '__main__.Test2'>

# step2: 使用type创建带有属性的类
Foo = type('Foo', (), {'bar': True})
print(Foo)
print(Foo.bar)

# 并且可以将Foo当成一个普通的类一样使用:
f = Foo()
print(f)
print(f.bar)
# 等价于
# class Foo(object):
#     bar = True


# 当然,你可以继承这个类,代码如下:
FooChild = type('FooChild', (Foo,), {})
print(FooChild)
print(FooChild.bar)  # bar属性是由Foo继承而来


# 注意:
# type的第2个参数,元组中是父类的名字,而不是字符串
# 添加的属性是类属性,并不是实例属性


# step3: 使用type创建带有方法的类
class A(object):
    num = 100

# 就是这样的,不是在class A中
def print_b(self):
    print(self.num)


@staticmethod
def print_static():
    print("----haha-----")


@classmethod
def print_class(cls):
    print(cls.num)


B = type("B", (A,), {"print_b": print_b, "print_static": print_static, "print_class": print_class})
b = B()
b.print_b()
b.print_static()
b.print_class()
print(hasattr(b, "num"))

# 结果
# 100
# ----haha-----
# 100
# true

demo_metaclass1.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2019/5/27 19:26 
# @Author : donghuan 
# @File : demo2_metaclass.py 
# @Software: PyCharm

"""
元类就是用来创建这些类(对象)的,元类就是类的类

type就是Python的内建元类

print(a.__class__.__class__)
# <type 'type'>


class Foo(Bar):
    pass
    
Python做了如下的操作:
Foo中有__metaclass__这个属性吗?如果是,Python会通过__metaclass__创建一个名字为Foo的类(对象)
如果Python没有找到__metaclass__,它会继续在Bar(父类)中寻找__metaclass__属性,并尝试做和前面同样的操作。
如果Python在任何父类中都找不到__metaclass__,它就会在模块层次中去寻找__metaclass__,并尝试做同样的操作。
如果还是找不到__metaclass__, Python就会用内置的type来创建这个类对象。


元类的主要目的就是为了当创建类时能够自动地改变类。
"""


# 遍历属性字典,把不是__开头的属性名字变为大写
def upper_attr(class_name, class_parents, class_attr):
    print("class_name:", class_name)
    print("class_parents:", class_parents)
    print("class_attr:", class_attr)
    new_attr = {}
    for name, value in class_attr.items():
        if not name.startswith("__"):
            new_attr[name.upper()] = value

    # 调用type来创建一个类
    return type(class_name, class_parents, new_attr)


class Foo(object, metaclass=upper_attr):
    bar = 'bip'

    @property
    def page_offset(self):
        return "page_offset"


print(hasattr(Foo, 'bar'))
print(hasattr(Foo, 'BAR'))

f = Foo()
print(f.BAR)
f.page_offset = 111
print(f.page_offset)

"""
但就元类本身而言,它们其实是很简单的:

1.拦截类的创建
2.修改类
3.返回修改之后的类

元类就是深度的魔法
"""

demo_metaclass2

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# @Time : 2019/5/27 19:36 
# @Author : donghuan 
# @File : demo3_metaclass2.py 
# @Software: PyCharm


class UpperAttrMetaClass(type):
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回之的方法
    # 而__init__只是用来将传入的参数初始化给对象
    # 你很少用到__new__,除非你希望能够控制对象的创建
    # 这里,创建的对象是类,我们希望能够自定义它,所以我们这里改写__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__特殊方法,但是我们这里不用
    def __new__(cls, class_name, class_parents, class_attr):
        # 遍历属性字典,把不是__开头的属性名字变为大写
        new_attr = {}
        for name, value in class_attr.items():
            if not name.startswith("__"):
                new_attr[name.upper()] = value

        # 方法1:通过'type'来做类对象的创建
        return type(class_name, class_parents, new_attr)

        # 方法2:复用type.__new__方法
        # 这就是基本的OOP编程,没什么魔法
        # return type.__new__(cls, class_name, class_parents, new_attr)


# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):
    bar = 'bip'


# python2的用法
# class Foo(object):
#     __metaclass__ = UpperAttrMetaClass
#     bar = 'bip'


print(hasattr(Foo, 'bar'))
# 输出: False
print(hasattr(Foo, 'BAR'))
# 输出:True

f = Foo()
print(f.BAR)
# 输出:'bip'

demo_metaclass_orm.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# @Time : 2019/5/27 19:37 
# @Author : donghuan 
# @File : demo4_metaclass_orm.py 
# @Software: PyCharm


class ModelMetaclass(type):
    def __new__(cls, name, bases, attrs):
        mappings = dict()
        # 判断是否需要保存
        for k, v in attrs.items():
            # 判断是否是指定的格式
            if isinstance(v, tuple):
                print('Found mapping: %s ==> %s' % (k, v))
                mappings[k] = v

        # 删除这些已经在字典中存储的属性
        for k in mappings.keys():
            attrs.pop(k)

        # 将之前的uid/name/email/password以及对应的对象引用、类名字保存
        attrs['__mappings__'] = mappings  # 保存属性和列的映射关系
        attrs['__table__'] = name         # 假设表名和类名一致
        return type.__new__(cls, name, bases, attrs)


class Model(object, metaclass=ModelMetaclass):
    def __init__(self, **kwargs):
        for name, value in kwargs.items():
            setattr(self, name, value)

    def save(self):
        fields = []
        args = []
        for k, v in self.__mappings__.items():
            fields.append(v[0])
            args.append(getattr(self, k, None))

        args_temp = list()
        for temp in args:
            # 判断入如果是数字类型
            if isinstance(temp, int):
                args_temp.append(str(temp))
            # 判断入如果是字符串类型
            elif isinstance(temp, str):
                args_temp.append("""'%s'""" % temp)
        sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))
        print('SQL: %s' % sql)


class User(Model):
    uid = ('uid', "int unsigned")
    name = ('username', "varchar(30)")
    email = ('email', "varchar(30)")
    password = ('password', "varchar(30)")


u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
# print(u.__dict__)
u.save()

demo_metaclass4.py

# pip install pyyaml

import yaml


class Monster(yaml.YAMLObject):
    yaml_tag = u'!Monster'

    def __init__(self, name, hp, ac, attacks):
        self.name = name
        self.hp = hp
        self.ac = ac
        self.attacks = attacks

    def __repr__(self):
        return "%s(name=%r, hp=%r, ac=%r, attacks=%r)" % (
            self.__class__.__name__, self.name, self.hp, self.ac, self.attacks)


print(yaml.dump(Monster(name=u'Cave lizard', hp=[3, 6], ac=16, attacks=[u'BITE', u'HURT'])))

# 输出
"""
!Monster
ac: 16
attacks: [BITE, HURT]
hp: [3, 6]
name: Cave
lizard
"""

result = yaml.load("""
--- !Monster
    name: Cave spider
    hp: [2, 6] 
    ac: 16
    attacks: [BITE, HURT]
    """, Loader=yaml.FullLoader)
print(result)


result = yaml.load("""
--- !Monster
    name: Cave spider
    hp: [2, 6]
    ac: 16
    attacks: [BITE, HURT]
    """, Loader=yaml.BaseLoader)
print(result)


# yaml源码
# Python 2/3 相同部分
# class YAMLObjectMetaclass(type):
#     def __init__(cls, name, bases, kwds):
#         super(YAMLObjectMetaclass, cls).__init__(name, bases, kwds)
#         if 'yaml_tag' in kwds and kwds['yaml_tag'] is not None:
#             cls.yaml_loader.add_constructor(cls.yaml_tag, cls.from_yaml)
#
#
# # Python 3
# class YAMLObject(metaclass=YAMLObjectMetaclass):
#     yaml_loader = Loader
#     # 省略其余定义
#
#
# # Python 2
# class YAMLObject(object):
#     __metaclass__ = YAMLObjectMetaclass
#     yaml_loader = Loader

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值