元类编程的基本使用
更新时间是在2023年02月22日, 具体的时刻是08:27:54, 作者是代码输入中...。
这篇文章主要是讲了一下元类编程是怎么用的, 里面的示例代码写得特别具体, 对大家的学东西或者是干活儿都有点参考价值, 有需要的家伙们接下来就跟着小编一块来学一学吧。
1.1.动态属性
在面向对象编程里面, 通常情况下, 我们把那些名词性质的东西映射成属性, 把那些动词性质的东西映射成方法。在他们两个对应的情况下, 分别就是self.xxx这种形式的属性以及类方法这样的情况存在。
但是, 有时候我们真正所需要的这些属性, 是需要根据其他的现有属性来进行动态计算才行的一种状态, 如果在这种情况下我们依然直接使用那种常规的属性方式来进行处理的话, 那么就很可能会引发数据不同步这样一个问题的发生。
所以下面部分的内容, 我们就专门来重点介绍一下如何用@这一个特定的符号标记的方法来实现对于动态类型的类属性的一个创建过程的相关操作环节。
from datetime import datetime,dateclass User:
def __init__(self,name,birthday):
self.name = name
self.birthday = birthday
self._age = 0
@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("derek",date(year=1994,month=11,day=11))
user.age = 23
print(user._age) # 23
print(user.age) # 24 ,动态计算出来的
1.2.和的区别
.(self, name)
当出现找不到的时候, 会执行调用的操作, 这一操作的结果会是返回一个具体的值或者是引发一种特定的异常。
.(self, name)
它是会被无条件地调用的, 并且是通过实例来访问其中的属性的。如果在这个类里面定义了某种特定的方法, 那么该方法就不会被进行调用, 但是这种情况需要排除掉显示出进行的调用, 或者是由于引发了异常所导致的情形。
(1)调用一个不存在的属性
class User:def __init__(self,info={}):
self.info = info
# def __getattr__(self, item):
# return self.info[item]
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
print(user.name)
会报错
(2)在把相应的东西添加上去了之后, 接着就可以直接开始进行调用了。
class User:def __init__(self,info={}):
self.info = info
#__getattr__是在查找不到属性的时候调用
def __getattr__(self, item):
return self.info[item]
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
print(user.name) #derek
(3)
class User:def __init__(self,info={}):
self.info = info
#__getattr__是在查找不到属性的时候调用
def __getattr__(self, item):
return self.info[item]
#__getattribute不管属性存不存在,都访问这个
def __getattribute__(self, item):
return "zhang_derek"
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
#不管属性存不存在,都走__getattribute__
print(user.name) #zhang_derek #即使属性存在也走__getattribute__
print(user.test) #zhang_derek #不存在的属性也能打印
print(user.company) #zhang_derek #不存在的属性也能打印
1.属性描述符是指用于定义对象属性特征的描述性结构。
在验证赋值的时候, 需要去确认一下当前的值是不是整数类型。
#属性描述符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")
self.value = value
def __delete__(self, instance):
pass
class User:
age = IntField()
if __name__ == '__main__':
user = User()
user.age = 24
print(user.age)
假设变量里面的年龄数值等于二十四, 这个数据的类型是整数形式, 那么在进行显示输出的时候, 不会出现任何阻碍。
如果给user.age传递字符串test, 也就是设置'test'这个参数的时候, 系统就会产生报错。
1.4.和的区别
(1)假如方法是没有任何东西返回的, 那么init方法就不会被执行。
class User:def __new__(cls, *args, **kwargs):
print("in new")
def __init__(self,name):
print("in init")
self.name = name
# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
user = User("derek")
运行结果:没有调用init方法
(2)当对象被返回的时候, 就会执行初始化方法。
class User:def __new__(cls, *args, **kwargs):
print("in new") #in new
print(cls) #cls是当前class对象
print(type(cls)) #
return super().__new__(cls) #必须返回class对象,才会调用__init__方法
def __init__(self,name):
print("in init") #in init
print(self) #self是class的实例对象 <__main__.User object at 0x00000000021B8780>
print(type(self)) #
self.name = name
# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
user = User(name="derek")
#总结
# __new__ 用来创建实例,在返回的实例上执行__init__,如果不返回实例那么__init__将不会执行
# __init__ 用来初始化实例,设置属性什么的
1.5.自定义元类
(1)在前面的准备工作环节中, 通过传入不同的字符串这个操作方法, 来达到动态地创建出不同类别的类的这样一个目的。
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
if __name__ == '__main__':
Myclass = create_class("user")
my_obj = Myclass()
print(my_obj) #user
print(type(my_obj)) #.User'>
(2)用type创建
尽管前面说到的方式是可以进行创建的, 但是实际操作起来非常地繁琐且复杂。紧接着下面会给出使用 type 来创建类的简单实例。
# 一个简单type创建类的例子#type(object_or_name, bases, dict)
#type里面有三个参数,第一个类名,第二个基类名,第三个是属性
User = type("User",(),{"name":"derek"})
my_obj = User()
print(my_obj.name) #derek
(3)不但可以进行属性的定义工作, 而且还能够实现对方法的界定设定。
def say(self): #必须加selfreturn "i am derek"
User = type("User",(),{"name":"derek","say":say})
my_obj = User()
print(my_obj.name) #derek
print(my_obj.say()) #i am derek
(4)通过使用 type 这种方式去创建一个新的类, 然后让这个新创建的类去继承于那一个已经存在的基类。
def say(self): #必须加selfreturn "i am derek"
class BaseClass:
def answer(self):
return "i am baseclass"
#type里面有三个参数,第一个类名,第二个基类名,第三个是属性
User = type("User",(BaseClass,),{"name":"derek","say":say})
if __name__ == '__main__':
my_obj = User()
print(my_obj.name) # derek
print(my_obj.say()) # i am derek
print(my_obj.answer()) # i am baseclass
1.6. 什么是元类?
所谓元类, 说白了它就是专门用来创建类的一个工具, 就像我们在上文那里所举的那个例子中的type那样。
在实质的编码操作进程之中, 我们通常并不直接运用type参数去进行类的创建活动, 而是应当采用元类设计的书写策略方式,通过自行定制一款特定的元类对象来完成这一创建任务。
# 把User类创建的过程委托给元类去做,这样代码的分离性比较好class MetaClass(type):
def __new__(cls, *args, **kwargs):
return super().__new__(cls,*args, **kwargs)
class User(metaclass=MetaClass):
def __init__(self,name):
self.name = name
def __str__(self):
return "test"
if __name__ == '__main__':
#python中类的实例化过程,会首先寻找metaclass,通过metaclass去创建User类
my_obj = User(name="derek")
print(my_obj) #test
这篇关于元类编程的文章介绍到这里就结束了, 对于更多相关元类编程的内容, 请大家去搜索脚本之家以前的文章, 或者继续浏览下面的相关文章, 希望大家能够以后多多支持脚本之家。