魔法方法介绍 | 学习笔记

简介: 快速学习 魔法方法介绍

开发者学堂课程【Python入门 2020年版魔法方法介绍】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址:https://developer.aliyun.com/learning/course/639/detail/10376


魔法方法介绍


内容介绍:

一、self 的注意事项

二、算数相关的魔法方法

三、转换字符串


一、 self 的注意事项

先新建一个 python 文件,名为02-self 的注意事项

新建一个类:

class Person(object):

def __init__(self,name,age):

self.name = name

self.age = age

def eat(self):

print(self.name + ‘正在吃东西’)

p1 = Preson(‘张三’,18)

p2 = Person(‘李四’,20)

到现在一共有两个对象,把__init__()方法当作函数,形参是在赋值的时候可以用。如果执行的是 p1 = Preson(‘张三’,18)这段代码,此时 self 指的是 p1创造的内存空间的。

如下图所示:

p1指向内存空间时,self 也指向对应的内存空间。p1走完后,__init__调完后,self 不再指向 p1的内存空间,会变为空。

image.png

当执行 p2时,会再次调用__init__,它就会指向 p2的内存空间。也就时执行的时候会调用__init__函数,不调用的时候方法就为空,谁调用就指向谁。

但如果加入语句 p1.eat(),此时__init__()中的 self 是都没有指向的,而 eat()中的 self 是指向 p1的内存空间。再函数正在执行的时候,才有指向,等到调完之后,self 谁也不指。

也就是调的时候才有指向,不调就没有指向。所以__init__()eat()中的 self 是没有可比性的,只有调用的时候才知道self 是谁。


二、  算数相关的魔法方法

新建一个 python 文件,并命为03-运算符相关的魔法方法

书写代码:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

p1 = Preson(zhangsan’,18)

p2 = Person(zhangsan’,18)

print(p1 is p2)

运行结果为:

False,这是两块内存,不过数据内容相同。

加入语句 print(p1 == p2)

整理代码:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

pass

p1 = Preson(zhangsan’,18)

p2 = Person(zhangsan’,18)

print(p1 is p2)

print(p1 ==p2)

运行结果为:

False,原因是

image.png

==运算符的本质其实是调用对象的__eq__方法,获取__eq__方法的返回值结果。a == b 其实就是 a.__eq__(b)

print(p1 == p2)就是 p1.__eq__()方法调用到 p2上。现在的问题是在于__eq__(self,other):语句中的 self 指的是谁?

它指的是 p1,因为在之前说过谁调用,self 指的就是谁。所以 p1指向的是 selfp2指向的是 other。现在依照若 p1的内容等于 p2的内容来书写代码:

def __eq__(self,other):

if self.name == other.name and self.age == other.age:

return True

return False

1)在向代码中加入 print(p1 !=p2)

整理代码内容:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

p1 = Preson(zhangsan’,18)

p2 = Person(zhangsan’,18)

print(p1 is p2)

print(p1 ==p2)

print(p1 !=p2)

运行结果为:

结果是 False

=本质是调用__ne__方法(not equal)或者__eq__方法取反,虽然没有写这个方法,但只要具有__eq__方法后取反的效果是一样的。

加入代码:

def __ne__(self,other):

return ‘hello

整理代码内容:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

def __ne__(self,other):

returnhello

p1 = Preson(zhangsan’,18)

p2 = Person(zhangsan’,18)

print(p1 is p2)

print(p1 ==p2)

print(p1 !=p2)

运行之后:

!=运算就是调用__ne__方法的结果,如果没写这个方法。它就会找到__eq__方法取反来返回这个值。!=运算符会自动调用__ne__这个方法。默认都不写的时候,会比较内存地址

2)加入 print(p1 >p2)

新加入一个对象 p3 = print(lisi,19)

此时,运行结果如下:

会报错,它不支持写 p1>p2

需要添加

def __gt__(self,other):

return self.age > other.age

greater than 使用 > 会自动调用上面的方法

还有__ge__(selfother)方法,它是大于等于时会自动调用。

举一个例子:

num1 = [1,2,3]

num2 = [1,2,3]

print(num1 == num2)

这个用来判断两个之间的内容相等,但是系统自带的,会重写列表。重写的话就会指定规则,在机器上,不管写没写__ge__方法或__gt__方法,都会自动调用,但是不写就调用的话会报错。

如果不写就不能比较。3>2可以的原因是它们的类型是 int,再 class int 里实现了这些方法就可以使用。自定义的类,没有实现方法就使用那么就会报错。

在字典中比较,加入语句{name:zhangsan} >{name:jack}

运行结果为:

字典之间不能用>运算,原因是系统中的dict的类,没有重写机器代码的类,内部写的__gt__方法存在漏洞。

修改{name:zhangsan} >{name:jack}{name:zhangsan} >lisi‘,运行结果依旧报错。

在字典和字典之间重写了这个方法,这可能是有不同类型的比较是不可行的。

修改为{age:18} >12,得运行结果为:

依旧是不可以比较的。机器重写得这个方法应该是满足某些条件是可以比较的

代码具体得写法,是有自己的内部实现。

加入 print(p1 > 20),这样的写法会在运行时报错。原因是原来的 print(p1 >p2)是比较两个对象,原来的 p1.agep2.age 进行的比较,给的是20的话,这个数字是不具备 age 属性的。所以具体的实现和报错,是由内部实现来决定的。

如果把__gt__方法的返回值改为 return self.age > other,写成 print(p1 > 12)就是可以的,这跟内部的实现有关。

运行结果如下:

就是把 p1age 传给 self.age12直接传给 other,然后两者直接进行比较。自己写代码时,内部的实现究竟是怎样的是自己决定的。不需要管系统的内部是如何实现的,它的实现还是要依赖内部的逻辑是什么,只要知道原理即可。

3)小于运算

只要写小于号就会调用 def __it__(self,other):less than p1<p2

def __le__(self,other):这个是小于等于。这几个运算,当需要用到哪一个时,都会调用相应的运算。print(p1 >p2)中是传一个12还是一个 p2

这个要看内部实现里面怎样的逻辑,如果是方法的返回值要拿到 other.age,这个对象就必须要有 age 属性;如果返回值是一个 other 那么就选择写12;后面比较的值会传给 other

4)需要 p1p2,单运行的话它是不支持的需要添加方法

def __add__(self,other):

return self.age+other.age

print(p1+p2)

整理代码为:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

(5)p1-p2

加入代码:

def __sub__(self,other):

return self.age other

print(p1p2)

在方法中写的是年龄相加那么就执行年龄相加,如果是姓名就是姓名相加。

减法中不能 print(p1 p2)这样写,减法中返回的是对象,一删就会删掉对象,运行代码时会出错,所以 print(p1 p2)p2的所在位置只能写数字

整理代码为:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

最后到底是加一个对象还是数字,关键是在于内部的代码是如何实现的。

在学习中,一切都是有迹可循的,为什么字符串和字符串在这可以加,在那不可以加,原因就是这样。在做方法实现的时候,就会体现什么可以加,什么不可以加。

6__mul__乘法

def __mul__(self,other):

return self.name * other

print(p1 * 2)

(7)除法 def __truediv__(),除了前面讲过的之外,还有一些

取模运算:

def __mod__(self,other):

return self.age % other

幂运算:会自动调用

def __pow__(self,other):

return self.age ** other

整理代码为:

class Person:

def __init__(self,name,age):

自定义所需要进行的运算以及运算的规则,例如允许做加法运算,写上代码后在做规则约束


三、  转换为字符串  

print(str(p1))默认会转换成为类型+内存地址

str()将对象转换成为字符串,会自动调用__str__方法

1.   类型转换时会调用str()str(p1)

2.   直接打印对象也会调用,print(str(p1))

def __str__(self):

returnhello

x = str(p1)

print(x)

整理代码为:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

def __ne__(self,other):

类型转换就是把一个数据转换成字符串,依旧会调用__str__方法并返回它的结果。

还可以转换为数字,比如加入 print(int(p1)),把 int(1234)转换为1234,此时运行会报错。

报错的原因是,当 int(),会调用__int__的结果

加入

def __int__(self):

return 20

这些方法的调用都是魔法方法,除了这些之外还可以加入 print(float(p1)),运行后结果会报错。也是加入一个方法 def __float__(self):

return 100.5

整理代码为:

class Person:

def __init__(self,name,age):

self.name = name

self.age = age

def __eq__(self,other):

return self.name == other.name and self.age == other.age:

def __ne__(self,other):

return hello

def __gt__(self,other):

return self.age > other.age

def __add__(self,other):

p1 = Preson(zhangsan’,18)

p2 = Person(zhangsan’,18)

p3 = print(‘lisi,19)

运行后的结果为:

image.png

Python 语言是非常灵活且强大的,通过本次代码的编写,可以窥探出编程语言是如何做的,它的本质到底是怎么实现的。

掌握的好的话,可以自己写一个编程语言,在学习之后可以知道 python 语言是怎么实现的。

比如写了一个 int(hello)

就是调字符串:

class str:

def __int__(self):

Return

先调用 int,后打印出 hello

如果是 print(int(p1))只调用__int__方法,没有调用到__str__方法,只有 print(p1)才能够调用__str__方法。

这些内容需要了解,它涉及 python 语言的思想。这个还要区分好内置类和内置函数,在这里用内置类进行的调用转换。

相关文章
|
存储 安全 C++
C++ 类 & 对象初学者学习笔记
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。
91 0
|
设计模式 算法 关系型数据库
关于本人对学习知识的方法的理解
关于本人对学习知识的方法的理解
69 1
|
运维 Kubernetes 虚拟化
结课(有方法,请注意) | 学习笔记
快速学习结课(有方法,请注意)
结课(有方法,请注意) | 学习笔记
|
Java Scala 开发者
方法|学习笔记
快速学习方法。
方法|学习笔记
|
存储 PHP 开发者
类内部对象|学习笔记
快速学习类内部对象
类内部对象|学习笔记
|
Java 编译器 PHP
C++学习笔记1:类的使用
C++学习笔记1:类的使用1. 类的定义与使用2. 类的成员变量和成员函数3. 构造函数4. 析构函数5.5 友元函数和友元类
115 0
C++学习笔记1:类的使用
|
网络协议 程序员 测试技术
方法介绍和使用|学习笔记
快速学习方法介绍和使用
|
JSON 数据格式 开发者
方法的封装| 学习笔记
快速学习方法的封装
|
网络协议 编译器 测试技术
方法和函数区别说明|学习笔记
快速学习方法和函数区别说明
|
Java 开发者
大数字处理类|学习笔记
快速学习大数字处理类
133 0
大数字处理类|学习笔记