news 2026/9/29 15:08:38

python元类编程的基本使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
python元类编程的基本使用

元类编程的基本使用

更新时间是在2023年02月22日, 具体的时刻是08:27:54, 作者是代码输入中...。

这篇文章主要是讲了一下元类编程是怎么用的, 里面的示例代码写得特别具体, 对大家的学东西或者是干活儿都有点参考价值, 有需要的家伙们接下来就跟着小编一块来学一学吧。

1.1.动态属性

在面向对象编程里面, 通常情况下, 我们把那些名词性质的东西映射成属性, 把那些动词性质的东西映射成方法。在他们两个对应的情况下, 分别就是self.xxx这种形式的属性以及类方法这样的情况存在。

但是, 有时候我们真正所需要的这些属性, 是需要根据其他的现有属性来进行动态计算才行的一种状态, 如果在这种情况下我们依然直接使用那种常规的属性方式来进行处理的话, 那么就很可能会引发数据不同步这样一个问题的发生。

所以下面部分的内容, 我们就专门来重点介绍一下如何用@这一个特定的符号标记的方法来实现对于动态类型的类属性的一个创建过程的相关操作环节。

from datetime import datetime,date

class 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): #必须加self

return "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): #必须加self

return "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

这篇关于元类编程的文章介绍到这里就结束了, 对于更多相关元类编程的内容, 请大家去搜索脚本之家以前的文章, 或者继续浏览下面的相关文章, 希望大家能够以后多多支持脚本之家。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 15:07:24

基于STM32的智能鸽子驯养系统:从环境监测到自动饲喂的完整设计

1. 从鸽棚里的真实痛点说起&#xff1a;这套系统到底要解决什么养鸽子这件事&#xff0c;外行看是闲情逸致&#xff0c;内行才知道是个精细活。我接触过不少鸽友&#xff0c;有养信鸽参赛的&#xff0c;有做观赏鸽繁育的&#xff0c;也有规模化肉鸽养殖的。聊下来发现一个共性痛…

作者头像 李华
网站建设 2026/9/29 15:06:56

OpenHarmony上Flutter功能卡片组件实战:状态管理与平台通道

最近我一直在折腾 Flutter for OpenHarmony 这套链路&#xff0c;手里的项目是一个文件转换助手 App。整个界面没有用传统的列表页加详情页那种结构&#xff0c;而是把所有操作单元都做成了“功能卡片组件”&#xff1a;选文件是一张卡片、选转换格式是一张卡片、调参数是一张卡…

作者头像 李华
网站建设 2026/9/29 15:06:43

《AI 时代 FPGA 的全栈开发实战·从入门到精通》筑基篇|第3课时

课时导读 前两课时我们完成了两件事:建立了硬件思维(第1课时)、补齐了数字电路地基(第2课时)。本课时回答一个非常实际的问题:2026年,FPGA开发者到底有哪些AI工具可以用?它们各自擅长什么?我应该怎么选、怎么搭配? 很多学习者现在的状态是网上说什么火就用什么:刷…

作者头像 李华
网站建设 2026/9/29 15:06:21

千万级设备并发接入,FluxMQ 如何扛住海量终端连接洪峰?

千万级设备并发接入&#xff0c;FluxMQ 如何扛住海量终端连接洪峰&#xff1f;很多企业都会遇到一个共性问题&#xff1a;平台平时运行稳定&#xff0c;一旦遇到设备批量上线、网络断联回复、整点集中上报&#xff0c;就会出现延迟飙升、设备频繁掉线、系统负载爆表&#xff0c…

作者头像 李华
网站建设 2026/9/29 15:06:05

Linux如何开放SSH服务监听多个端口

Linux上默认SSH服务端口为22&#xff0c;但是通常在一些公司里面这个端口是禁用的&#xff0c;需要进行对应的修改。如果大家要开放多个端口的监听&#xff0c;可以通过如下方法进行配置。首先&#xff0c;修改sshd的配置文件 &#xff0c;默认位置为&#xff1a;/etc/ssh/sshd…

作者头像 李华