介绍

__set_name__ 方法是 Python 3.6 中引入的一种特殊方法,它可以在类属性被赋值时自动调用。这个方法可以用来处理类属性的名称绑定问题,例如将类属性与其所在的类进行绑定。

具体来说,当一个类定义了一个描述符(descriptor)并将其作为类属性时,Python 将在该类定义完成后自动调用描述符的 __set_name__ 方法,并将该类属性的名称作为参数传递给该方法。这样,我们就可以在 __set_name__ 方法中访问该类属性的名称,并将其与描述符进行绑定。

示例

class Descriptor:
def __set_name__(self, owner, name):
print(f"Descriptor.__set_name__(owner={owner}, name={name})") def __get__(self, instance, owner):
print(f"Descriptor.__get__(instance={instance}, owner={owner})")
return instance.__dict__.get(self.name) def __set__(self, instance, value):
print(f"Descriptor.__set__(instance={instance}, value={value})")
instance.__dict__[self.name] = value class MyClass:
my_attr = Descriptor()

代码分析

在这个示例中,我们定义了一个名为 Descriptor 的类,它实现了描述符协议(即包含 __get__、__set__ 和 __delete__ 方法)。然后,我们定义了一个名为 MyClass 的类,并将 Descriptor 实例作为其类属性 my_attr 的值。

当 Python 解释器执行到 MyClass 类定义结束时,它会自动调用 Descriptor.__set_name__() 方法,并将 MyClass 类和属性名 my_attr 作为参数传递给该方法。在本例中,我们只是简单地打印了一条消息来演示 __set_name__ 方法的调用时机。

接下来,当我们创建 MyClass 实例并访问其 my_attr 属性时,Python 将自动调用描述符的 __get__ 和 __set__ 方法,并分别输出相应的消息以演示这些方法的调用时机。

代码示例

from typing import Callable, Any

class Validation:

    def __init__(
self, validation_function: Callable[[Any], bool], error_msg: str
) -> None:
print("Validation初始化被执行")
self.validation_function = validation_function # 传进来的是匿名函数
self.error_msg = error_msg def __call__(self, value):
print("call被执行")
if not self.validation_function(value): # lambda x: isinstance(x, (int, float))
raise ValueError(f"{value!r} {self.error_msg}") class Field: # 描述符类 def __init__(self, *validations): # 用*接收,表示可以传多个,目前代码可以理解为传进来的就是一个个Validation的实例
print("Field初始化被执行")
self._name = None
self.validations = validations # 接收完后的类型是元组 def __set_name__(self, owner, name):
print("set_name被执行")
self._name = name # 会自动将托管类ClientClass的类属性descriptor带过来 def __get__(self, instance, owner):
print("get被执行")
if instance is None:
return self
return instance.__dict__[self._name] def validate(self, value):
print("验证被执行")
for validation in self.validations:
validation(value) # 这是是将对象当成函数执行时,调用Validation的__call__魔法方法 def __set__(self, instance, value):
"""
:param self: 指的是Field对象
:param instance: ClientClass对象
:param value: 给属性赋值的值
:return:
"""
print("set被执行")
self.validate(value)
instance.__dict__[self._name] = value # 给ClientClass对象赋值 {"descriptor": 42} class ClientClass: # 托管类
descriptor = Field(
Validation(lambda x: isinstance(x, (int, float)), "is not a number"),
# Validation(lambda x: x >= 0, "is not >= 0"),
) if __name__ == '__main__':
"""
Validation初始化被执行
Field初始化被执行
set_name被执行 # 当Field()赋值给descriptor变量时,执行__set_name__
---------------------
set被执行
验证被执行
call被执行
"""
client = ClientClass() # 实例化对象
print("---------------------")
# 给上面实例化的对象中的属性(Field实例化对象)赋值为42
client.descriptor = 42

__set_name__魔法方法的更多相关文章

  1. PHP的魔法方法__set() __get()

    php的魔法方法__set()与__get() Tags: PHP 我们先来看看官方的文档如何定义他们的: public void __set(string $name, mixed $value); ...

  2. python进阶(四)---需要了解的魔法方法

    以下内容,源于个人理解所得,纯属臆测,爱信不信:-D.欢迎大家留言讨论指正. 1.__new__魔法方法: 原型:__new__(cls, *args, **kwargs) 说明:__new__魔法方 ...

  3. Python中的魔法方法

    1.什么是魔法方法? 魔法方法就是可以给你的类增加魔力的特殊方法,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而这一 ...

  4. Python的魔法方法 .

    基本行为和属性 __init__(self[,....])构造函数 . 在实例化对象的时候会自动运行 __del__(self)析构函数 . 在对象被回收机制回收的时候会被调用 __str__(sel ...

  5. 《Python基础教程(第二版)》学习笔记 -> 第九章 魔法方法、属性和迭代器

    准备工作 >>> class NewStyle(object): more_code_here >>> class OldStyle: more_code_here ...

  6. python 魔法方法

    I am not a creator, I just a porter. Note: Everything is object in python. 对于Python来说一切都是对象,也就是函数的参数 ...

  7. Python学习笔记:06魔法方法和迭代器

    魔法方法,属性和迭代器 新式类 通过赋值语句__metaclass=true或者class NewStyle(object)继承内建类object,可以表明是新式类. 构造方法 对象被创建后,会立即调 ...

  8. 魔法方法:算术运算 - 零基础入门学习Python042

    魔法方法:算术运算 让编程改变世界 Change the world by program 我现在重新提一个名词:工厂函数,不知道大家还有没有印象?我们在老早前就提到过Ta,由于那时候我们还没有学习类 ...

  9. 魔法方法:构造和析构 - 零基础入门学习Python041

    魔法方法:构造和析构 让编程改变世界 Change the world by program 构造和析构 什么是魔法方法呢?我们来系统总结下: - 魔法方法总是被双下划线包围,例如__init__ - ...

  10. python 魔法方法之:__getitem__ __setitem__ __delitem__

    h2 { color: #fff; background-color: #7CCD7C; padding: 3px; margin: 10px 0px } h3 { color: #fff; back ...

随机推荐

  1. 【转帖】GPT4All开源的聊天机器人

    GPT4All是一个开源的聊天机器人,它基于LLaMA的大型语言模型训练而成,使用了大量的干净的助手数据,包括代码.故事和对话.它可以在本地运行,不需要云服务或登录,也可以通过Python或Types ...

  2. Opentelemetry Metrics SDK

    Metrics SDK 目录 Metrics SDK 目标 期望 SDK 术语 数据流图表 要求 SDK MeterProvider Shutdown SDK:Instrument注册 SDK: Re ...

  3. 学习下Redis内存模型

    作者:京东零售 吴佳 前言 redis,对于一个java开发工程师来讲,其实算不得什么复杂新奇的技术,但可能也很少人去深入了解学习它的底层的一些东西.下面将通过对内存统计.内存划分.存储细节.对象类型 ...

  4. 解决刷新SwaggerUi控制台报错

    一.问题描述 在浏览器刷新SwaggerUI的页面,控制台就报错: java.lang.NumberFormatException: For input string: "" at ...

  5. C/C++ 通用ShellCode的编写与调用

    首先,我们的ShellCode代码需要自定位,因为我们的代码并不是一个完整的EXE可执行程序,他没有导入表无法定位到当前系统中每个函数的虚拟地址,所以我们直接获取到Kernel32.dll的基地址,里 ...

  6. MySQL安装 starting the server解决办法

    https://blog.csdn.net/qq_52183856/article/details/123792012 主要原因:

  7. “I/O多路复用”和“异步I/O”的前世今生

    曾经的VIP服务在网络的初期,网民很少,服务器完全无压力,那时的技术也没有现在先进,通常用一个线程来全程跟踪处理一个请求.因为这样最简单.其实代码实现大家都知道,就是服务器上有个ServerSocke ...

  8. 多路转接高性能IO服务器|select|poll|epoll|模型详细实现

    前言 那么这里博主先安利一下一些干货满满的专栏啦! Linux专栏https://blog.csdn.net/yu_cblog/category_11786077.html?spm=1001.2014 ...

  9. Git Q&A

    git入门 Q: 什么是git ? A: git是一种版本控制工具,也是程序员的"后悔药":当你在工程中写入一堆混乱的代码后,只要通过几行简单的git命令,就可以回退到任意一个提交 ...

  10. MarkDown文件插入图片(绝对\相对路径\调整图像大小位置)

    1. 插入网络图片(有效网络连接) Markdown中插入图片的语法为,图片路径可以直接写入图片有效链接网址即可: 方法1:![图片说明](图片有效链接网址) 方法2:<img src=&quo ...