Python面向对象魔法方法和单例模块代码实例
作者:jueyuanfengsheng 发布时间:2023-05-02 19:03:16
魔法方法
凡是在类内部定义,以“__开头__结尾”的方法都称之为魔法方法,又称“类的内置方法”, 这些方法会在某些条件成立时触发。
经常用到的双下方法
__init__: 在调用类时触发。
__delarttr__:
__getattr__: 会在对象.属性时,“属性没有”的情况下才会触发。对象.__dict__[属性]不会触发__getattr__,会报keyerror;
__getattribute__:会在对象.属性时触发,不管有没有该属性都会触发;
__setattr__: 会在 “对象.属性 = 属性值” 时触发。即:设置(添加/修改)属性会触发它的执行;
__del__: 当对象在内存中被释放时,自动触发执行,该方法会在最后执行。
class Uderline_func:
x = 100
def __init__(self, y):
print('类加括号调用的时候触发我!')
self.y = y # 当与__setattr__方法同时存在时,self.y = y并不会被加载到对象的名称空间
# self['y'] = y # TypeError: 'Uderline_func' object does not support item assignment
def general_func(self):
print('随便定义的一个函数!')
# def __getattr__(self, item):
# print('只有对象获取一个没有的属性值得时候触发我!')
def __getattribute__(self, item):
print('类或对象无论获取的属性有没有都会触发我!且出现我,对象点一个没有的属性会覆盖掉__getattr__,还会导致__setattr__函数报错')
def __setattr__(self, key, value):
print('设置属性的时候触发我!')
# self.a = '在对象名称空间增加一个值!' # 会一直触发__setattr__,出现递归调用
self.__dict__['a'] = '在对象名称空间增加一个值!'
def __delattr__(self, item):
print('删除值得时候触发我!')
def __del__(self):
print('程序运行完,被Python解释器回收时,触发我!')
# print(Uderline_func.__dict__) # 类在定义阶段就已经创建好了类名称空间,将其内部变量名和函数名塞进去
u = Uderline_func(100) # 触发__init__
# print(u.__dict__) # {'y': 100}
# Uderline_func.z # 只会触发__getattribute__
u.z # 获取没有的属性触发__getattr__
# u.name = 'zhang' # 触发__setattr__
# del u.x # 对象不能删除掉类中的属性,但只要执行删除操作,都会触发__delattr__的执行
__str__: 会在打印对象时触发。
__call__: 会在对象被调用时触发。
__new__: 会在__init__执行前触发。
class Uderline_func():
x = 100
# def __new__(cls, *args, **kwargs):
#
# print('在__init__执行之前触发我,造一个空对象!')
def __init__(self):
print('类加括号调用的时候触发我!')
def __call__(self, *args, **kwargs):
print('对象加括号调用的时候触发我!')
def __str__(self):
print('对象被打印的时候触发我!')
return '必须要写return返回一个字符串!不然报错"TypeError: __str__ returned non-string (type NoneType)"'
u = Uderline_func()
u()
print(u)
__setitem__,__getitem,__delitem__
class Foo:
def __init__(self,name):
self.name=name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
self.__dict__[key]=value
# self.age = value # 也可以给对象添加属性
def __delitem__(self, key):
print('del obj[key]时,我执行')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,我执行')
self.__dict__.pop(item)
f1=Foo('sb')
f1['age']=18
# print(f1.__dict__)
f1['age1']=19
# del f1.age1
# del f1['age']
f1['name']='alex'
f1.xxx = 111
print(f1.__dict__) # {'name': 'alex', 'age': 18, 'age1': 19, 'xxx': 111}
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代
实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。 更多的是用来作为一个内存优化工具。
class Foo:
__slots__ = 'x'
f1 = Foo()
f1.x = 1
f1.y = 2 # 报错
print(f1.__slots__) # f1不再有__dict__属性
print(f1.x) #依然能访问
class Bar:
__slots__ = ['x', 'y']
n = Bar()
n.x, n.y = 1, 2
n.z = 3 # 报错
__doc__:查看类中注释
class Foo:
'我是描述信息'
pass
print(Foo.__doc__)
class Foo:
'我是描述信息'
pass
class Bar(Foo):
pass
print(Bar.__doc__) #该属性无法继承给子类
__module__和__class__
__module__:表示当前操作的对象在那个模块
__class__:表示当前操作的对象的类是什么
class C:
def __init__(self):
self.name = ‘SB'
from lib.aa import C
obj = C()
print obj.__module__ # 输出 lib.aa,即:输出模块
print obj.__class__ # 输出 lib.aa.C,即:输出类
__enter__和__exit__
我们知道在操作文件对象的时候可以这么写
with open('a.txt') as f:
'代码块'
上述叫做上下文管理协议,即with语句,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
# return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
with Open('a.txt') as f:
print('=====>执行代码块')
# print(f,f.name)
'''
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊
'''
exit()中的三个参数分别代表异常类型,异常值和追溯信息,with语句中代码块出现异常,则with后的代码都无法执行
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->不会执行
'''
出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊
<class 'AttributeError'>
***着火啦,救火啊***
<traceback object at 0x000000000A001E88>
Traceback (most recent call last):
File "G:/Python代码日常/第一阶段/1阶段/面向对象/test.py", line 52, in <module>
raise AttributeError('***着火啦,救火啊***')
AttributeError: ***着火啦,救火啊***
'''
如果__exit()返回值为True,那么异常会被清空,就好像啥都没发生一样,with后的语句正常执行
class Open:
def __init__(self,name):
self.name=name
def __enter__(self):
print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量')
def __exit__(self, exc_type, exc_val, exc_tb):
print('with中代码块执行完毕时执行我啊')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Open('a.txt') as f:
print('=====>执行代码块')
raise AttributeError('***着火啦,救火啊***')
print('0'*100) #------------------------------->会执行
class Open:
def __init__(self,filepath,mode='r',encoding='utf-8'):
self.filepath=filepath
self.mode=mode
self.encoding=encoding
def __enter__(self):
# print('enter')
self.f=open(self.filepath,mode=self.mode,encoding=self.encoding)
return self.f
def __exit__(self, exc_type, exc_val, exc_tb):
# print('exit')
self.f.close()
return True
def __getattr__(self, item):
return getattr(self.f,item)
with Open('a.txt','w') as f:
print(f)
f.write('aaaaaa')
f.wasdf #抛出异常,交给__exit__处理
用途或者说好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
单例模式
单例模式:多次实例化的结果指向同一个实例
方式1
# @classmethod(用类绑定方法)
import settings
class MySQL:
__instance=None
def __init__(self, ip, port):
self.ip = ip
self.port = port
@classmethod
def from_conf(cls):
if cls.__instance is None:
cls.__instance=cls(settings.IP, settings.PORT)
return cls.__instance
obj1=MySQL.from_conf()
obj2=MySQL.from_conf()
obj3=MySQL.from_conf()
# obj4=MySQL('1.1.1.3',3302)
print(obj1)
print(obj2)
print(obj3)
# print(obj4)
方式2
# 用类装饰器
import settings
def singleton(cls):
_instance=cls(settings.IP,settings.PORT)
def wrapper(*args,**kwargs):
if len(args) !=0 or len(kwargs) !=0:
obj=cls(*args,**kwargs)
return obj
return _instance
return wrapper
@singleton #MySQL=singleton(MySQL) #MySQL=wrapper
class MySQL:
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj=MySQL('1.1.1.1',3306) #obj=wrapper('1.1.1.1',3306)
# print(obj.__dict__)
obj1=MySQL() #wrapper()
obj2=MySQL() #wrapper()
obj3=MySQL() #wrapper()
obj4=MySQL('1.1.1.3',3302) #wrapper('1.1.1.3',3302)
print(obj1)
print(obj2)
print(obj3)
print(obj4)
方式3
# 调用元类
import settings
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
#self=MySQL这个类
self.__instance=self(settings.IP,settings.PORT)
def __call__(self, *args, **kwargs):
# self=MySQL这个类
if len(args) != 0 or len(kwargs) != 0:
obj=self.__new__(self)
self.__init__(obj,*args, **kwargs)
return obj
else:
return self.__instance
class MySQL(metaclass=Mymeta): #MySQL=Mymeta(...)
def __init__(self, ip, port):
self.ip = ip
self.port = port
obj1=MySQL()
obj2=MySQL()
obj3=MySQL()
obj4=MySQL('1.1.1.3',3302)
print(obj1)
print(obj2)
print(obj3)
print(obj4)
方式4
# 利用模块多次导入只产生一次名称空间,多次导入只沿用第一次导入成果。
def f1():
from singleton import instance
print(instance)
def f2():
from singleton import instance,My
SQL
print(instance)
obj=MySQL('1.1.1.3',3302)
print(obj)
f1()
f2()
来源:https://www.cnblogs.com/zhangchaocoming/p/11706501.html


猜你喜欢
- 可匹配结构:今天~前天, 几天前, 分钟秒前等 | 2017-1-4 12:10 | 2017/1/4 12:10 | 2018年4月2日
- 有个朋友要求帮忙绘制堆叠柱状图,查阅了一些文档之后也算是完成了,只是一个小demo,下面我就记录一下。1.什么是堆叠柱状图与并排显示分类的分
- 安装Pytorch在pytorch官网上选择相应选项,我的是OS X, pip, python2.7, none CUDA。(之所以用pyt
- 前言在学习操作系统的时候,我们应该都学习过临界区、互斥锁这些概念,用于在并发环境下保证状态的正确性。比如在秒杀时,100 个用户同时抢 10
- 今天在使用pytorch进行训练,在运行 loss.backward() 误差反向传播时出错 :RuntimeError: grad can
- 一个小问题今天在做一个实验时,需要对一个包含中英文词汇的TXT文件进行读入和整理。Python代码的编码规则为UTF-8。在读入时,文件的每
- 使用场景当项目越来越庞大之后,不可避免的要拆分成多个子模块,我们希望各个子模块有独立的版本管理,并且由专门的人去维护,这时候我们就要用到gi
- 第一种方式阿里云、百度云服务器可用!!!yum install python3第二种方式1.下载python3.6.5的压缩包wget ht
- 插件机制是代码/功能反向依赖注入到主体程序的一种方法,编译型语言通过动态加载动态库实现插件。对于Python这样的脚本语言,实现插件机制更简
- 下面就来说说解决方案吧~import osimport syscurPath = os.path.abspath(os.path.dirna
- 昨天群里介绍了一个专门帮你PS图片的网站。吐司网。网站在图片的预览处理上有点意思。当鼠标经过图片,显示为处理过的图片。这样大家能很清晰的对比
- 聚合函数 count,max,min,avg,sum... select count (*) from T_Employee select
- 目录前言前期准备数据的选择与获取分词筛选与可视化总结前言”数据可视化“这个话题,相信大家并不陌生,在一些平台,经常可以看到一些动态条形图的视
- cmd中输入net start mysql 提示:服务名无效请进入MySQL的bin目录,并在bin目录打开命令行窗口,或设置系统环境变量,
- 本文实例讲述了Python视频爬虫实现下载头条视频功能。分享给大家供大家参考,具体如下:一、需求分析抓取头条短视频思路:分析网页源码,查找解
- 本文实例讲述了js+CSS实现弹出居中背景半透明div层的方法。分享给大家供大家参考。具体实现方法如下:<!DOCTYPE html
- DreamWeaver 4的到来让大家兴奋吧?但是大家一定为DreamWeaver4里面的字体、文字大
- codecs在读取文件时,发生错误:UnicodeDecodeError: 'utf-8' codec can't
- Cookie是一种发送到客户浏览器的文本串句柄,并保存在客户机硬盘上,可以用来在某个Web站点会话之间持久地保持数据。Request和Res
- 在处理Python代码字符串的时候,我们常会遇到要去除空格的情况,所以就总结了多种方法供大家参考。1、strip()方法去除字符串开头或者结