python3のメタクラスとORM

元类

メソッドのexec

  • EXEC()メソッドは、コードブロックのPythonの文字列の形式で行ってもよいです
  • 使用exec(object, global=None, local=None)
    • オブジェクト:文字列型Pythonのコードブロック
    • グローバル:グローバル名前空間を表し、それは、コードのブロックは、グローバル名前空間で実行していることを示して辞書には、デフォルトなし、パラメータの受け渡しによって、である必要があります
    • ローカル:それは、コードのブロックは、ローカル空間で実行することを示しているとして、代表のローカルネームスペース、任意のマッピングすることができ、デフォルトはなし、パラメータの受け渡しです
code = '''
x = 0
sum = x + y + z
print(sum)
'''
y = 1
z = 2

global_dict = {'y': 2, 'z': 3}

local_dict = {'y': 3, 'z': 4}

exec(code)
'''
y = 1
z = 2
x = 0
sum = x + y + z
print(sum)
'''

exec(code, global_dict)
'''
相当于
y = 2
z = 3
x = 0
sum = x + y + z
print(sum)
'''

exec(code, global_dict, local_dict)
'''
相当于
y = 2
z = 3
def exec_func():
    y = 3
    z = 4
    x = 0
    sum = x + y + z
    print(sum)
    
exec_func()
'''

'''
3
5
7
'''

型メタクラス

  • それ自体オブジェクトクラスであり、オブジェクトはメタクラス得メタクラスによってインスタンス化されるクラスのクラスであります
  • デフォルトでは、Pythonのメタクラスのタイプである、あなたはまた、コントロールクラスの作成を達成するために元のクラスをカスタマイズすることができます
  • 型メタクラスによってクラスを作成するには MyClass = type(class_name, class_bases, class_dict)
    • CLASS_NAMEクラス名
    • 先祖の形で渡して、親クラスをclass_bases
    • 辞書の形で(名前空間のクラスを)渡すプロパティのclass_dictクラス、
# 用type元类来创建一个Chinese类
def __init__(self, name, gender, age):
    self.name = name
    self.gender = gender
    self.age = age

class_name = 'Chinese'
class_bases = (object,)
class_dict = {'country': 'China', '__init__': __init__}

Chinese = type(class_name, class_bases, class_dict)

c1 = Chinese('bigb', 'male', 18)

print(c1.name)  # bigb
print(c1.country)   # China

カスタムメタクラス

カスタムコントロールクラスのメタクラスを作成します。

  • 私たちは、カスタムのメタクラスプロセス制御クラスの作成を達成するためにすることができます
  • メタクラスは、の種類定義されており、カバータイプから継承しなければなりません__init__方法
'''
通过自定义元类来实现:
1. 类名首字母必须大写
2. 类中必须有文档注释

'''

class MyMeta(type):

    def __init__(self, class_name, class_bases, class_dict):
        print(class_name)  # chinese
        print(class_bases) # (<class 'object'>,)
        print(class_dict)  # {'__module__': '__main__', '__qualname__': 'chinese', 'country': 'China', '__init__': <function chinese.__init__ at 0x0000000009FBFD90>, 'kongfu': <function chinese.kongfu at 0x0000000009FBFE18>}

        # 类名首字母必须大写
        if not class_name.istitle():
            raise TypeError('类的首字母必须大写!')

        # 类中必须有注释
        if not class_dict.get('__doc__'):
            raise TypeError('类中必须有文档注释!')

        # 调用type中的__init__方法初始化对象
        super().__init__(class_name, class_bases, class_dict)


class chinese(object, metaclass=MyMeta):  # foo = MyMeta('foo', (object, ) {...})
    country = 'China'

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

    def kongfu(self):
        print('降龙十八掌!')
        
'''
    raise TypeError('类的首字母必须大写!')
TypeError: 类的首字母必须大写!
'''


# 将类名大写, 再运行
class Chinese(object, metaclass=MyMeta):  # foo = MyMeta('foo', (object, ) {...})
    country = 'China'

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

    def kongfu(self):
        print('降龙十八掌!')
        
        
'''
    raise TypeError('类中必须有文档注释!')
TypeError: 类中必须有文档注释!
'''

カスタムコントロールクラスのメタクラスを呼び出します

  • あなたはクラスオブジェクトを呼び出すと、オブジェクトが間にトリガされ__call__た方法
  • クラス自体も対象なので、呼び出し元のクラスは、オブジェクトをインスタンス化するために、彼らは、トリガーの中でメタクラスます__call__方法
class MyMeta(type):
    def __call__(self, *args, **kwargs):
        # 产生一个空对象
        obj = self.__new__(self)  # self是类对象

        # 初始化空对象
        self.__init__(obj, *args, **kwargs)

        # 返回初始化好的对象
        return obj


class Chinese(object, metaclass=MyMeta):  # foo = MyMeta('foo', (object, ) {...})
    country = 'China'

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

    def kongfu(self):
        print('降龙十八掌!')


# 这里调用了类对象Chinese, 因此会触发Chinese的类(元类)中的__call__方法
c1 = Chinese('bigb', 'male', 18)

print(c1.name)

'''
1. __call__中的__new__生成了一个空对象
2. __call__中的__init__初始化这个空对象
3. __call__返回了这个对象,并赋值给了c1
'''
  • 今、私たちは変更することで、これに基づいてでき__call__たクラスを制御するために、呼び出しプロセス・ロジックを
# 通过元类让Chinese类实例化出来的对象的属性变为私有属性
class MyMeta(type):
    def __call__(self, *args, **kwargs):
        # 产生一个空对象
        obj = self.__new__(self)  # self是类对象

        # 初始化空对象
        self.__init__(obj, *args, **kwargs)
        
        # 将对象的属性变成私有属性(对象._类__属性名)
        obj.__dict__ = {f'_{self.__name__}__{k}': v for k, v in obj.__dict__.items()}
        
        # 返回初始化好的对象
        return obj


class Chinese(object, metaclass=MyMeta):  # foo = MyMeta('foo', (object, ) {...})
    country = 'China'

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

    def kongfu(self):
        print('降龙十八掌!')


# 这里调用了类对象Chinese, 因此会触发Chinese的类(元类)中的__call__方法
c1 = Chinese('bigb', 'male', 18)

print(c1._Chinese__name)  # bigb

  • オブジェクトリレーショナルマッピングオブジェクトリレーショナルマッピング
    • 表--->クラス
    • フィールド---> [プロパティ]
    • 録音--->オブジェクト
# 定义字段类
class Field:
    def __init__(self, name, column_type, primary_key, default):
        self.name = name
        self.column_type = column_type
        self.primary_key = primary_key
        self.default = default


# 定义整数字段类
class IntegerField(Field):
    def __init__(self, name, column_type='int', primary_key=False, default=0):
        super().__init__(name, column_type, primary_key, default)


# 定义字符字段类
class StringField(Field):
    def __init__(self, name, column_type='varchar(64)', primary_key=False, default=None):
        super().__init__(name, column_type, primary_key, default)


# 定义元类
class OrmMetaClass(type):
    def __new__(cls, class_name, class_bases, class_dict):
        print(class_name)
        print(class_dict)

        # Models类中什么都不做, 将类原路返回
        if class_name == 'Models':
            return type.__new__(cls, class_name, class_bases, class_dict)

        # 获取表名, 如果没有,则将类名当做表名
        table_name = class_dict.get('table_name', class_name)

        # 主键名标记
        primary_key = None

        # 定义一个空字典, 用来存放字段对象
        mappings = {}

        for key, value in class_dict.items():
            # 过滤字段对象以外的属性
            if isinstance(value, Field):
                mappings[key] = value

                # 判断该字段对象中的primary key是否为True
                if value.primary_key:
                    # 判断主键是否已经存在
                    if primary_key:
                        raise TypeError('只能有一个主键!')

                    # 若主键不存在, 则给primary key赋值
                    primary_key = value.name

        # 删除mappings与类名称空间中重复的属性, 节省空间
        for key in mappings.keys():
            class_dict.pop(key)

        if not primary_key:
            raise TypeError('必须有一个主键!')

        # 给类的名称空间添加表名
        class_dict['table_name'] = table_name
        # 给类的名称空间添加主键名
        class_dict['primary_key'] = primary_key
        # 给类的名称空间中添加mappings字典, 字典中拥有所有字段属性
        class_dict['mappings'] = mappings

        return type.__new__(cls, class_name, class_bases, class_dict)


class Models(dict, metaclass=OrmMetaClass):
    # 让表对象(字典)可以通过 对象.属性的方式获取值
    def __getattr__(self, item):
        return self.get(item)

    # 让表对象(字典)可以通过 对象.属性 = 值 的方式进行赋值
    def __setattr__(self, key, value):
        self[key] = value


# 定义用户表类
class User(Models):
    user_id = IntegerField(name='user_id', primary_key=True)
    user_name = StringField(name='name')
    pwd = StringField(name='pwd')

おすすめ

転載: www.cnblogs.com/bigb/p/11796023.html