目录
- 1. 对象构建
- 2. 对象属性访问
- 3. 对象比较
- 4. 对象输出
- 5. 对象运算
- 6. 总结
python中魔法方法(magic method)其实就是那些被双下划线包围的方法,比如__init__
,__str__
等等。
这些魔法方法为类添加了**“魔力”,让我们可以在面向对象编程中用更加简洁的代码来操作对象。
本篇根据面向对象编程的一些场景来介绍常用的魔法方法**。
1. 对象构建
为了初始化对象,我们常常在对象中定义一个__init__
方法,比如:
class Student(object): """ 学生信息 """ def __init__(self, name): print("[__init__] Student 初始化...") self.name = name # 创建对象 stu = Student("小明") # 运行结果 [__init__] Student 初始化...
当我们创建对象时,会自动调用魔法方法__init__
去初始化属性。
与__init__
对应的是__del__
,它会在对象失效的调用,我们可以在__del__
方法中清理对象Student
占用的资源。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __del__(self): print("[__del__] 清理 Student...") def foo(): print("进入 foo 函数...") stu = Student("小明") print("离开 foo 函数...") foo() # 运行结果 进入 foo 函数... [__init__] 初始化 Student... 离开 foo 函数... [__del__] 清理 Student...
进入 foo
函数后创建对象,离开后,自动清理对象。
2. 对象属性访问
python
的对象是可以直接访问属性的,但是访问不存在的属性时,会抛出异常。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name stu = Student("小明") print(stu.name) print(stu.fullname) # 运行结果 [__init__] 初始化 Student... 小明 AttributeError: 'Student' object has no attribute 'fullname'
如果不想抛出异常,从而影响程序的其他部分的运行,这里可以用魔法方法 __getattr__
来控制访问了不存在的属性时的行为。
比如,下面的示例中,访问不存在的属性时,返回False
,不抛出异常。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __getattr__(self, attr): print("[__getattr__] 访问了 Student 不存在的属性 {}".format(attr)) return False stu = Student("小明") print(stu.name) print(stu.fullname) # 运行结果 [__init__] 初始化 Student... 小明 [__getattr__] 访问了 Student 不存在的属性 fullname False
与__getattr__
相对的另一个魔法方法__setattr__
,与__getattr__
不同的是,它既可以设置不存在的属性,也可以设置已存在的属性。
class Student(object): def __init__(self, name): print("[__init__] 初始化 Student...") self.name = name def __setattr__(self, attr, value): print("[__setattr__] 设置 Student 属性 {}={}".format(attr, value)) self.__dict__[attr] = value stu = Student("小明") print(stu.name) # 已存在的属性 stu.name = "小华" print(stu.name) # 不存在的属性 stu.fullname = "小红" print(stu.fullname) # 运行结果 [__init__] 初始化 Student... [__setattr__] 设置 Student 属性 name=小明 小明 [__setattr__] 设置 Student 属性 name=小华 小华 [__setattr__] 设置 Student 属性 fullname=小红 小红
每次对属性赋值,都会触发__setattr__
方法,即使在__init__
中给self.name
赋值,也触发了__setattr__
方法,所以一共被触发了三次。
3. 对象比较
在使用基本类型(比如数值类型,字符串类型等)的时候,比较其大小非常简单。
print(1 < 2) print(1 > 2) print("abc" < "edf") # 运行结果 True False True
而对象直接互相比较大小则没有这么简单了,还是用上面的Student类,这次我们加上各门功课的分数。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics stu1 = Student("小明", 80, 90, 75) stu2 = Student("小红", 85, 70, 95) # 比较两个学生对象 print(stu1 > stu2) # 运行结果 TypeError: '>' not supported between instances of 'Student' and 'Student'
不出所料,抛出了异常。
其实我们比较两个学生对象,是想要比较两个学生的总分谁高谁低。
这时,我们就可以实现用于比较的魔法方法,比如 __eq__
,__lt__
,__gt__
等等。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics def total(self): return self.chinese + self.english + self.mathematics def __eq__(self, other: Student): return self.total() == other.total() def __lt__(self, other: Student): return self.total() < other.total() def __gt__(self, other: Student): return self.total() > other.total() stu1 = Student("小明", 80, 90, 75) stu2 = Student("小红", 85, 70, 95) print(stu1 > stu2) print(stu1 == stu2) print(stu1 < stu2) # 运行结果 False False True
实现相应的魔法方法,就能使用相应的比较运算符来直接比较对象了。
PS. 上面的例子中只实现了大于(__gt__
),等于(__eq__
),小于(__lt__
)的比较,还有其他魔法方法,比如:大于等于(__ge__
),不等于(__ne__
),小于等于(__le__
)等等。
实现的方式和上面例子中类似。
4. 对象输出
对于一个基本类型的变量,显示其内容非常简单,而对于一个对象,显示的内容可能就不是我们所期望的了。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics s = "hello world" print(s) stu = Student("小明", 80, 90, 75) print(stu) # 运行结果 hello world <__main__.Student object at 0x00000164F72FD6D0>
字符串内容可以直接显示出来,而对象stu
只是显示了它的内存地址,对我们了解其中的内容毫无帮助。
此时,就可以拿出我们的魔法方法__str__
,来定制对象在print
时显示的内容。
class Student(object): def __init__(self, name, chinese, english, mathematics): self.name = name self.chinese = chinese self.english = english self.mathematics = mathematics def __str__(self): return """姓名: {} 成绩: 1. 语文: {} 分 2. 数学: {} 分 3. 英语: {} 分""".format( self.name, self.chinese, self.mathematics, self.english, ) stu = Student("小明", 80, 90, 75) print(stu) # 运行结果 姓名: 小明 成绩: 1. 语文: 80 分 2. 数学: 75 分 3. 英语: 90 分
通过魔法方法__str__
,可以让对象按照我们希望的形式显示出来。
5. 对象运算
对象除了可以像普通变量一样比较,输出,是不是也可以像变量一样进行算术运算呢?
比如:class Student(object): def __init__(self, name, scores): self.name = name self.scores = scores def __str__(self): return """姓名: {}, 各科成绩: {}""".format( self.name, self.scores, ) stu1 = Student("小明", [80, 90, 75]) stu2 = Stud编程客栈ent("小红", [85, 70, 95]) print(stu1) print(stu2) print(stu1 + stu2) # 运行结果 姓名: 小明, 各科成绩: [80, 90, 75] 姓名: 小红, 各科成绩: [85, 70, 95] TypeError: unsupported pythonoperand type(s) for +: 'Student' and 'Student'
果然,直接进行算术运算是不行的。
还是得借助魔法方法,下面在类中实现加法和减法的魔法方法。
class Student(object): def __init__(self, name, scores): self.name = name self.scores = scores def __str__(self): return """姓名: {}, 各科成绩: {}""".format( self.name, self.scores, ) def __add__(self, other: Student): name = "{}, {} 成绩合计".format(self.name, other.name) scores = [self.scores[i] + other.scores[i] for i in range(len(self.scores))] return Student(name, scores) def __sub__(self, other: Student): name = "{}, {} 成绩之差".format(self.name,编程 other.name) scores = [self.scores[i] - other.scores[i] for i in range(len(self.shttp://www.devze.comcores))] return Student(name, scores) stu1 = Student("小明", [80, 90, 75]) stu2 = Student("小红", [85, 70, 95]) print(stu1) print(stu2) print(stu1 + stu2) print(stu1 - stu2) # 运行结果 姓名: 小明, 各科成绩: [80, 90, 75] 姓名: 小红, 各科成绩: [85, 70, 95] 姓名: 小明, 小红 成绩合计, 各科成绩: [165, 160, 170] 姓名: 小明, 小红 成绩之差, 各科成绩: [-5, 20, -20]
其他的算术运算(比如,乘法,除法和求模等等)也有相应的魔法方法,仿照上面的示例实现即可。
6. 总结
Python
的魔法方法很多,本文只是列举了其中很少的一部分,github
上有一个示例python
文件,列举了很多魔法方法,供参考:magicmethods.py
到此这篇关于Python利用魔法方法玩转对象的文章就介绍到这了js,更多相关Python魔法方法内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论