python常用的魔法方法(双下划线)
作者:程序媛小庄 发布时间:2022-08-01 23:23:37
目录
前言
魔法方法
__init__方法
__new__方法
__call__方法
__str___方法
__del___方法
__enter__ & __exit__方法
item系列方法
attr系列方法
单例模式
模块导入的方式
通过__new__方法
自定义元类的方式
结语
前言
本文介绍一下python中常用的魔法方法以及面向对象中非常重要的单例模式。
魔法方法
python中一切皆对象,因为python是面向对象的编程语言。python给类和对象提供了大量的内置方法,这些内置方法也称魔法方法。这些魔法方法总是在某种条件下自动触发执行,就像魔法一样。
__init__方法
该方法是用来接收定义类时类中__new__方法返回的空对象后为空对象进行初始化的操作,没有返回值。
class Test():
def __init__(self, name):
self.name = name
def test(self):
print(self.name)
t = Test('xu')
t1 = Test('python')
__new__方法
该方法是当类被调用实例化对象时首先被触发的方法,用来实例化一个空对象并返回。
class Test():
def __new__(cls,*args, **kwargs):
return object.__new__(cls, *args, **kwargs)
def __init__(self, name):
self.name = name
__call__方法
如果想让一个对象变成一个可调用对象(加括号可以调用),需要在该对象的类中定义__call__方法,调用可调用对象的返回值就是__call__方法的返回值。
class Test():
def __init__(self):
self.name = 'python'
def __call__(self, *args, **kwargs): # self是Test类的对象
print(self) # <__main__.Test object at 0x000001C78CE78FD0>
print(self.name)
t = Test()
t() # python
__str___方法
当对象被访问打印时触发执行,该方法必须有一个字符串类型的返回值。
class Test():
def __init__(self, name):
self.name = name
def __str__(self):
return self.name
t = Test('xu')
print(t1) # xu
__del___方法
__del__方法是在对象被删除时自动触发,由于python的垃圾回收机制会自动清理程序中没用的资源,因此如果一个对象只是占用应用程序的资源,没有必要定义__del__方法,但是如果设计到占用系统资源的话比如打开的文件对象,由于关系到操作系统的资源,python的垃圾回收机制派不上用场的时候,就需要为对象创建__del__方法,用于对象被删除后自动触发回收操作系统资源。
class Test:
def __init__(self):
self.x = open('a.txt',mode='w')
# self.x = 占用的是操作系统资源
def __del__(self):
print('run')
# 发起系统调用,告诉操作系统回收相关的系统资源
self.x.close()
obj = T()
del obj # obj.__del__()
__enter__ & __exit__方法
使用with上下文管理时,会触发对象中的__enter__方法,并将__enter__方法的返回值赋值给as声明的变量。
with语句正常结束的时候会触发__exit__方法,该方法的三个参数分别代表异常类型、异常值和溯源信息,如果with语句代码块出现异常,则with语句后的代码都不会被执行,但是如果该方法返回值为True,异常会被清空,with代码块后的代码还会被正常执行。代码如下:
class Open:
def __init__(self):
self.name = 'open'
def __enter__(self):
print('with语句执行时会首先执行的方法,返回值会赋值给as声明的变量')
return self.name
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中的代码块执行完毕时执行exit')
print(exc_type, '如果出现异常表示异常类型')
print(exc_val, '表示异常的值')
print(exc_tb, '表示异常的溯源信息')
return 123 # 非零 非空 非None为真
with Open() as test:
print(test)
raise TypeError('看一下错误信息')
print('我会不会被执行呢') # 当__exit__方法返回值为真时,会被执行,否则不会被执行
item系列方法
item系列方法包括__setitem__、__getitem__、delitem__方法,这三种方法分别会在中括号赋值/修改值、中括号取值、中括号删除值时触发,比如可以自定义一个字典类,并自定义中括号赋值、取值、删除值的方法:
class MyDict(dict):
def __setitem__(self, key, value):
print('执行setitem', key, value) # 执行setitem, x, 1
self.__dict__[key] = value
def __getitem__(self, item):
print('执行getitem', item) # 执行getitem x
print(self.__dict__[item]) # 1
def __delitem__(self, key):
print('执行delitem', key) # 执行delitem x
self.__dict__.pop(key)
d = MyDict()
d['x'] = 1
print(d['x'])
del d['x']
attr系列方法
attr系列方法包括__setattr__,__getattr__,__delattr__,__setattr__在添加/修改属性时会触发,___delattr__删除属性的时候触发,__getattr__在使用.调用属性并且属性不存在时触发。如下代码所示
class Test:
def __init__(self):
self.name = 'python'
def __setattr__(self, key, value):
print('添加/修改属性setattr')
self.__dict__[key] = value
# self.key = value # 会出现无线递归,因为对象.属性会调用__setattr__方法
def __delattr__(self, item):
print('删除属性delattr')
self.__dict__.pop(item)
def __getattr__(self, item):
print('属性不存在时调用getattr')
t = Test()
t.x = 'x'
print(t.y)
del t.x
单例模式
单例模式是一种软件设计模式,为了保证一个类无论调用多少次产生的对象都指向同一个内存地址,即仅仅只有一个对象。
实现单例模式的方式有很多,总的原则就是保证一个类只要实例化一个对象,因此关键点就是如何判断这个类是否实例化过一个对象。
这里介绍几种实现方式,供大家参考:
模块导入的方式
这种方式的原理是模块导入后只运行一次,后面再次使用该模块中的类是直接从内存中查找。
# cls_singleton.py
class Foo(object):
pass
instance = Foo()
# test.py
import cls_singleton
obj1 = cls_singleton.instance
obj2 = cls_singleton.instance
print(obj1 is obj2) # True
通过__new__方法
原理就是判断类是否有实力,有就直接返回,没有就保存到_instance中
class Test:
_instance = None
def __init__(self, name, age):
self.name = name
self.age = age
def __new__(cls, *args, **kwargs):
# if cls._instance:
# return cls._instance # 有实例则直接返回
# else:
# cls._instance = super().__new__(cls) # 没有实例则new一个并保存
# return cls._instance # 这个返回是给是给init,再实例化一次,也没有关系
if not cls._instance: # 这是简化的写法,上面注释的写法更容易提现判断思路
cls._instance = super().__new__(cls)
return cls._instance
t1 = Test('python', 18)
t2 = Test('python1', 18)
print(t1 is t2) # True
自定义元类的方式
这种方式的原理是类调用的过程,类定义时会调用元类下的__init__,类调用(实例化对象)时会触发元类下的__call__方法。
class Mymeta(type):
def __init__(cls, name, bases, dic):
super().__init__(name, bases, dic)
cls._instance = None # 将记录类的实例对象的数据属性放在元类中自动定义了
def __call__(cls, *args, **kwargs): # 此call会在类被调用(即实例化时触发)
if cls._instance: # 判断类有没有实例化对象
return cls._instance
else: # 没有实例化对象时,控制类造空对象并初始化
obj = cls.__new__(cls, *args, **kwargs)
obj.__init__(*args, **kwargs)
cls._instance = obj # 保存对象,下一次再实例化可以直接返回而不用再造对象
return obj
class Test(metaclass=Mymeta):
def __init__(self, name, age):
self.name = name
self.age = age
t1 = Test('python', 18)
t2 = Test('python1', 18)
print(t1 is t2) # True
结语
来源:https://juejin.cn/post/6987254150446710815
猜你喜欢
- 如何实现自定义一个异常python内置了许多异常类,为编写代码划定红线,才使调试代码时能及时发现错误。那么我们编写一个模块也可以为使用此模块
- 以前大家谈了很多有关打开数据库连接安全的问题,现在我再提出一种思路:使用activex dll来保护你的代码。(既可以不用为使用共享的加密软
- 前言本文主要给大家介绍的关于Python批量压缩png的相关资料,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:1.需求为什
- Python下实现定时任务的方式有很多种方式。下面介绍几种循环sleep:这是一种最简单的方式,在循环里放入要执行的任务,然后sleep一段
- 平时见到的url参数都是key-value, 一般vlaue都是字符串类型的如果有幸和我一样遇到字典,列表等参数,那么就幸运了python2
- 使用tensorflow过程中,训练结束后我们需要用到模型文件。有时候,我们可能也需要用到别人训练好的模型,并在这个基础上再次训练。这时候我
- 本文实例为大家分享了基于wxPython的GUI实现输入对话框的具体代码,供大家参考,具体内容如下编程时,免不了要输入一些参数等,这时输入对
- 我就废话不多说了,直接上代码吧!#Copyright (c)2017, 东北大学软件学院学生# All rightsreserved#文件名
- 要用django的orm表达sql的exists子查询,是个比较麻烦的事情,需要做两部来完成from django.db.models im
- 1.Beautiful Soup库简介Beautiful Soup 简称 BS4(其中 4 表示版本号)是一个 Python 中常用的页面解
- PyQt5切换按钮控件QPushButton简介QAbstractButton类为抽象类,不能实例化,必须由其他的按钮类继承QAbstrac
- 一、http请求1、http请求方式:get和postget一般用于获取/查询资源信息,在浏览器中直接输入url+请求参数点击enter之后
- 1、DOMWEB标准现在可真是热门中热门,不过下面讨论的是一个不符合标准的document.all[]。DOM--DOCUMENTOBJEC
- 这个decorator是什么意思呢?很简单,它接受一个log的参数,即传入logger对象。然后它会先把函数名打印出来,接下来,会利用enu
- 原始两张图片:代码运行结果如下。5种算法值哈希算法、差值哈希算法和感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的
- 数据库操作类在网上一搜一大把,我这并不比那些好,只是是自己写的,用着更习惯。所以我这个类没有什么特别的地方,只是自己用着习惯罢了,至于效率等
- 简单介绍NumPy系统是Python的一种开源的数组计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested
- 本文实例讲述了Python实现配置文件备份的方法。分享给大家供大家参考。具体如下:这里平台为Linux:#!/usr/bin/python#
- 本文实例讲述了Python使用re模块正则提取字符串中括号内的内容操作。分享给大家供大家参考,具体如下:直接上代码吧:# -*- codin
- 本文实例讲述了JS实现淡入淡出图片效果的方法。分享给大家供大家参考,具体如下:效果:鼠标移入时,图片由半透明逐渐变成清晰,移出时,由清晰变为