首页 > 编程语言 >python魔术方法类构建篇

python魔术方法类构建篇

时间:2023-07-15 20:46:01浏览次数:35  
标签:__ 这个 name python 魔术 构建 print class def

本篇章的很多魔术方法都是跟class的建立有关的

4,类构建篇

  • __init_subclass__
  • __set_name__
  • __class_getitem__和__mro_entries__
  • __prepare__
  • __instancecheck__和__subclasscheck__

 

__init_subclass__方法

__init_subclass__这个方法你要定义在基类里面,然后当你以这个类为基类,定义一个衍生类的时候,这个方法就会被调用,我们尝试一个简单的例子,就是打印这个class,然后这里我们以base类为基类建立衍生类A,那运行结果呢就打印出来了这个class A,这个传进去的参数cls,是你刚刚建立的衍生类

 

class Base:
    def __init_subclass__(cls):
        print(cls)


class A(Base):
    pass

 

<class '__main__.A'>

这里我们可以把这个例子稍微做复杂一点点,我们让这个衍生类里面增加一个attribute x,让它是一个空的Dictionary,我们看在我们定义了A之后,这个A.x就是一个空的Dictionary,

class Base:
    def __init_subclass__(cls):
        cls.x = {}


class A(Base):
    pass


print(A.x)
# {}

那这个方法呢还可以传参数,比如下面我们可以要求它传一个name,然后在定义衍生类的时候,我们把这个Jack作为name传进去,可以看到这个衍生类A的name attribute就被赋值了 

class Base:
    def __init_subclass__(cls, name):
        cls.x = {}
        cls.name = name


class A(Base, name="Jack"):
    pass


print(A.x)
print(A.name)
# {}
# Jack

 

__set_name__方法

__set_name__方法更多的是定义在这个descriptor class 里,即使这个class它不是一个descriptor class,它依然起作用,这个方法相当于一个hook,当你在类的定义里去构建一个这个class的instance的时候,这个方法就会被调用,执行一下下面的程序,我们看owner 是A,也就是在哪个class定义里面,去构建的这个instance,而name是它赋值的这个变量的名字。那这个方法呢,有的时候我们在做log的时候可以使用

class D:
    def __set_name__(self, owner, name):
        print(owner, name)


class A:
    x = D()
<class '__main__.A'> x

 

__class_getitem__方法

接下来的两个方法都是在强化typing的时候被引入的,第一个叫做__class_getitem__,__getitem__是这个class的object用方括号尝试access value的时候使用的魔术方法,那__class_getitem__就是这个类用方括号做 subscribe 的时候会调用的方法,下面我们写了一个简单的__class_getitem__函数,把这个item打印出来,然后返回abc,在下面我们打印一个A[0],注意这个A是class而不是class A的object,我们会发现item是0被打印出来了,然后A[0]是abc也被打印出来了

class A:
    def __class_getitem__(cls, item):
        print(item)
        return "abc"


print(A[0])
# 0
# abc

这个东西跟typing的关系,这个list[int]表示我这个type是一个由integer组成的list,我们可以把它赋值到一个变量上,然后用这个变量再给其他的list做type hint,而type hint本身就是python代码,所以这个list[int]就必然有其实现的方式,我们观察一下它就是一个class然后方括号里面方东西,那它就是用__class_getitem__实现的。

class A:
    def __class_getitem__(cls, item):
        print(item)
        return "abc"


print(A[0])
int_arr_type = list[int]
lst1: int_arr_type = []
lst2: int_arr_type = []

 

__mro_entries__方法

另外一个更晦涩一点的函数叫做__mro_entries__,我们在B做继承A的时候,更多的时候括号里面是A是一个class object,而现在我们使用的是A(),也就是class A的一个object,如果我们直接这么写的话会报错

class A:
    pass
    # def __mro_entries__(self, bases):
    #     print(bases)
    #     return ()


class B(A()):
    pass
TypeError: A() takes no arguments

这里为什么会报错呢,简单来说就是建立B的时候它寻找自己的基类出现了问题,那这个__mro_entries__呢就是帮他去找基类的,它需要返回一个tuple,就是你去哪找你的基类去,那我们加上这个方法之后,它就能运行了

class A:

    def __mro_entries__(self, bases):
        print(bases)
        return ()


class B(A()):
    pass
(<__main__.A object at 0x000001A3D34DFCD0>,)

我们在下面这种情况下这个__mro_entries__返回的是一个空的tuple,这个的意思就是说你从我这找不到任何基类,别地儿找去,正因如此,这个时候如果你去打印issubclass(B,A),你就会发现A它并不是B的基类,因为B试图官这个A的object去问 你这个object 我怎么拿到你的基类啊 它说这里没有你的基类啊 一边呆着去

class A:

    def __mro_entries__(self, bases):
        print(bases)
        return ()


class B(A()):
    pass


print(issubclass(B, A))
(<__main__.A object at 0x000002847D3CFCD0>,)
False

我们现在把这个代码稍微作点改变,现在这个__mro_entries__返回一个带A的tuple,这就相当于B问这个A的object说 你能给我什么基类啊 

然后它说就把A当成你的基类吧,这种情况下 issubclass(B,A)就是True了,因为B就会认为A是自己的基类,

class A:

    def __mro_entries__(self, bases):
        print(bases)
        return (A, )


class B(A()):
    pass


print(issubclass(B, A))
(<__main__.A object at 0x000001298760FCD0>,)
True

 

__prepare__方法

接下来看几个与metaclass相关的魔术方法,首先是这个__prepare__方法,它是用来准备你要构建的这个class的命令空间的,这里注意一下你需要手动的给这个__prepare__方法加上classmethod这个decorator,我们简单运行一下,可以看到当我们用这个metaclass Meta来构建A的时候,__prepare__方法被运行了,然后打印了A bases没有 keywords也没有

class Meta(type):
    @classmethod
    def __prepare__(cls, name, bases, **kwds):
        print(name, bases, kwds)
        return {}


class A(metaclass=Meta):
    pass
A () {}

这里我们可以在这个__prepare__函数里面,返回一个Dictionary,这个Dictionary里面是x:10,那在构建这个class A之后,A就会有x这个attribute,然后值是10

class Meta(type):
    @classmethod
    def __prepare__(cls, name, bases, **kwds):
        return {"x": 10}


class A(metaclass=Meta):
    pass


print(A.x)
# 10

 

__instancecheck__方法和__subclasscheck__方法

__instancecheck__和__subclasscheck__它们对应的函数就是isinstance跟issubclass这个两个函数,我们在做isinstance(123, A)的时候,就调用了A的元类的__instancecheck__这个函数,同样的当我们做issubclass(int, A)的时候,就调用了A的元类的__subclasscheck__函数,这个函数我们稍微写得复杂了一点点,说如果传进来的class是int的话,返回True否则返回False,可以看到由于传进来的这个type是int,所以返回了True,那这两个方法一般也是在你做metaclass的时候才需要用到的

class Meta(type):
    def __instancecheck__(self, instance):
        print("Instance Check")
        return True

    def __subclasscheck__(self, subclass):
        print("Subclass Check")
        if subclass is int:
            return True
        return False


class A(metaclass=Meta):
    pass


o = A()
print(isinstance(123, A))
print(issubclass(int, A))
Instance Check
True
Subclass Check
True

 

标签:__,这个,name,python,魔术,构建,print,class,def
From: https://www.cnblogs.com/jiushao-ing/p/17556708.html

相关文章

  • python,质谱数据,加噪声后用小波神经网络,二分类预测
    #库的导入importnumpyasnpimportpandasaspdimportmath#激活函数deftanh(x):return(np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x))#激活函数偏导数defde_tanh(x):return(1-x**2)#小波基函数defwavelet(x):return(math.cos(1.75*x))*(np.......
  • python爬虫抓取小说
    我这里是使用的requests模块和re(正则)模块可以模仿浏览器正常访问网页返回网页源码的方式,通过正则获取到小说的名字,以及每个章节名称和对应的网页链接,并将小说正文截取出来,写入到文本中,具体代码实现如下:#导入requests模块importrequests#导入re(正则)模块importre#下......
  • Python练手小项目——简易版基础SQL模板代码生成器
    1、效果图2、代码源码-ui.py:fromtkinterimport*fromtkinterimportscrolledtext,messageboxfromtkinter.ttkimportComboboximportpymysqldefinit():#创建窗口:实例化一个窗口对象window=Tk()#窗口大小window.geometry("900x550")......
  • Python 并发编程之IO模型(转载)
    Python并发编程之IO模型https://www.cnblogs.com/linhaifeng/articles/7454717.htmlIO模型介绍为了更好地了解IO模型,我们需要事先回顾下:同步、异步、阻塞、非阻塞同步(synchronous)IO和异步(asynchronous)IO,阻塞(blocking)IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别......
  • Python 潮流周刊第 11 期(2023-07-15)
    查看全文:Python潮流周刊#11:如何使用Golang运行Python代码?......
  • python打印各种文本颜色及加粗、背景色、斜体、下划线
    ----------字体颜色------------print("\033[1;30m字体颜色:白色\033[0m")print("\033[1;31m字体颜色:红色\033[0m")print("\033[1;32m字体颜色:深黄色\033[0m")print("\033[1;33m字体颜色:浅黄色\033[0m")print("\033[1;34m字体颜色:蓝色\033[0m&quo......
  • python魔术方法属性篇
    python魔术方法属性篇本篇章主要讲与对象的属性有关的魔术方法3,属性篇__getattr____getattribute____setattr____delattr____dir____get____set____delete____slots__ __getattr__方法每当我们写形如这种o.test的代码的时候,我们实际上都是在尝试access这个对象......
  • Python pygame实现中国象棋单机版源码
    今天给大家带来的是关于Python实战的相关知识,文章围绕着用Pythonpygame实现中国象棋单机游戏版展开,文中有非常详细的代码示例,需要的朋友可以参考下#-*-coding:utf-8-*-"""CreatedonSunJun1315:41:562021@author:Administrator"""importpygamefrompygame.local......
  • PHP调用Python无返回或提示No Module
    问题:自己通过命令行执行python正常,但通过php调用就没有反应。解决方法:1、首先检查一下php有没有执行权限,简单粗暴的:sudochmod777xxx.php2、Python如果有中文返回,似乎需要额外操作。可以先去掉中文排除掉其他原因,也可以尝试以下操作:在python文件头部加上importcodecssys.stdout......
  • 【性能测试】性能监控-python编写(CPU | 内存 | 磁盘io)占比监控脚本
    一、主要通过Python脚本实现对linux环境(CPU|内存|磁盘io)监控脚本示例:importtimeimportsubprocess#获取CPU使用率defget_cpu_usage():#系统CPU占比=系统态占比+空闲态占比=3.2%+36.5%=39.7%cpu_usage=subprocess.check_output("top-bn1......