python3使用元類和資料描述符實現ORM

2021-09-07 11:07:20 字數 3406 閱讀 5454

# -*- coding: utf-8 -*-

# @author : pengj # @time : 2019/1/5 16:40

# @file : myorm.py

import numbers

class field:

pass

class charfield(field):

# 資料描述符

# 好處在於可以在各方法中校驗傳入值的合理性

def __init__(self, col_name, max_length):

if col_name is none or not isinstance(col_name, str):

raise valueerror("col_name must be given as str")

if max_length is none or not isinstance(max_length, numbers.integral):

raise valueerror("max_length must be given as int")

self._col_name = col_name

self._max_length = max_length

def __get__(self, instance, owner):

# return getattr(instance, self._col_name)

return instance.fields[self._col_name]

def __set__(self, instance, value):

# 這裡如果col_name和資料描述符對應的名字一樣的話,如name=charfield(col_name="name",10)

# 用setattr(instance, self._col_name, value)即user.name=value會再次進入此__set__方法,導致無限遞迴

instance.fields[self._col_name] = value

class intfield(field):

def __init__(self, col_name, min_length, max_length):

self._col_name = col_name

self._min_length = min_length

self._max_length = max_length

def __get__(self, instance, owner):

return instance.fields[self._col_name]

def __set__(self, instance, value):

if value is none or (not isinstance(value, numbers.integral)):

raise valueerror("value must be given as int")

instance.fields[self._col_name] = value

class modelmetaclass(type):

def __new__(cls, cls_name, base_class, attrs):

if cls_name == "model":

return super().__new__(cls, cls_name, base_class, attrs)

fields = {}

for k, v in attrs.items():

if isinstance(v, field):

fields[k] = v

attrs["fields"] = fields

_meta = {}

attrs_meta = attrs.get("meta", none)

if attrs_meta is not none and isinstance(attrs_meta, type):

_meta["tb_name"] = getattr(attrs_meta, "tb_name", cls_name)

del attrs["meta"]

else:

_meta["tb_name"] = cls_name.lower()

attrs["_meta"] = _meta

return super().__new__(cls, cls_name, base_class, attrs)

class model(metaclass=modelmetaclass):

def __init__(self, **kwargs):

self.fields = {}

for k, v in kwargs.items():

setattr(self, k, v)

# def more_func(self):

# pass

class user(model):

name = charfield(col_name="name", max_length=10)

*** = charfield(col_name="***", max_length=1)

age = intfield(col_name="age", min_length=1, max_length=10)

class meta:

tb_name = "user"

class company(model):

name = charfield(col_name="name", max_length=10)

address = charfield(col_name="address", max_length=1)

# class meta:

# tb_name = "company"

if __name__ == "__main__":

user = user(name="boy1", age=5, ***="男")

user1 = user(name="girl1", age=6, ***="女")

company = company(name="com", address="china")

print(user.__dict__)

print(user.__dict__)

print(user1.__dict__)

print(company.__dict__)

print(company.__dict__)

輸出

, '_meta': , '__doc__': none}}}

, '_meta': , '__doc__': none}

}

參考:

python高階程式設計和非同步io併發程式設計

python描述符 (descriptor) 詳解-屬性查詢優先順序

python3元類 python3元類的呼叫順序

在嘗試理解元類建立類例項的順序時,我感到困惑.根據該圖 source 我鍵入以下 進行驗證.class meta type def call self print meta call super meta,self call def new mcs,name,bases,attrs,kwargs p...

Python3 元類拓展

自定義元類控制類的建立 class mymeta type def init self,class name,class bases,class dic if not class name.istitle raise typeerror 類名首字母必須大寫 if doc not in class d...

Python3 元類程式設計

在python中一切接物件,類也是乙個物件,所有的類都是有type類建立,我們實際開發中最常用的type方法,是用來獲取某個物件的型別的,例如type 1 int type str str。但是type還有一種用法,就是用來建立類的。1 通過type動態建立無父類 無屬性的類people type ...