__init__&__del__&__str__&__repr__&__call__魔法介绍 | 学习笔记

简介: 快速学习__init__&__del__&__str__&__repr__&__call__魔法介绍

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

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


__init__&__del__&__str__&__repr__&__call__魔法介绍


内容介绍:

一、魔法方法简介

二、__init__& 方法

三、__del__方法

四、__str__方法和__repr__方法

五、__call__方法

 

一、魔法方法简介

魔法方法,也叫魔术方法,是类里的特殊的一些方法。

特点:

1. 不需要手动调用,会在合适的时机自动调用。而合适的时机是需要掌握的,它是不需要手动调用的但如果需要可以是手动调用的,一般不会手动调用,在后面的学习中会写到手动调用。

2.这些方法,都是使用__开始,使用__结束。

3.方法名都是系统规定好的,在合适的时机自动调用。就是这个名字得写好,写好才能在合适的时机自动调用,不可以瞎写

 

二、__init__& 方法

注意:

1._ init _() 方法在创建对象时,会默认被调用,不需要手动的调用这个方法。

2._ init _() 方法里的 self 参数,在创建对象时不需要传递参数,python 解释器会把创建好的对象引用直接赋值给 self

3.在类的内部,可以使用 self 来使用属性和调用方法;在类的外部,需要使用对象名来使用属性和调用方法法。

4.如果有多个对象,每个对象的属性是各自保存的,都有各自独立的地址。

5.方法是所有对象共享的,只占用一份内存空间,方法被调用时会通过 sell 来判断是哪个对象调用了实例方法。

新建一个 python 文件命名为 08- 魔法方法,书写代码。

在创建对象时,会自动调用这个__init__方法

以下为代码内容:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

p = Person(‘zhangsan’,18)

运行结果为:

结果可以看到这个函数被调用后得到的结果

 

三、__del__方法

有创建对象的就会存在删除对象的函数,就是__del__方法。

在对象被销毁时,会自动调用这个__def__方法

创建对象后,python 解释器默认调用_ init _()方法;

而当删除对象时,python 解释器也会默认调用一个方法,这个方法为_ de l_() 方法。

以下为代码内容:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

p = Person(‘zhangsan’,18)

运行结果为:

结果可以看到这两个函数都被调用

此时并没有删除对象,但依旧被销毁了。原因是,程序结束了,它申请的所有内存是都已经结束,它自己会终结自己。向代码中最后加入 time.sleep() 函数(注意导包)进行休息。此时代码整体修改为

import time

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

p = Person(‘zhangsan’,18)

time.sleep(10)

运行结果为:

刚开始运行后结果为下图

image.png

等待十秒后,程序结束。会自动删掉新对象。

也可以选择手动销毁,在创建的对象后面,直接加入语句 delp。创建对象语句执行完后会立即销毁,会调用销毁函数完成。

代码整体为:

import time

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

p = Person(‘zhangsan’,18)

del p

time.sleep(10)

运行结果为:

创建之后立即销毁,此时程序还未结束。

等待十秒完成 sleep 函数之后,程序结束。

__del__方法就是销毁对象时会调用,__init__方法用的较多

 

四、__str__方法和__repr__方法

(1) __str__方法返回对象的描述信息,使用 print() 函数打印对象时,其实调用的就是这个对象的__str__方法。

先打印 p,加入语句 print(p)。如果不作任何修改,直接打印一个对象,是对象的类型以及内存地址,准确的来说,是对象得模块名.类型。更加贴切得来讲是文件的__name__.类型 内存地址。

代码内容为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

p = Person(‘zhangsan’,18)

print(p)

运行结果为:

会打印出 p 的类型是 Person 类,以及会打印出对应得内存地址。

__main__是这个 p 得模块名,直接运行就是__main__

在开发的时候,大多数打印这个对象并不是为了打印出它的文件类型和内存地址。

例如想打印 p,但要求是输出的是这个人的名字以及年龄,可以通过使用__str__或者__repr__方法来改变打印出来的结果。语句 print(p.name,p.age) 是可以的,但在这用另一种方式。

(2) 当打印一个对象的时候,会调用这个对象的__str__或者__repr__方法

代码内容为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

def __repr__(self)

return ‘hello’

p = Person(‘zhangsan’,18)

print(p)

运行结果为:

发现要求打印的是 p,但打印出来的是 hello ,在这里是 p 自动调用了__repr__方法并打印出了函数返回值内容。

(3)除了调用__repe__,还可以是__str__方法,加入函数。

代码内容为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

运行结果为:

此时,并没有运行__repr__函数,说明当两个函数都存在时,只运行__str__函数。

有一个内置函数名为 repr()

加入语句 print(repr({‘name’:’zhangsan’,’age’:18}))

这个语句本身是一个字典,加入 repr 语句中就会变为一串字符串“{‘name’:’zhangsan’,’age’:18}“。

repr 语句中放入的字典,它本质上就是找字典的下划线__repr__方法。

(4)现在如果想调用 repr 的方法可以按下面的讲解来完成。之前所说的是魔术方法属于自动调用方法,在这里可以手动调用方法,删掉刚刚的 repr 语句,加入 print(repr(p)) 语句

此时代码内容为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

运行结果为:

结果中会调用 repr 方法得到 hello 结果。

大多数情况下,在 repr 语句中加入一个对象,就是代表找到这个对象的 repr 方法。

除了加入 print(repr(p)) 的方式,还可以再加入 print(p.__repr__())

总之,魔法方法一般不直接调用,但是是可以直接调用的。在调用内置函数 repr 会触发对象的__repr__方法。一般情况下,选择__str__或者__repr__方法都可以。

在这个例子中要想打印出名字和年龄,就需要语句 return ‘姓名:{},年龄:{}’.format(self.name,self.age),继续选择打印 p。

整体代码变为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

def __repr__(self)

return ‘姓名:{},年龄:{}’.format(self.name,self.age)

运行结果为:

可以书写__str__或者__repr__方法都可以。

(4)这两个方法的区别:

使用__str__和__repr__方法,都会修改一个对象转换成为字符串的结果。一般来说,__str__方法的结果更加在意可读性,而__repr__方法的结果更加在意正确性(例如: datetime 模块里的 datellime 类)

举例:加入语句

import datatime

datatime.datatime

点进后面的 datatime 进入发现,它是一个类,就可以创建它们,使用__init__来创建。

加入语句 x = datatime.datatime() ,通过点进了 datatime 中可以看到这个代码需要年、月、日、时、分、秒以及毫秒这些数据。在这里成 x = datatime.datatime(2020,2,24,26,17,45,200),并加入 print(x) 语句。

在 datatime 模块中,这个两种方法都写的有。print(x) 调用的时__str__方法,而 print(repr(x)) 调用的是__repr__方法。如果调用__str__方法它的可读性更好,更加方便。

但如果调用的是__repr__方法,它读出来的就更加精确。在写的过程中,两个方法选一个就好,选__str__方法或是__repr__方法都是可行的。也可以两个都写,在 datatime 中就是两个都写了。


五、__call__方法

p 是指一个对象,现在写成 p() ,小括号是当成函数来调用现在这个 p 就是个函数。

写 repr 可以直接调用,用手动调用,但直接打印是调用 str 方法

1)直接加入代码 p()

源代码变为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.age = age

运行结果如图:

可以看到会报错,它还不是函数,此时运行会崩掉。运行后的结果显示是不可以被调用的。

(2) 类似的如果把 p() 换成 a = ’hello’a () 语句,会显示有同样的错误。

代码更改后为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

运行结果如下图:

会告知字符串是不可以被调用的

(3)函数是可以调用的,写一段函数,使 p 也可以被调用

增加以下语句:

def __call__(self,*args,**kwargs):

print(‘__call__方法被调用’)

p = Person(‘zhangsan’,18)

print(p)

p()

此时运行代码,结果如下图:

此时不会报错并且是可以调用到 call 方法

image.png

其实对象名 ()==> 调用这个对象的__call__方法,括号里还可以传参数,例如将代码修改为 p(1,2),此时在运行依旧不会报错。原因是写的 p.__call__(1,2) 方法,这个函数中写的都是可变参数。

将代码继续修改为 p(1,2,fn=lambda x,y:x+y) ,要想到处 lambda 数据需要以下步骤。

这个中的 1 和 2,有方法中可以知道,args 是一个元组,保存 (1,2),kwargs 是一个 字典,里面存的就是 {fn:lambda x,y:x+y}

(4) 加入语句

print(‘args={},kwargs={}’.format(args,kwargs))

(5)现在要想实现一个加法的操作,方法如下:

需要先拿到函数,利用语句 fn = kwargs[‘fn’]

在提取 args 当中的第零个、第一个,用语句 fn(args[0],args[1])Fn 通过字典拿到函数,在传进去两个参数,参数从 args 中获取,最后再把获取到的值返回

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

print(‘__del__方法被调运了’)

def __repr__(self)

return ‘hello’

def __str__(self)

return ‘姓名:{},年龄:{}’.format(self.name,self.age)

def __call__(self,*args,**kwargs):

print(‘args={},kwargs={}’.format(args,kwargs))

fn = kwargs[‘fn’]

return fn(args[0],args[1])

p = Person(‘zhangsan’,18)

print(p)

n = p(1,2,fn=lambda x,y:x+y)

print(n)

此时运行代码,结果如下图:

image.png

这些内容都是前面所提到过的,在这里进化了以下,变成了面向对象编程语法。

所传进去的 1、2 是放在了 args 的元组中,而传的关键字 lambda 会当成一个字典传给 kwargs,这个传进去是一个 fn,一个函数;调用的过程就是先通过字典拿到数据,在通过函数进行调用。两个参数都是从 args 中获取。

把对象当成一个函数调用这种写法是有的,但是不多,一般用在装饰器,以前的装饰器都是由函数作为。这代码中都是 fn 参数,它没有重名的问题。

为了更好的理解,将 fn 更改名字为 test,代码内容变为:

class Person(object):

def __init__(self,name,age):

print(‘__init__方法被调运了’)

self.name = name

self.age = age

def __del__(self):

print(‘__del__方法被调运了’)

def __repr__(self)

return ‘hello’

def __str__(self)

return ‘姓名:{},年龄:{}’.format(self.name,self.age)

def __call__(self,*args,**kwargs):

print(‘args={},kwargs={}’.format(args,kwargs))

test = kwargs[‘fn’]

return test(args[0],args[1])

p = Person(‘zhangsan’,18)

print(p)

n = p(1,2,fn=lambda x,y:x+y)

print(n)

这个是不具有重名的问题,当传过去的时候 fn 对应得是一个函数,它在这里面是一个字符串。

这个 fn 字典通过 key 获得 value 函数,其实也可以不需要加上函数名直接return kwargs[‘fn’](args[0],args[1])。它就是一个拿到对应得函数进行调用得一个过程。

这些高级语言了解即可,把一个对象当作函数是可以调用的,可以传任意的参数,按照处理的不同方式来选择参数。逻辑是根据业务需求来写的,把一个对象当作函数是调用的语法关键是在于传参,以及之后的处理都是要根据业务逻辑来进行处理的。



相关文章
|
2月前
|
Unix Go
cast.ToString(time.Now().Unix())这样不可以吗
cast.ToString(time.Now().Unix())这样不可以吗
|
3月前
|
SQL Oracle 关系型数据库
深入解析 NOW() 与 CURRENT_DATE() 的区别
【8月更文挑战第31天】
126 0
|
6月前
|
SQL 存储 关系型数据库
【Mysql】The DATE, DATETIME, and TIMESTAMP Types
【Mysql】The DATE, DATETIME, and TIMESTAMP Types
79 0
|
6月前
|
SQL 存储 关系型数据库
【Mysql】The DATE, DATETIME, and TIMESTAMP Types(一)
【Mysql】The DATE, DATETIME, and TIMESTAMP Types
47 0
【Mysql】The DATE, DATETIME, and TIMESTAMP Types(一)
|
6月前
|
存储 关系型数据库 MySQL
【Mysql】The DATE, DATETIME, and TIMESTAMP Types(二)
【Mysql】The DATE, DATETIME, and TIMESTAMP Types
67 0
【Mysql】The DATE, DATETIME, and TIMESTAMP Types(二)
|
关系型数据库 MySQL PostgreSQL
PSQLException: 错误: 函数 date_format(timestamp without time zone, unknown) 不存在
PSQLException: 错误: 函数 date_format(timestamp without time zone, unknown) 不存在
303 0
|
机器学习/深度学习 测试技术 Python
Python date,datetime,time等相关操作总结
Python date,datetime,time等相关操作总结
122 0
|
存储 关系型数据库 MySQL
MySQL中date、datetime、timestamp、time、year的区别
MySQL中date、datetime、timestamp、time、year的区别
178 0
|
开发者 Python
Is&isinstance&issbuclass 的使用 | 学习笔记
快速学习 Is&isinstance&issbuclass 的使用
Is&isinstance&issbuclass 的使用 | 学习笔记