热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析Python中的魔法方法__dict__和__getattr__的巧妙应用

在Python中,魔法方法`__dict__`和`__getattr__`具有重要的作用和灵活的应用。`__dict__`是一个用于存储对象属性的字典,其中键为属性名,值为对应的属性值。通过`__dict__`,可以动态地访问和修改对象的属性。而`__getattr__`方法则在尝试访问对象中不存在的属性时被调用,提供了一种优雅的处理方式,避免了属性访问错误。这两个魔法方法在实现复杂的数据结构和动态行为时尤为有用。

python魔法函数__dict__和__getattr__的妙用

_dict_

__dict__是用来存储对象属性的一个字典,其键为属性名,值为属性的值。

既然__dict__是个字典那么我们就可以用字典的属性了。

我们通过使用dir()属性来看看__dict__都有哪些属性。

['__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

我们看一段代码内含注释:

class A():
    def __init__(self):
        self.name="liming"

    def save_data(self,dicts):
        self.__dict__.update(dicts)#添加字典元素
        if isinstance(self.__dict__,dict):
            print(True)
        #获取字典独有的属性
        print(set(dir(self.__dict__))-set(dir(self)))
        return self.__dict__

if __name__ == '__main__':
     dicts={"a":1,"b":2,"c":3}
     a=A()
     print(a.save_data(dicts))

输出结果

True
{'__delitem__', 'keys', 'update', '__len__', '__getitem__', 'get', 'clear', 'copy', 'popitem', '__iter__', 'items', '__contains__', 'pop', '__setitem__', 'fromkeys', 'values', 'setdefault'}
{'name': 'liming', 'a': 1, 'b': 2, 'c': 3}

下面来一个比较实用的例子来大大的减少你的代码,做到真正的pythonic。
我们在使用给对象的属性赋值的时候

class A():
    def __init__(self,dicts):
        self.name=dicts["name"]
        self.age=dicts["age"]
        self.sex=dicts["sex"]
        self.hobby=dicts["hobby"]
if __name__ == '__main__':
     dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
     a=A(dicts)

我们看到我们需要换取传入的字典的各个键值,并创建键值同名一个属性,这里我们只有4个还好,想象一下如果我们传入的字典有100个键。。。如何还是这样一个一个赋值不敢想不敢想,人家都写完代码了,你还在赋值有木有。。
其实一开始的那段代码已经给出了答案,如果不会也没关系,
下面我们就来点pythonic的python。来解决这个问题。
上面代码简化为:

class A():
    def __init__(self,dicts):
        self.__dict__.update(dicts)
        print(self.__dict__)

if __name__ == '__main__':
     dicts={"name":"lisa","age":23,"sex":"women","hobby":"hardstyle"}
     a=A(dicts)

看完后感觉怎么样啊,其实__dict__还有一个重要的用处就是单例模式***享同一状态,参考之前写的单例模式。
拓展:部分内建函数不包含__dict__属性比如list,如果要查看list的属性怎么办呢,这时候用dir(list),dir方法也是查看对象的属性,包括内建对象的属性,但是它的输出形式列表,而__dict__是列表。

_getattr_

经过查阅资料用我的理解去解释这个方法的用法那就是:使用.获取属性的时候,如果该属性存在就输出其值,如果不存在则会去找_getatrr_,我们可以通过重写该方法可以实现动态属性的操作。(如果只允许添加指定的属性需要用__solts__函数控制,这里不做详细讲解)

先来一段比较有意思的代码

from requests_html import HTMLSession
class UrlGenerator(object):
    def __init__(self, root_url):
        self.url = root_url
        self.session=HTMLSession()

    def __getattr__(self, item):
        if item == 'get':
            self.get_html()
        return UrlGenerator('{}.{}'.format(self.url, item))
    def get_html(self):
        req = self.session.get(self.url)
        print(req.text)

url_gen = UrlGenerator('https://www')
url_gen.baidu.com.get

充分利用__getattr__会在没有查找到相应实例属性时被调用的特点,方便的通过链式调用生成对应的url,在碰到get方法的时候调用函数获取其网页源码。
可调用的对象更加的优雅,链式的操作不仅优雅而且还能很好的说明调用的接口的意义。

下面展示一个__getattr__经典应用的例子,可以通过获取属性值的方式获取字典的键值。

class ObjectDict(dict):
    def __init__(self, *args, **kwargs):
        super(ObjectDict, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        value = self[name]
        if isinstance(value, dict):
            value = ObjectDict(value)
        return value

if __name__ == '__main__':
    od = ObjectDict(asf={'a': 1}, d=True)
    print(od.asf,od.asf.a)     # {'a': 1} 1
    print(od.d)                 # True

好了,今天的内容就到这。


推荐阅读
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本文详细介绍了钩子(hook)的概念、原理及其在编程中的实际应用。通过对比回调函数和注册函数,解释了钩子的工作机制,并提供了具体的Python示例代码,帮助读者更好地理解和掌握这一重要编程工具。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • Django Token 认证详解与 HTTP 401、403 状态码的区别
    本文详细介绍了如何在 Django 中配置和使用 Token 认证,并解释了 HTTP 401 和 HTTP 403 状态码的区别。通过具体的代码示例,帮助开发者理解认证机制及权限控制。 ... [详细]
  • 本文介绍如何在Spring Boot项目中集成Redis,并通过具体案例展示其配置和使用方法。包括添加依赖、配置连接信息、自定义序列化方式以及实现仓储接口。 ... [详细]
  • 社交网络中的级联行为 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • Python 工具推荐 | PyHubWeekly 第二十一期:提升命令行体验的五大工具
    本期 PyHubWeekly 为大家精选了 GitHub 上五个优秀的 Python 工具,涵盖金融数据可视化、终端美化、国际化支持、图像增强和远程 Shell 环境配置。欢迎关注并参与项目。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
author-avatar
妞妞吃粑粑_577
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有