技术图文:Python魔法方法之属性访问详解
背景
今天在B站学习“零基础入门学习 Python”中的第45节“魔法方法:属性访问”,这也是我们组织的 Python基础刻意练习活动 的学习任务,其中有这样的一个题目。
练习要求:
- 写一个矩形类,默认有宽和高两个属性。
- 如果为一个叫
square
的属性赋值赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。
技术分析
我们先来看看有关于属性的四个魔法方法:
__getattr__(self, name)
: 定义当用户试图获取一个不存在的属性时的行为。__getattribute__(self, name)
:定义当该类的属性被访问时的行为(先调用该方法,查看是否存在该属性,若不存在,接着去调用__getattr__
)。__setattr__(self, name, value)
:定义当一个属性被设置时的行为。__delattr__(self, name)
:定义当一个属性被删除时的行为。
class Test:def __getattr__(self, name):print('__getattr__')def __getattribute__(self, name):print('__getattribute__')def __setattr__(self, name, value):print('__setattr__')def __delattr__(self, name):print('__delattr__')t = Test()
t.x# __getattribute__
如上述代码所示,x
并不是Test
实例对象t
的一个属性,首先去调用 __getattribute__()
方法,得知该属性并不属于该实例对象。但是,按照常理,t.x
应该打印 __getattribute__
和__getattr__
,但实际情况并非如此,为什么呢?
实例对象属性寻找的顺序如下:
① 首先访问 __getattribute__()
魔法方法(隐含默认调用,无论何种情况,均会调用此方法)。
② 接着,去t.__dict__
中查找是否具备该属性。
③ 若在 t.__dict__
中找不到对应的属性, 则去t.__class__.__dict__
中寻找。
④ 若在实例的类中也找不到该属性,则去父类中寻找,即 t.__class__.__bases__.__dict__
中寻找
⑤ 若以上均无法找到,则会调用 __getattr__
方法,执行内部的命令(若未重载 __getattr__
方法,则直接报错:AttributeError
)
以上几个流程,即完成了属性的寻找。
但是,以上的说法,并不能解释为什么执行 t.x
时,不打印 __getattr__
啊?
问题就出在了步骤的第④步,因为,一旦重载了 __getattribute__()
方法,如果找不到属性,则必须要手动加入第④步,否则无法进入到 第⑤步 (__getattr__
)的。
验证一下以上说法是否正确:
方法一:采用 object
(所有类的基类)
class Test:def __getattr__(self, name):print('__getattr__')def __getattribute__(self, name):print('__getattribute__')object.__getattribute__(self, name)def __setattr__(self, name, value):print('__setattr__')def __delattr__(self, name):print('__delattr__')t = Test()
t.x# __getattribute__
# __getattr__
方法二:采用 super()
方法
class Test:def __getattr__(self, name):print('__getattr__')def __getattribute__(self, name):print('__getattribute__')super().__getattribute__(name)def __setattr__(self, name, value):print('__setattr__')def __delattr__(self, name):print('__delattr__')t = Test()
t.x# __getattribute__
# __getattr__
以上介绍完毕,那么 __setattr__
和 __delattr__
方法相对简单多了:
class Test:def __getattr__(self, name):print('__getattr__')def __getattribute__(self, name):print('__getattribute__')object.__getattribute__(self, name)def __setattr__(self, name, value):print('__setattr__')def __delattr__(self, name):print('__delattr__')t = Test()
t.x = 1# __setattr__del t.x# __delattr__
对了,再补充一点哈!
class Test:def __init__(self):self.count = 0def __setattr__(self, name, value):print('__setattr__')self.count += 1t = Test()# AttributeError: 'Test' object has no attribute 'count'
看报错信息很容易明白,这是因为:
① __init__()
时,给内部属性 self.count
进行了赋值;
② 赋值默认调用 __setattr__()
方法
③ 当调用 __setattr__()
方法时,首先打印 __setattr__
字符串,而后执行 self.cout += 1
操作
④ 当执行 self.cout + 1
操作时,将会去寻找 count
这个属性,然而,由于此时 __init__
尚未完成,并不存在 count
这个属性,因此导致 AttributeError
错误。
那么该如何更改呢?可以这样的:
class Test:def __init__(self):self.count = 0def __setattr__(self, name, value):print('__setattr__')super().__setattr__(name, value + 1)t = Test()
print(t.count)# __setattr__
# 1
以上代码虽然解决了报错的问题,深入体会一下,你会发现,采用此方法只是给 基类object
增加了一个属性 count
,而并不是实例的属性,因此,以上这种写法避免使用。
另外,再次将代码改进一下,如下:
class Test:def __setattr__(self, name, value):self.name = valuet = Test()
t.x = 'lsgo'# RecursionError: maximum recursion depth exceeded
当我们给 t.x
赋值时,调用了 __setattr__()
方法,进入该方法。该方法中,又来了一次赋值(self.name = value
),又会去调用 __setattr__()
方法,持续这个死循环。
所以,我们只好改变上述的问题了:
class Test:def __setattr__(self, name, value):print('__setattr__() been called')super().__setattr__(name, value)t = Test()
t.x = 'lsgo'# __setattr__() been calledprint(t.x)# lsgo
代码实现
上面详细介绍了关于属性的四个魔法方法,下面我们来看实现要求的具体代码:
class Rectangle:def __init__(self, width=0, height=0):self.width = widthself.height = heightdef __setattr__(self, key, value):if key == 'square':self.width = valueself.height = valueelse:super().__setattr__(key, value)def getArea(self):return float(self.width) * float(self.height)r = Rectangle(4, 5)
print(r.getArea()) # 20.0
r.square = 10
print(r.__dict__) # {'width': 10, 'height': 10}
print(r.getArea()) # 100.0
总结
魔法方法是 Python 面向对象编程中最核心的内容,需要花费一定的精力才能将其掌握,参加 Python基础刻意练习的小伙伴们加油! See You!
参考文献:
- https://www.bilibili.com/video/av4050443/?p=46
- https://www.runoob.com/python3/python3-tutorial.html
- https://www.cnblogs.com/Jimmy1988/p/6804095.html
相关图文:
- 资料分享:数学建模资料分享 – 图论部分
- 资料分享:数学建模资料分享 – 神经网络部分
- 如何利用 C# 实现 K 最邻近算法?
- 如何利用 C# 实现 K-D Tree 结构?
- 如何利用 C# + KDTree 实现 K 最邻近算法?
- 如何利用 C# 对神经网络模型进行抽象?
- 如何利用 C# 实现神经网络的感知器模型?
- 如何利用 C# 实现 Delta 学习规则?
- 如何利用 C# 实现 误差反向传播 学习规则?
- 如何利用 C# 爬取带 Token 验证的网站数据?
- 如何利用 C# 向 Access 数据库插入大量数据?
- 如何利用 C# + Python 破解猫眼电影的反爬虫机制?
相关文章:

chmod权限设置
drwxr-xr-x. 7 root root 4096 Sep 26 20:16 sysconfig-rw-r--r--. 1 root root 1150 Aug 31 18:46 sysctl.conflrwxrwxrwx. 1 root root 14 Aug 31 17:21 system-release -> centos-release例如:-rw-r--r--第一个代表文件类型:-普通文件:…

【Python培训基础】一篇文件教你py文件打包成exe
场景: 如果要将我们编写好的代码给别人使用,如果要他们直接使用我们的代码,就需要安装各种编译软件以及第三方模块,还要对软件操作,编程有一定的了解,这对使用者的要求比较高,不是很方便,为了解决这一问题,我们可以选择将我们编写的代码,编译成一个可执行文件,这样,就可以实现跨…

刻意练习:Python基础 -- Task06. 字典与集合
背景 我们准备利用17天时间,将 “Python基础的刻意练习” 分为如下任务: Task01:变量、运算符与数据类型(1day)Task02:条件与循环(1day)Task03:列表与元组(…

WCF - Session 剖析
WCF中的Session WCF是MS基于SOA建立的一套在分布式环境中各个相对独立系统进行通信的构架,实现了最新的基于WS-*规范。按照SOA的原则,相对独自的业务逻辑以service的形式封装,调用者通过Messaging的方式调用Service。对于承载着某个业务功能的…

mui 微信支付 与springMVC服务器交互
昨天搞定了微信支付,没有想象中的难,主要是官方的demo不全好多东西要自己琢磨,mui端的就不写了支付宝的有了一模一样.上java端的首先是jar包 一个是用来解析xml文件 一个是用来解析json 当然可以替代 然后是工具类当然并不是全都用的到. public class ConfigUtil { /** * 服务…

Python零基础自学会有哪些弊端
Python在人工智能领域的发展前景非常好,很多人都想要学习Python技术,有一些小伙伴会选择通过自学来学习,但是如果是零基础,自学的话一定要注意这些弊端,下面就为大家详细的介绍一下Python零基础自学会有哪些弊端? Pyt…

技术图文:如何利用 Turtle 绘制一棵漂亮的樱花树
背景 最近看到很多机构在推动“青少年编程能力等级标准”的制定以及相关考试的测评,看样子今年年底这个事情就能够确定,明天上半年在一些大中城市就会全面铺开。 《青少年编程能力等级》标准发布,年底前将在部分地区落地青少年编程能力等级…

Python 是否是下一个 PHP?为什么?
前几天和一个看好 Python 的 Rails 开发者聊天,他看好 Python 的原因就是 PHP 统治今天的网络应用开发。而 Python 很像下一个 PHP 。 『下一个 PHP』如何定义?是指流行程度么?如果是的话,我觉得 Python 不会像 PHP 那样流行。根本…

正确使用STL-MAP中Erase函数
一切尽在代码中。 #include <iostream> #include <map> #include <string> using namespace std ;int main(void) { map<int, string> m ;m.insert(pair<int, string>(1, "abc")) ;m.insert(pair<int, string>(2, "def&qu…

学完UI设计可以从事哪些工作
最近有很多同学都会问到一个问题,就是学完UI设计可以从事哪些工作?对于正在学习UI设计的同学和已经学完UI设计的同学们,可以来看看下面文章的详细介绍就知道了。 学完UI设计可以从事哪些工作? 一、交互设计师。 学习UI设计之后就可以做交互设计师了&am…

刻意练习:Python基础 -- Task08. 异常处理
背景 我们准备利用17天时间,将 “Python基础的刻意练习” 分为如下任务: Task01:变量、运算符与数据类型(1day)Task02:条件与循环(1day)Task03:列表与元组(…

Winform 控件自适应 JSP 入门登录案例
明儿在放,先睡转载于:https://www.cnblogs.com/javabin/archive/2011/09/26/2192402.html

MyEclipse对Struts2配置文件较检异常 Invalid result location value/parameter
有时在编写struts.xml时会报错,但是找不出有什么她方有问题。也能正常运行 MyEclipse有地方去struts的xml进行了验证,经查找把这里 的build去掉就可以了 本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/3791…

学Python有哪些优势
Python在人工智能领域应用是比较广泛的,近几年,越来越多的人对Python技术比较感兴趣,想要学习,那么具体学Python有哪些优势呢?我们来看看下面的详细介绍就知道了。 学Python有哪些优势? 1.Python很受欢迎 流行程度似乎不是衡量价…

MongoDB 正则表达式
阅读目录 示例不区分大小写数组使用正则表达式正则中包含变量回到顶部示例 MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。 > db.col.find() { "_id" : ObjectId("56c6bbef64799370c0ef358a"), "x" : "hello world", &…

刻意练习:Python基础 -- Task09. else 与 with 语句
背景 我们准备利用17天时间,将 “Python基础的刻意练习” 分为如下任务: Task01:变量、运算符与数据类型(1day)Task02:条件与循环(1day)Task03:列表与元组(…

Java学习必不可少的网站,快收藏起来
java技术在IT互联网行业的发展前景一直在提升,越来越多的人都在学习java技术,今天小编来给大家提供一些学习Java的网站集合,希望能够帮助到正在学习java技术的同学。 Java学习必不可少的网站,快收藏起来! 1. Stackoverflow Stacko…

刻意练习:Python基础 -- Task11. 魔法方法
背景 我们准备利用17天时间,将 “Python基础的刻意练习” 分为如下任务: Task01:变量、运算符与数据类型(1day)Task02:条件与循环(1day)Task03:列表与元组(…

Oracle中的MERGE语句
转自http://blog.chinaunix.net/space.php?uid16981447&doblog&cuid430716做了简单的格式整理,加入了一点点原创的东西。Oracle9i引入了MERGE命令,你能够在一个SQL语句中对一个表同时执行inserts和updates操作. MERGE命令从一个或多个数据源中选择行来upda…

C#从数据库导出数据[excel]
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Data;using MySql.Data.MySqlClient;using Microsoft.Office.Interop.Excel;using Excel Microsoft.Office.Interop.Excel; //使用命名空间别名using System.Reflection; …

UI设计培训中的扁平化理念
本文是为正在学习UI设计的同学们整理的一份资料,主要讲的是UI设计培训中的扁平化理念,扁平化的设计是抛弃一切装饰的设计,扁平化设计使得用户操作起来更加简洁、高效和舒适。简洁大方的交互界面设计自然能够引导用户,并且在短时间…
刻意练习:Python基础 -- Task12. 模块
背景 我们准备利用17天时间,将 “Python基础的刻意练习” 分为如下任务: Task01:变量、运算符与数据类型(1day)Task02:条件与循环(1day)Task03:列表与元组(…

Linux JSP连接MySQL数据库
Linux(Ubuntu平台)JSP通过JDBC连接MySQL数据库,与Windows平台类似,步骤如下: 下载 jdbc: mysql-connector-java-5.1.18.tar.gz 解压 jdbc: tar -zxvf mysql-connector-java-5.1.18.tar.gz 配置 …

h5 getUserMedia error PermissionDeniedError
HTML5 在使用非 localhost 地址访问时打开摄像头失败 。报getUserMedia error PermissionDeniedError,火狐下是可以正常调取的。 需要https: 火狐: 转载于:https://www.cnblogs.com/cosyer/p/7646672.html

女生零基础学软件测试难不难
软件测试属于一门IT技术编程语言,很多人都觉得IT技术都是男性比较多,按照目前的行业数据来看,确实是男性居多,但最近几年,女性程序猿也越来越多,其中就有软件测试这个岗位,下面具体来看看女生零…

技术图文:NumPy 的简单入门教程
背景 这段时间,LSGO软件技术团队正在组织 “机器学习实战刻意练习”活动,这个活动是“Python基础刻意练习”活动的升级,是对学员们技术的更深层次的打磨。在用 Python 写各类机器学习算法时,我们经常会用到 NumPy库,故…

Android常见错误
1、Unable to resolve target android-2 安装低版本的api,再default.properties 这个文件中把targetandroid-2 改成 targetandroid-7终于就没有问题了。 2、Invalid start tag LinearLayout main.xml放错文件夹了,应该在\res\layout下。 3、INSTALL_FAIL…

【开发】简易教程
本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果。这个小程序的首页将会显示欢迎语以及当前用户的微信头像,点击头像,可以在新开的页面中查看当前小程序的启动日志。下载源码 1. 获取微信小程序的 AppID 登录…

Python未来的发展趋势怎么样
Python未来的发展趋势怎么样?最近很多人都在学习Python技术,但是在学习的过程中,还是比较担心Python是否有发展前景这个问题,我们来看看下面的详细解析。 Python未来的发展趋势怎么样? 一、从事Python的待遇高。 由于Python语言的应用领域很…

刻意练习:机器学习实战 -- Task01. K邻近算法
背景 这是我们为拥有 Python 基础的同学推出的精进技能的“机器学习实战” 刻意练习活动,这也是我们本学期推出的第三次活动了。 我们准备利用8周时间,夯实机器学习常用算法,完成以下任务: 分类问题:K邻近算法分类问…