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 ...
随机推荐
- eval方法将字符串转换成json对象
方法一: 使用Eval将json字符串转为json对象 var str = "name:'Jon',sex:'男'"; 将字符串进行处理: str = "{"+ ...
- 峰Redis学习(7)Redis 之Keys 通用操作
keys * 显示所有key 查找所有以s开头的key 用s* *代表任意字符 127.0.0.1:6379> keys s* 1) "set3" 2) "s ...
- hive命令的3种调用方式
方式1:hive –f /root/shell/hive-script.sql(适合多语句) hive-script.sql类似于script一样,直接写查询命令就行 例如: [root@cloud ...
- go语言学习--语法糖
语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指计算机语言中添加的某种语法,这种语法对语言的功能并没有 ...
- [UE4]时间轴线TimeLine,Lerp插值
一.TimeLine时间轴线 勾选“User Last Keyframe”表示使用时间轴最后一个关键帧所在时间点作为结束时间,而不是使用设置的5秒作为结束时间点. 二.Lerp插值 Lerp插值一般与 ...
- Unable to load the plugin type
crm 2016 post update 异步执行 1 我们自定义文件是发布在GAC的,所以先注册GAC 2 更新注册插件 3 重启IIS ,异步服务
- Page Cache, the Affair Between Memory and Files.页面缓存-内存与文件的那些事
原文标题:Page Cache, the Affair Between Memory and Files 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限 ...
- webstorm命令行无法使用node-gyp进行编译
换成cmd命令即可:
- IP地址查询接口API
项目需要根据ip查询pos机设备所在的省份信息,经查询有以下几种免费接口: 1. 淘宝IP API http://ip.taobao.com/service/getIpInfo.php?ip=xxx ...
- python学习之----深网和暗网
深网是网络的一部分,与浅网(surface Web)对立.浅网是互联网上搜索引擎可以抓 到的那部分网络.据不完全统计,互联网中其实约90% 的网络都是深网.因为谷歌不 能做像表单提交这类事情,也找不到 ...