Python面向对象魔法方法和单例模块代码实例


Posted in Python onMarch 25, 2020

魔法方法

​ 凡是在类内部定义,以“__开头__结尾”的方法都称之为魔法方法,又称“类的内置方法”, 这些方法会在某些条件成立时触发。

经常用到的双下方法

  • __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()

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
在ironpython中利用装饰器执行SQL操作的例子
May 02 Python
Python数组定义方法
Apr 13 Python
python学习之matplotlib绘制散点图实例
Dec 09 Python
Python学生成绩管理系统简洁版
Apr 05 Python
python开启摄像头以及深度学习实现目标检测方法
Aug 03 Python
python使用Plotly绘图工具绘制水平条形图
Mar 25 Python
Django重置migrations文件的方法步骤
May 01 Python
pandas 数据索引与选取的实现方法
Jun 21 Python
Python基于Opencv来快速实现人脸识别过程详解(完整版)
Jul 11 Python
Selenium python时间控件输入问题解决方案
Jul 22 Python
使用python把xmind转换成excel测试用例的实现代码
Oct 12 Python
python对 MySQL 数据库进行增删改查的脚本
Oct 22 Python
Python语法垃圾回收机制原理解析
Mar 25 #Python
python实现Pyecharts实现动态地图(Map、Geo)
Mar 25 #Python
Pyecharts 动态地图 geo()和map()的安装与用法详解
Mar 25 #Python
Django查询优化及ajax编码格式原理解析
Mar 25 #Python
python使用pyecharts库画地图数据可视化的实现
Mar 25 #Python
python实现3D地图可视化
Mar 25 #Python
简单了解django处理跨域请求最佳解决方案
Mar 25 #Python
You might like
短波收音机简介
2021/03/01 无线电
php SQL Injection with MySQL
2011/02/27 PHP
php 魔术方法详解
2014/11/11 PHP
两个SUBMIT按钮,如何区分处理
2006/08/22 Javascript
jQuery 处理表单元素的代码
2010/02/15 Javascript
jquery插件制作 提示框插件实现代码
2012/08/17 Javascript
JS实现定时页面弹出类似QQ新闻的提示框
2013/11/07 Javascript
JS 实现BASE64_ENCODE和BASE64_DECODE(实例代码)
2013/11/13 Javascript
javascript 处理null及null值示例
2014/06/09 Javascript
zepto.js中tap事件阻止冒泡的实现方法
2015/02/12 Javascript
javascript自定义滚动条实现代码
2020/04/20 Javascript
微信js-sdk地理位置接口用法示例
2016/10/12 Javascript
jquery控制页面的展开和隐藏实现方法(推荐)
2016/10/15 Javascript
jQuery响应滚动条事件功能示例
2017/10/14 jQuery
vue组件中的样式属性scoped实例详解
2018/10/30 Javascript
vue+element加入签名效果(移动端可用)
2019/06/17 Javascript
python错误处理详解
2014/09/28 Python
在Python中操作列表之list.extend()方法的使用
2015/05/20 Python
详解Python在七牛云平台的应用(一)
2017/12/05 Python
python编程实现12306的一个小爬虫实例
2017/12/27 Python
python爬虫 2019中国好声音评论爬取过程解析
2019/08/26 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
用ldap作为django后端用户登录验证的实现
2020/12/07 Python
使用HTML5 Canvas为图片填充颜色和纹理的教程
2016/03/21 HTML / CSS
印尼值得信赖的在线交易网站:Bukalapak
2019/03/11 全球购物
eBay意大利购物网站:eBay.it
2019/09/04 全球购物
法律专业个人实习自我鉴定
2013/09/23 职场文书
加拿大留学自荐信
2014/01/28 职场文书
化妆品店促销方案
2014/02/24 职场文书
高中课程设置方案
2014/05/28 职场文书
房产分割协议书范文
2014/11/21 职场文书
社区植树节活动总结
2015/02/06 职场文书
当幸福来敲门英文观后感
2015/06/01 职场文书
2016年党员岗位承诺书
2016/03/24 职场文书
HR在给员工开具离职证明时,需要注意哪些问题?
2019/07/03 职场文书
Win10 最新稳定版本 21H2开始推送
2022/04/19 数码科技