python 元类编程_第七章:Python高级编程-元类编程

第七章:Python高级编程-元类编程

7.1 property动态属性

from datetime import data, datetime

class User:

def __init__(self, name, birthday):

self.name = name

self.birthday = birthday

self._age = 0

def get_age(self):

return datetime.now().year - self.birthday.year

@property

def age(self):

return datetime.now().year - self.birthday.year

@age.setter

def age(self, value):

self._age = value

if __name__ == "__main__":

user = User("bobby", date(year=1987, month=1, day=1))

print(user.get_age())

user.age = 30

print(self._age)

7.2 __getattr__、__getattribute__魔法函数

#__getattr__, __getattribute__

#__getattr__ 就是在查找不到属性的时候调用

from datetime import date

class User:

def __init__(self,info={}):

self.info = info

def __getattr__(self, item): # 查找不到属性的时候调用

return self.info[item]

# def __getattribute__(self, item): # 查找属性时调用

# return "bobby"

if __name__ == "__main__":

user = User(info={"company_name":"imooc", "name":"bobby"})

print(user.test)

7.3 属性描述符和属性查找过程

from datetime import date, datetime

import numbers

class IntField:

#数据描述符

def __get__(self, instance, owner):

return self.value

def __set__(self, instance, value):

if not isinstance(value, numbers.Integral):

raise ValueError("int value need")

if value < 0:

raise ValueError("positive value need")

self.value = value

def __delete__(self, instance):

pass

class NonDataIntField:

#非数据属性描述符

def __get__(self, instance, owner):

return self.value

class User:

age = IntField()

# age = NonDataIntField()

'''

如果user是某个类的实例,那么user.age(以及等价的getattr(user,’age’))

首先调用__getattribute__。如果类定义了__getattr__方法,

那么在__getattribute__抛出 AttributeError 的时候就会调用到__getattr__,

而对于描述符(__get__)的调用,则是发生在__getattribute__内部的。

user = User(), 那么user.age 顺序如下:

(1)如果“age”是出现在User或其基类的__dict__中, 且age是data descriptor, 那么调用其__get__方法, 否则

(2)如果“age”出现在user的__dict__中, 那么直接返回 obj.__dict__[‘age’], 否则

(3)如果“age”出现在User或其基类的__dict__中

(3.1)如果age是non-data descriptor,那么调用其__get__方法, 否则

(3.2)返回 __dict__[‘age’]

(4)如果User有__getattr__方法,调用__getattr__方法,否则

(5)抛出AttributeError

'''

# class User:

#

# def __init__(self, name, email, birthday):

# self.name = name

# self.email = email

# self.birthday = birthday

# self._age = 0

#

# # def get_age(self):

# # return datetime.now().year - self.birthday.year

#

# @property

# def age(self):

# return datetime.now().year - self.birthday.year

#

# @age.setter

# def age(self, value):

# #检查是否是字符串类型

# self._age = value

if __name__ == "__main__":

user = User()

user.__dict__["age"] = "abc"

print (user.__dict__)

print (user.age)

# print (getattr(user, 'age'))

# user = User("bobby", date(year=1987, month=1, day=1))

# user.age = 30

# print (user._age)

# print(user.age)

7.4 __new__和__init__的区别

class User:

def __new__(cls, *args, **kwargs): # args 位置参数 kwargs 有名参数

print (" in new ")

return super().__new__(cls)

def __init__(self, name):

print (" in init")

pass

a = int()

#new 是用来控制对象的生成过程, 在对象生成之前

#init是用来完善对象的

#如果new方法不返回对象, 则不会调用init函数

if __name__ == "__main__":

user = User(name="bobby")

7.5 自定义元类

#类也是对象,type创建类的类

def create_class(name):

if name == "user":

class User:

def __str__(self):

return "user"

return User

elif name == "company":

class Company:

def __str__(self):

return "company"

return Company

#type动态创建类

# User = type("User", (), {})

def say(self):

return "i am user"

# return self.name

class BaseClass():

def answer(self):

return "i am baseclass"

class MetaClass(type):

def __new__(cls, *args, **kwargs):

return super().__new__(cls, *args, **kwargs)

from collections.abc import *

#什么是元类, 元类是创建类的类 对象

class User(metaclass=MetaClass):

def __init__(self, name):

self.name = name

def __str__(self):

return "user"

#python中类的实例化过程,会首先寻找metaclass,通过metaclass去创建user类

#去创建类对象,实例

if __name__ == "__main__":

# MyClass = create_class("user")

# my_obj = MyClass()

# print(type(my_obj))

# User = type("User", (BaseClass, ), {"name":"user", "say":say})

my_obj = User(name="bobby")

print(my_obj)

7.6 自定义元类

# 需求

import numbers

class Field:

pass

class IntField(Field):

# 数据描述符

def __init__(self, db_column, min_value=None, max_value=None):

self._value = None

self.min_value = min_value

self.max_value = max_value

self.db_column = db_column

if min_value is not None:

if not isinstance(min_value, numbers.Integral):

raise ValueError("min_value must be int")

elif min_value < 0:

raise ValueError("min_value must be positive int")

if max_value is not None:

if not isinstance(max_value, numbers.Integral):

raise ValueError("max_value must be int")

elif max_value < 0:

raise ValueError("max_value must be positive int")

if min_value is not None and max_value is not None:

if min_value > max_value:

raise ValueError("min_value must be smaller than max_value")

def __get__(self, instance, owner):

return self._value

def __set__(self, instance, value):

if not isinstance(value, numbers.Integral):

raise ValueError("int value need")

if value < self.min_value or value > self.max_value:

raise ValueError("value must between min_value and max_value")

self._value = value

class CharField(Field):

def __init__(self, db_column, max_length=None):

self._value = None

self.db_column = db_column

if max_length is None:

raise ValueError("you must spcify max_lenth for charfiled")

self.max_length = max_length

def __get__(self, instance, owner):

return self._value

def __set__(self, instance, value):

if not isinstance(value, str):

raise ValueError("string value need")

if len(value) > self.max_length:

raise ValueError("value len excess len of max_length")

self._value = value

class ModelMetaClass(type):

def __new__(cls, name, bases, attrs, **kwargs):

if name == "BaseModel":

return super().__new__(cls, name, bases, attrs, **kwargs)

fields = {}

for key, value in attrs.items():

if isinstance(v alue, Field):

fields[key] = value

attrs_meta = attrs.get("Meta", None)

_meta = {}

db_table = name.lower()

if attrs_meta is not None:

table = getattr(attrs_meta, "db_table", None)

if table is not None:

db_table = table

_meta["db_table"] = db_table

attrs["_meta"] = _meta

attrs["fields"] = fields

del attrs["Meta"]

return super().__new__(cls, name, bases, attrs, **kwargs)

class BaseModel(metaclass=ModelMetaClass):

def __init__(self, *args, **kwargs):

for key, value in kwargs.items():

setattr(self, key, value)

return super().__init__()

def save(self):

fields = []

values = []

for key, value in self.fields.items():

db_column = value.db_column

if db_column is None:

db_column = key.lower()

fields.append(db_column)

value = getattr(self, key)

values.append(str(value))

sql = "insert {db_table}({fields}) value({values})".format(db_table=self._meta["db_table"],

fields=",".join(fields), values=",".join(values))

pass

class User(BaseModel):

name = CharField(db_column="name", max_length=10)

age = IntField(db_column="age", min_value=1, max_value=100)

class Meta:

db_table = "user"

if __name__ == "__main__":

user = User(name="bobby", age=28)

# user.name = "bobby"

# user.age = 28

user.save()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值