day28-面相对象的特殊成员、内置函数
1、 isinstance与issubclass
1.1、isinstance(obj,cls)
检查obj是否是类cls的对象,或者是类cls的子类的对象
class A: pass
class B(A): pass abj = B()
print(isinstance(abj,B)) #True
print(isinstance(abj,A)) #True
1.2、issubclass(sub, super)
检查sub类是否是super类的子类,或者是super子类的子类
class A: pass
class B(A): pass print(issubclass(B,A)) #True 这里2个参数都是类名,不是对象名
2、内置函数
__len__ 返回类的__dict__字典中属性的个数,通过len(obj)调用
__hash__ 返回一个哈希值,通过hash(obj)调用
__str__ 返回一个字符串,直接打印obj时调用
__repr__ 返回一个字符串,直接打印repr(obj)时调用
__call__ (重要) 对象后面加括号,触发执行
__eq__ 判断属性是否相等,设置返回值,通过打印obj1 == obj2调用
__del__ 析构方法,当对象在内存中被释放时,自动触发执行。
__new__ (重要)
__item__系列 (重要) 对实例化对象进行类似字典的操作,有3种
__getitem__
__setitem__
__delitem__
__attr__系列(重要),对实例化对象进行对象操作,有3种
__getattr__
__setattr__
__delattr__
__iter__ 实现迭代器
__next__ 从迭代器中取值
2.1 __len__
class A:
def __init__(self):
self.a = 1
self.b = 2 def __len__(self):
return len(self.__dict__) a = A()
print(len(a))
# 等同于下面的效果
class A:
def __init__(self):
self.a = 1
self.b = 2 def len(self):
return len(self.__dict__)
a = A()
print(a.len())
2.2、__hash__
class A:
def __init__(self):
self.a = 1
self.b = 2 def __hash__(self):
return hash(str(self.a))
a = A()
print(hash(a))
# 737862024 将self.a的值转换成字符串1,再进行hash 等同于下面的效果
class A:
def __init__(self):
self.a = 1
self.b = 2
def hash(self):
return str(self.a)
a = A()
print(hash(a.hash()))
2.3、__str__
如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。
class A:
def __init__(self):
self.a = 1
self.b = 2
def __str__(self):
return ''
a = A()
print(a)
#
2.4、__repr__
如果一个类中定义了__repr__方法,那么在repr(对象) 时,默认输出该方法的返回值。
class A:
def __init__(self):
self.a = 1
self.b = 2
def __repr__(self):
return ''
a = A()
print(repr(a))
#
2.5、__call__ (重要)
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
class Foo:
def __init__(self):
print('in __init__')
def __call__(self, *args, **kwargs):
print('in __call__')
obj = Foo() #执行 __init__
# in __init__
obj() # 执行 __call__
# in __call__
2.6、__eq__
class Foo:
def __init__(self, a, b):
self.a = a
self.b = b
def __eq__(self, obj):
if self.a == obj.a and self.b == obj.b: #判断条件可自行设置
return True #返回值可自行定义
obj1 = Foo(1,2)
obj2 = Foo(1,2)
obj3 = Foo(2,3)
print(obj1 == obj2)
# True
print(obj1 == obj3)
# None
2.7、__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Animal(object):
def __init__(self,name):
self.__name = name def __del__(self):
print('啊。。。')
dog = Animal('旺财')
print('---1---') ---1---
啊。。。
虽然没有调用__del__()方法,那是谁调用的呢?
python解释器如果检测到一个对象没有任何用处了,那么就把这个对象kill掉。
2.8、__new__ (重要)
class A:
def __init__(self):
print('in __init__') def __new__(cls,*args, **kwargs):
print('in __new__') obj = A()
print(obj)
# 结果:
# in __new__
# None
# 类A里面的__new__方法中并没有创建对象,所以对象obj并不存在 class A:
def __init__(self, name):
print('in __init__')
self.name = name def __new__(cls, *args, **kwargs):
print('in __new__')
return object.__new__(cls) # 调用object类中的__new__方法 obj = A('Tom')
# in __new__
# in __init__
print(obj.name)
# Tom
可以看出在实例化对象时先执行了__new__方法,再执行__init__方法
单例模式
定义一个类A,当实例化对象obj1和obj2时,会在内存中分别存储2个对象的空间,通过打印对象可以看出内存地址不同
class A:
__instance = None
def __init__(self, name):
self.name = name obj1 = A('Tom')
print(obj1)
# <__main__.A object at 0x00622490>
obj2 = A('Mike')
print(obj2)
# <__main__.A object at 0x00622910>
那么是否可以创建多个实例化对象时共用同一个内存空间,而不让每次创建实例化对象时都占用一个内存空间,从而节省内存呢?
我们可以在创建多个实例化对象时判断是否已经有实例化对象了,如果有就沿用第1个对象的内存空间,而不是重新创建新的内存空间。
class A:
__instance = None
def __init__(self, name):
self.name = name
def __new__(cls, *args, **kwargs):
if cls.__instance is None:
cls.__instance = object.__new__(cls)
return cls.__instance obj1 = A('Tom')
print(obj1)
# <__main__.A object at 0x01E901D0>
obj2 = A('Mike')
print(obj2)
# <__main__.A object at 0x01E901D0>
obj3 = A('Jack')
print(obj3)
# <__main__.A object at 0x01E901D0>
# 可以看到3个实例化对象的内存空间是相同的,其实都是第1个实例化对象的地址
单例模式具体分析
单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
【采用单例模式动机、原因】
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
【单例模式优缺点】
【优点】
一、实例控制
单例模式会阻止其他对象实例化其自己的单例对象的副本,从而确保所有对象都访问唯一实例。
二、灵活性
因为类控制了实例化过程,所以类可以灵活更改实例化过程。
【缺点】
一、开销
虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销。可以通过使用静态初始化解决此问题。
二、可能的开发混淆
使用单例对象(尤其在类库中定义的对象)时,开发人员必须记住自己不能使用new关键字实例化对象。因为可能无法访问库源代码,因此应用程序开发人员可能会意外发现自己无法直接实例化此类。
三、对象生存期
不能解决删除单个对象的问题。在提供内存管理的语言中(例如基于.NET Framework的语言),只有单例类能够导致实例被取消分配,因为它包含对该实例的私有引用。在某些语言中(如 C++),其他类可以删除对象实例,但这样会导致单例类中出现悬浮引用
2.9、__item__系列 (重要)
将实例化对象当作一个字典来进行操作
1)__getitem__:返回__dict__字典中key为item的值,通过对象['key']来调用
class Foo1:
def __init__(self, name, age):
self.name = name
self.age = age
def __getitem__(self, item):
return self.__dict__[item] obj1 = Foo1('Tom',20)
print(obj1['name'])
# Tom
2)__setitem__ : 将__dict__字典中key的值设置为vlaue,通过对象['key'] = vlaue来调用
class Foo2:
def __init__(self, name, age):
self.name = name
self.age = age
def __setitem__(self, key, value):
self.__dict__[key] = value
obj2 = Foo2('Mike', 25)
obj2['sex'] = 'man'
print(obj2.__dict__)
# {'name': 'Mike', 'age': 25, 'sex': 'man'}
3)__delitem__: 将__dict__字典中key的值删除,通过del 对象.key来调用
class Foo3:
def __init__(self, name, age):
self.name = name
self.age = age
def __delitem__(self, key):
self.__dict__.pop(key)
obj3 = Foo3('Jack', 28)
del obj3['age']
print(obj3.__dict__)
# {'name': 'Jack'}
其实这3种item方法都可以通过下面的代码实现,只是item方法在操作上可以将对象当作一个字典来实现,对于外面的调用者来说只需要知道这是一个字典就可以了,不需要知道这是一个对象,这个对象的方法是怎么调用的。
class Foo4:
def __init__(self, name, age):
self.name = name
self.age = age
def get(self):
print(self.__dict__)
def set(self, key, value):
self.__dict__[key] = value
def delete(self,key):
self.__dict__.pop(key)
obj4 = Foo4('Tom', 20)
obj4.get()
# {'name': 'Tom', 'age': 20}
obj4.set('sex', 'man')
obj4.get()
# {'name': 'Tom', 'age': 20, 'sex': 'man'}
obj4.delete('name')
obj4.get()
# {'age': 20, 'sex': 'man'}
2.10、__attr__系列 (重要)
将实例化对象当作一个对象来进行操作
1)__getattr__:返回__dict__字典中key为item的值,通过对象.'key'来调用
class Foo1:
def __init__(self, name, age):
self.name = name
self.age = age
def __getattr__(self, item):
return self.__dict__[item] obj1 = Foo1('Tom',20)
print(obj1.name)
# Tom
2)__setattr__ : 将__dict__字典中key的值设置为vlaue,通过对象.'key' = vlaue来调用
class Foo2:
def __init__(self, name, age):
self.name = name
self.age = age
def __setitem__(self, key, value):
self.__dict__[key] = value
obj2 = Foo2('Mike', 25)
obj2.sex = 'man'
print(obj2.__dict__)
# {'name': 'Mike', 'age': 25, 'sex': 'man'}
3)__delattr__: 将__dict__字典中key的值删除,通过del 对象.key来调用
class Foo3:
def __init__(self, name, age):
self.name = name
self.age = age
def __delattr__(self, key):
self.__dict__.pop(key)
obj3 = Foo3('Jack', 28)
del obj3.age
print(obj3.__dict__)
# {'name': 'Jack'}
2.11、__iter__和__next__实现迭代器
例子1
class Foo:
def __init__(self,start):
self.start = start def __iter__(self):
return self def __next__(self):
self.start+=1 #每次调用,将值加1
return self.start f1 = Foo(10)
print(f1.__next__())
11
print(next(f1))
12 for i in f1:
if i > 20:
break
print(i)
11
12
13
14
15
16
17
18
19
20
例子2:实现斐波那契
class Fib:
def __init__(self):
self._a = 0
self._b = 1 def __iter__(self):
return self def __next__(self):
self._a, self._b = self._b, self._a + self._b
return self._a fib = Fib() for i in fib:
if i > 10:
break
print(i) 1
1
2
3
5
8
3、二次加工标准类型
包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制自己的数据类型,新增/改写方法,这就用到了继承/派生的知识。
例子:
1、定义一个列表,增加一个需求,该列表可以取出下标在中间的值
自定义一个List类,继承内置list类,并增加新的方法get_middle
class List(list):
def __init__(self, item):
super().__init__(item)
self.item = item def get_middle(self):
mid_index = len(self.item)//2
return self.item[mid_index] l1 = List([1,2,3,4,5])
print(l1)
#[1, 2, 3, 4, 5] print(l1.get_middle())
# l1.append(6)
print(l1)
#[1, 2, 3, 4, 5, 6]
授权:授权是包装的一个特性, 包装一个类型通常是对已存在类型的一些定制,这种做法可以新建,修改或删除原有产品的功能,其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。
实现授权的关键点就是覆盖__getattr__方法
class List:
def __init__(self,seq,permission=False):
self.seq=seq
self.permission=permission def get_middle(self):
mid_index = len(self.seq)//2
return self.seq[mid_index] def clear(self):
if not self.permission:
raise PermissionError('not allow the operation')
self.seq.clear() def __getattr__(self, item):
return getattr(self.seq,item) def __str__(self):
return str(self.seq)
l=List([1,2,3])
l.clear() #此时没有权限,抛出异常
# Traceback (most recent call last):
# File "C:\Users\Administrator\Desktop\test.py", line 16, in <module>
# l.clear() #此时没有权限,抛出异常
# File "C:\Users\Administrator\Desktop\test.py", line 7, in clear
# raise PermissionError('not allow the operation')
# PermissionError: not allow the operation l.permission=True
print(l)
#[1, 2, 3]
l.clear()
print(l)
#[] #基于授权,获得insert方法
l.insert(0,-123)
print(l)
#[-123]
例子2:对文件进行写操作时,每一行前面添加上时间标签
import time class Open:
def __init__(self, filename, mode='r',encoding='utf-8'):
self.file = open(filename, mode, encoding=encoding) def write(self,str):
time_str = time.strftime('%Y-%m-%d %X')
self.file.write('%s %s'%(time_str, str)) def __getattr__(self,item):
return getattr(self.file, item) f1 = Open('a1.txt','w+')
f1.write('111111\n')
f1.write('222222\n')
f1.seek(0)
print(f1.read())
2020-04-07 19:05:30 111111
2020-04-07 19:05:30 222222
day28-面相对象的特殊成员、内置函数的更多相关文章
- Day07:常用模块,面向对象编程(对象&类)及内置函数
今日内容:1.常用模块2.面向对象编程(*****) 介绍面向对象编程 类 对象3.内置函数------------------------------1.面向过程编程 核心“ ...
- python全栈开发-Day13 内置函数
一.内置函数 注意:内置函数id()可以返回一个对象的身份,返回值为整数. 这个整数通常对应与该对象在内存中的位置,但这与python的具体实现有关,不应该作为对身份的定义,即不够精准,最精准的还是以 ...
- python之三元表达式、列表推导式、生成器表达式、递归、匿名函数、内置函数
一 三元表达式.列表推导式.生成器表达式 一 三元表达式 name=input('姓名>>: ') res='SB' if name == 'alex' else 'NB' print(r ...
- python基础知识15---三元表达式、列表推导式、生成器表达式、递归、匿名函数、内置函数
阅读目录 一 三元表达式.列表推导式.生成器表达式 二 递归与二分法 三 匿名函数 四 内置函数 五 阶段性练习 一. 三元表达式.列表推导式.生成器表达式 1 三元表达式 name=input('姓 ...
- python之三元表达式、列表推导、生成器表达式、递归、匿名函数、内置函数
目录 一 三元表达式 二 列表推到 三 生成器表达式 四 递归 五 匿名函数 六 内置函数 一.三元表达式 def max(x,y): return x if x>y else y print( ...
- python之旅:三元表达式、列表推导式、生成器表达式、函数递归、匿名函数、内置函数
三元表达式 #以下是比较大小,并返回值 def max2(x,y): if x > y: return x else: return y res=max2(10,11) print(res) # ...
- python 匿名函数,内置函数
一 :匿名函数 匿名就是没有名字 def func(x,y,z=1): return x+y+z 匿名 lambda x,y,z=1:x+y+z #与函数有相同的作用域,但是匿名意味着引用计数为0,使 ...
- SQL Server 内置函数、临时对象、流程控制
SQL Server 内置函数 日期时间函数 --返回当前系统日期时间 select getdate() as [datetime],sysdatetime() as [datetime2] getd ...
- 10、SQL Server 内置函数、临时对象、流程控制
SQL Server 内置函数 日期时间函数 --返回当前系统日期时间 select getdate() as [datetime],sysdatetime() as [datetime2] getd ...
随机推荐
- C#实现mongodb自增列的使用
创建一个集合存放_id db.createCollection("counters") 加入需要自增的字段 { "_id":"productid&qu ...
- JS之滚动条效果2
在前面一篇说的是滚动条效果,本篇继续在前面的基础上面针对滚动条进行操作.本次要实现的效果如下:拖动滚动条左右移动时,上面的图片内容也相对外层盒子做相对移动. 下面针对要实现的效果进行分析:首先是页面基 ...
- requests 请求几个接口 出现’您的账户在其它设备使用过,为保障安全,需重新登入才能在本设备使用‘
因为接口和接口直接有个字段是关联的 在登陆请求后,后台响应了个token,下面的请求 ,请求头要带上这个token 才认为是登陆后 的操作
- 描述wxWidgets中事件处理的类型转化
wxWidgets是一个比较常用的UI界面库,我曾经试着使用wxWidgets写一个UI编辑工具,在此期间,学习了一些wxWidgets的知识.我对wxWidgets的绑定(Bind)比较好奇,想知道 ...
- MySQL 独立表空间恢复案例
创建表的时候就会得到元数据.可以通过定义的方式对表的元数据进行生成 这个地方要注意的是 独立表空间当中 ibd & frm分别存储的是什么数据? 表空间:文件系统,为了更好的扩容数据库的存 ...
- Idea 2018版破解
刚把idea升级到最新版,发现要重新激活,网上查了有改host的方法可行,只是有点麻烦.无意中发现一个方法,如图所示 输入 http://idea.java.sx/ 即可,亲测可用.如果资金 ...
- 使用adb安装遇到的一些坑
1.下载安装android SDK,可通过浏览器或者相关手机软件下载软件下载需要安装的apk安装文件,把apk文件放到android-sdk-windows\platform-tools下 2.可通过 ...
- JavaWeb项目中web.xml有关servlet的基本配置
JavaWeb项目中web.xml有关servlet的基本配置: 我们注意到,tomcat下的conf中也有一个web.xml文件,没错的,所有的JavaWeb项目中web.xml都继承自服务器下的w ...
- 使用nginx secure_link指令实现下载防盗链
一.安装nginx并检查是否已安装模块 [root@img_server ~]# nginx -V #输出nginx所有已安装模块,检查是否有ngx_http_secure_link_module 二 ...
- solr 请求参数过长报错,Solr配置maxBooleanClauses属性不生效原因分析
博客分类: 上次已经写过一篇关于solr中,查询条件过多的异常的文章,这次在总结扩展一下: 有时候我们的查询条件会非常多,由于solr的booleanquery默认设置的条件数为1024,所以超过 ...