魔法方法

Python里面有一种特殊的方法,叫做魔法方法。Python的类里提供的,是由两个下划线开始,再以两个下划线结束的方法。
魔法方法不需要手动调用,会在恰当的时候就会被激活,自动执行。
魔法方法的名字都是系统规定好的,不能乱写,在合适的时候自己调用。

1.__init__方法

_init_()方法,在创建一个对象时默认被调用,不需要手动调用。在开发中,如果希望在创建对象的同时,就设置对象的属性,可以对__init__ 方法进行改造。

class Student(object):def __init__(self, name):  # 重写了___init__魔法方法,设置对象的属性# 在创建对象时,会自动调用这个方法。print('__init__方法被调用了')self.name = namedef play_game(self):print('{}正在玩游戏'.format(self.name))
s1 = Student('张三') #创建对象时,必须要指定name属性的值
print(s1.name)  # 张三
s1.play_game()  # 张三正在玩游戏

运行结果:

__init__方法被调用了
张三
张三正在玩游戏

注意

  1. _init_()方法在创建对象时默认被调用,不需要手动调用。
  2. _init_()方法里的self参数,在创建对象时不需要传递参数,python解释器会把创建好的对象引用直接赋值给self
  3. 在类的内部,可以使用self来使用属性和调用方法;在类的外部,需要使用对象名来使用属性和调用方法。
  4. 如果有多个对象,每个对象的属性是各自保存的,都有各自独立的地址。
  5. 方法是所有对象共享的,只占用一份内存空间,方法被调用时会通过self来判断是哪个对象调用了实例方法。

2.__del__方法

既然有创建对象时的魔法方法调用,就会有删除对象时的魔法方法调用,_del_()方法就是当对象被销毁时,会自动调用这个方法。

class Student(object):def __init__(self, name):print('__init__方法被调用了')self.name = namedef __del__(self):# 当对象被销毁时,会自动调用这个方法print('__del__ 方法被调用了')def play_game(self):print('{}正在玩游戏'.format(self.name))
s1 = Student('张三')
del s1

运行结果:

__init__方法被调用了
del 方法被调用了

3.__str__方法

__str__方法返回对象的描述信息,使用print()函数打印对象时,其实调用的就是这个对象的__str__方法。
调用对象的 __str__方法,默认会打印类名和对象的地址名。

class Student(object):def __init__(self, name):self.name = name
s1 = Student('张三')
print(s1)   # <__main__.Student object at 0x00000298D1161808>

那我们如何得到s1的值呢?其实想要修改对象的输出结果,我们就需要重写__str__方法。

class Student(object):def __init__(self, name):self.name = namedef __str__(self):return '姓名:{}'.format(self.name)
s1 = Student('张三')
print(s1)  # 姓名:张三

4.__repr__方法

__repr__方法和__str__方法功能类似,都是用来修改一个对象的默认打印内容。在打印一个对象时,如果没有重写__str__方法,它会自动来查找__repr__方法。如果这两个方法都没有,会直接打印这个对象的内存地址。

class Student(object):def __init__(self, name):self.name = namedef __repr__(self):return '姓名:{}'.format(self.name)
s1 = Student('张三')
print(s1)  # 姓名:张三

倘若__repr__方法和__str__方法同时出现,会发生什么情况呢???

class Student(object):def __init__(self, name):self.name = namedef __repr__(self):return 'hello world'def __str__(self):return '姓名:{}'.format(self.name)
s1 = Student('张三')
print(s1)  # 姓名:张三

从上面的实例可知,若两种方法同时出现,会选择调用__str__方法。
如果还想在有__str__方法的情况下,调用__repr__方法,我们可以调用内置函数repr或者手动调用__repr__方法。

class Student(object):def __init__(self, name):self.name = namedef __repr__(self):return 'hello world'def __str__(self):return '姓名:{}'.format(self.name)
s1 = Student('张三')
print(s1)  #自动调用__str__方法
print(repr(s1))  # 调用内置函数 repr 会触发对象的 __repr__ 方法
print(s1.__repr__())  # 手动调用__repr__魔法方法

运行结果:

姓名:张三
hello world
hello world

注意:

  1. 如果不做任何的修改,直接打印一个对象,是文件的 name.类型 内存地址
  2. 当打印一个对象的时候,会调用这个对象的 str 或者 repr 方法
  3. 如果两个方法都写了,选择 str
  4. 如果在两个方法都写了的情况下,调用__repr__方法,我们可以调用内置函数repr或者手动调用__repr__方法。

5.__call__方法

对象后面加括号,触发执行。

class Student(object):def __init__(self, name):self.name = namedef __call__(self, *args, **kwargs):print('args={},kwargs={}'.format(args, kwargs))
s1 = Student('张三')
s1(1, 2, 3, age=18, score=99)  # args=(1, 2, 3),kwargs={'age': 18, 'score': 99}

6.比较运算符相关的魔法方法

class Student(object):def __init__(self, name, score):self.name = nameself.score = score
s1 = Student('zhangsan', 90)
s2 = Student('zhangsan', 90)

s1和s2是否是同一个对象?
比较两个对象是否是同一个对象,我们需要比较的是内存地址

print('0x%X' % id(s1))  # 0x16AA83BB408
print('0x%X' % id(s2))  # 0x16AA83BB448

由上可知,它们的内存地址不一样,两个对象不是同一个对象。

print('s1 is s2', s1 is s2)  # s1 is s2 False
print(s1 == s2)  # False

is 身份运算符,比较两个对象的内存地址
== 会调用对象的 eq 方法,如果不重写,默认比较依然是内存地址,如果重写方法,便可以获取这个方法的比较结果。

class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef __eq__(self, other):return self.name == other.name and self.score == other.score
s1 = Student('zhangsan', 90)
s2 = Student('zhangsan', 90)
print( s1 == s2)  # True

其它比较运算符,也是如此。

class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef __eq__(self, other):return self.name == other.name and self.score == other.score#def __ne__(self, other):# 使用 != 运算符会自动调用这个方法def __lt__(self, other):return self.score < other.scoredef __gt__(self, other):return self.score > other.scoredef __le__(self, other): return self.score <= other.scoredef __ge__(self, other): return self.score >= other.score
s1 = Student('zhangsan', 90)
s2 = Student('zhangsan', 90)
s3 = Student('lisi', 94)
s4 = Student('wangwu', 99)
print(s1 == s2)  #True
print(s1 != s2)  #False
print(s1 > s3)   #False
print(s1 >= s4)  #False
print(s1 < s4)   #True
print(s1 <= s3)  #True

7.算数运算符相关的魔法方法

class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef __add__(self, other):return self.score + otherdef __sub__(self, other):return self.score - otherdef __mul__(self, other):return self.name * otherdef __truediv__(self, other):return self.score / otherdef __mod__(self, other):return self.score % otherdef __pow__(self, power, modulo=None):return self.score ** powers = Student('zhangsan', 95)
print(s + 1)  # 96
print(s - 2)  # 93
print(s * 2)  # zhangsanzhangsan
print(s / 5)  # 19.0
print(s % 5)  # 0
print(s ** 2) # 9025

8.类型转换相关的魔法方法

class Student(object):def __init__(self, name, score):self.name = nameself.score = scoredef __int__(self):return self.scoredef __float__(self):return self.score * 1.0def __str__(self):return self.namedef __bool__(self):return self.score > 60s1 = Student('zhangsan', 90)
print(int(s1))   # 90
print(float(s1)) # 90.0
print(str(s1))   # zhangsan
print(bool(s1))  # True

9.容器方法

__ len__ -> len    计算长度
__ iter__ -> for    for循环
__ contains__ -> in  判断是否存在
__ getitem__ 对 string、 bytes、list、tuple、dict 有效   下标求值
__ setitem__ 对 list、dict 有效  添加、修改

需求:求出k列表后三位数

k = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]print(k.__getitem__(-3:)))  # 报错

这里可以使用slice切片

k = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]print(k.__getitem__(slice(7, 10)))  # [8, 9, 0]

10.上下文管理with

__ enter__ 进⼊ with 代码块前的准备操作
__ exit__ 退出时的善后操作
⽂件对象、线程锁、socket 对象等都可以使⽤ with 操作。
为什么要使用with来操作???因为使用with可以自动关闭文件,即便是代码程序报错,其也能关闭文件。

class A:def __enter__(self):print('exec enter')return selfdef __exit__(self, a1, a2, a3):print('exec exit')print('a1:', a1)print('a2:', a2)print('a3:', a3)with A() as a:print('a = ', a)raise ValueError('errorerror')

运行结果:

11.属性相关的方法

__ dict__、__ setattr__、__ getattribute__、__ getattr__
内建函数:setattr()、getattr()、hasattr()
对象的属性都存放在__ dict__中,类属性在类对象中保存;普通的对象是由类创建的,类是由元类创建的。

class A:def __init__(self):self.x = 123self.y = 456a = A()
a.z = 789
print(a.__dict__)  # {'x': 123, 'y': 456, 'z': 789}a.__dict__['x'] = 0print(a.__dict__)  # {'x': 0, 'y': 456, 'z': 789}
print(a.__dict__['x'])  # 0
class A:z = 789def __init__(self):self.x = 123self.y = 456def foo(self):print(self.x + self.y)def bar(self):return self.x / self.yA.bar = bar  # 猴子补丁(monkey patch)print(A.__dict__)

运行结果:

{‘module’: ‘main’,
‘z’: 789,
init’: <function A.init at 0x0000012BA24DA4C8>,
‘foo’: <function A.foo at 0x0000012BA24DA168>,
dict’: <attribute ‘dict’ of ‘A’ objects>,
weakref’: <attribute ‘weakref’ of ‘A’ objects>, # 弱引用
doc’: None, ‘bar’: <function bar at 0x0000012BA24DA438>}

通过 hasattr()可以查看是否拥有属性。

class A:z = 789def __init__(self):self.x = 123self.y = 456a = A()print(hasattr(a, 'abc'))  # False
print(hasattr(a, 'x'))  # True

通过 setattr()可以设置属性。

class A:z = 789def __init__(self):self.x = 123self.y = 456a = A()setattr(a, 'x', 777)
print(a.x)  # 777
setattr(a, 'h', 888)
print(a.h)  # 888

通过 getattr()可以获得属性。

class A:z = 789def __init__(self):self.x = 123self.y = 456a = A()print(getattr(a, 'x'))  # 123
print(getattr(a, 'r', 111))  # 没有可以设置默认值:111

通过 delattr()可以删除属性。

class A:z = 789def __init__(self):self.x = 123self.y = 456a = A()delattr(a, 'y')
print(a.y)  # 报错

__ setattr__、__ getattribute__、__ getattr__的使用

class User:z = [7,8,9]def __init__(self):self.money = 10000self.y = 'abc'def __setattr__(self, name, value):print('set %s = %s' % (name, value))object.__setattr__(self, name, value)def __getattribute__(self, name):print('getattribute %s' % name)return object.__getattribute__(self, name)def __getattr__(self, name):print('getattr %s' % name)return -1def foo(self, x, y):return x * y

当u = User()时,会执行__ init__()和__ setattr__()
当我们调用foo函数时u.foo(x,y),会执行__ getattribute__()
当我们找不到属性时,会执行__ getattribute__()和__getattr__()

12.槽(__ slots__)

其可以固定类所具有的属性,使实例不会分配__dict__,也无法动态添加属性,但其可以优化内存分配。

Python的面向对象(二):Python中神奇的魔法方法相关推荐

  1. Python爬虫-面向对象-《传闻中的陈芊芊》豆瓣热评

    Python爬虫-面向对象-<传闻中的陈芊芊>豆瓣热评 其实需要注意的问题也并不是很多,现在大多数网站都建立了反爬机制,通过user-agent模仿用户进行服务器访问,如果无法访问,再添加 ...

  2. python共享文件权限_利用Python实现在同一网络中的本地文件共享方法

    本文利用Python3启动简单的HTTP服务器,以实现在同一网络中共享本地文件. 启动HTTP服务器 打开终端,转入目标文件所在文件夹,键入以下命令: $ cd /Users/zero/Documen ...

  3. 手把手教你学python第十三讲(MRO详解和神奇的魔法方法)

    如果图片刷不出来,转到https://www.bilibili.com/read/cv286207 MRO重制 关于MRO和C3算法,我又去看了一些文章,然后发现了讲的很清楚的文章http://kai ...

  4. python中常见的魔法方法 magic method

    魔法方法 magic method(类中定义的双下方法) 魔法方法都是父类object有的,在python3中所有的类默认都会继承object.当我们对这个对象使用这些函数或者运算符时就会调用类中的对 ...

  5. 面向对象封装继承多态五大基本原则魔法方法反射

    目录 面向对象 三大基本特征 五大基本原则 魔法方法 反射 面向对象 什么是面向对象 使用模板的思想,将世界万事万物使用对象来表示一个类型 面向对象和面向过程的区别: 面向对象的不就是使用程序处理事情 ...

  6. Python基础-------面向对象二

    目录 一.封装 二.property装饰器 三.继承 四.多继承 五.方法的重写 super方法 一.封装 什么是封装 在日常中封装指的是将我们的物品包裹起来,不让看到其内部,具有保护的功能.在程序设 ...

  7. Python中面向对象self获取对象属性,魔法方法

    类和对象 类(Class) 由3个部分构成 01). 类的名称:类名 02). 类的属性:一组数据 03). 类的方法:允许对进行操作的方法 (行为) 定义类 object 是Python 里所有类的 ...

  8. python封装:隐藏对象中的属性或方法(三分钟读懂)

    封装:隐藏对象中的属性或方法 隐藏对象中的属性 隐藏:- 将对象的属性名,修改为一个外部不知道的名字 我们使用时,有特殊方法来处理获取(修改)对象中的属性 获取(修改)对象中的属性 需要提供一个get ...

  9. python import from区别_python中import与from方法总结(推荐)

    一.模块&包简介 模块:所谓模块就是一个.py文件,用来存放变量,方法的文件,便于在其他python文件中导入(通过import或from). 包(package): 包是更大的组织单位,用来 ...

最新文章

  1. 如何让phpmyadmin输入密码再进入
  2. 任务管理器进程中多个chrome.exe的问题
  3. go gorm 密码隐藏_掀开华为云的Go语言编程底座!有深度、有点难、需细品(上)...
  4. 【学习笔记】同余最短路
  5. 软件定义无线电matlab书,软件定义无线电
  6. 表格占据整个页面_excel转换为pdf6个示例,在多个工作表、表格和空白页中进行选择...
  7. php多维求组按照健值排序,PHP编程实现多维数组按照某个键值排序的方法小结【2种方法】...
  8. oracle新建对象 权限管理
  9. ubuntu安装有道云笔记_建立基于有道云笔记的错题本
  10. java derby xsai2,java-j内的引用罐
  11. mysql自增主键 php_MySQL的自增ID(主键) 用完了的解决方法
  12. iOS开发技巧:使用Objective-C创建UUID
  13. Oracle的方案(Schema)和用户(User)的区别
  14. 安卓逆向 -- 防抓包破解(JustTrustMe)
  15. 文献综述是什么?怎么写?内附简洁模板
  16. 全国哀悼日网站变灰代码
  17. 翡翠玉石微观世界,太美了!
  18. h5策划书_世界睡眠日H5策划方案
  19. ipad使用计算机的图片大全,三种方式备份 iPad 照片
  20. 设置360浏览器的背景色为绿豆色或护眼色

热门文章

  1. C/C++新建注册表项【代码示例】
  2. Comments are not permitted in JSON.报错
  3. 【Java】多个pdf合并成一个pdf(Itext)
  4. 通用Mapper Example类使用以及源码分析
  5. python环绕文字_Java 设置 Word 文档中图片文字环绕方式
  6. 编程,真不难 2 —— 搭建编程环境
  7. 使用485串口通信时,有时候有乱码,有时候就没乱码
  8. 关于git和gitee下载使用以及在idea中使用的情况
  9. Linux SSH 连接不上的各种联想
  10. 前端合并数组\对象的方法