Day 21 python :面向对象 类的相关内置函数 /单例模式 /描述符
1、isinstance(obj,cls) 检查obj是否是类cls的对象;
备注:用isinstance 的时候,产生实例后,会显示实例既是父类的实例,也是子类的实例
class Mom:
gender = "woman"
def __init__(self,name,weight):
self.name = name
self.weight = weight
def clean_up1(self):
return "% 正在擦桌子" % self.name
m1 = Mom("xfd",110)
print(isinstance(m1,Mom))#True
isinstance
2、issubclass(sub,super)检查sub类是否是super类的派生类
class Father:
pass class Mom(Father):
gender = "woman"
def __init__(self,name,weight):
self.name = name
self.weight = weight
def clean_up1(self):
return "% 正在擦桌子" % self.name
m1 = Mom("xfd",110)
print(issubclass(Father,Mom))#False 判断Mom是不是Father的父类
issubclass
3、 __getattribute__
#_getattrbute__方法对类实例的每个属性访问都有效。
#__getattr__方法对类及其实例未定义的属性有效
#当同时定义__getattribute__和__getattr__时,__getattr__方法不会再被调用
#如果getattribute 挂掉后,getattr会运行
class Mom(Father):
gender = "woman"
def __init__(self,name,weight):
self.name = name
self.weight = weight
def __getattr__(self, item):
print("执行getattr") def __getattribute__(self, item):
print("执行getattribute")
m1 = Mom("xfd",110)
print(m1.name)#执行getattribute
print(m1.ads)#执行getattribute
_getattrbute__
二、__setitme__/__getitme__/__delitme__
class Mom:
gender = "woman"
def __init__(self,name,weight):
self.name = name
self.weight = weight
def __setitem__(self, key, value):
print("执行setitem")
self.__dict__[key] = value
def __getitem__(self, item):
print("执行getitem")
return self.__dict__[item]
def __delitem__(self, key):
print("delitme")
#self.__dict__.pop(key)
m1 = Mom("xfd",110)
m1['gender']="woman" #执行setitem
print(m1.__dict__)
del m1['gender']
print(m1.__dict__)
#中括号的这种操作,触发item ,点的方式触发attr的方法
item
三、__str__、__repr__,__format__
前言:
lis = list('xianfangdi')
print(lis)
#输出:['x', 'i', 'a', 'n', 'f', 'a', 'n', 'g', 'd', 'i']
class test:
pass
t1 = test()
print(t1)
#输出<__main__.test object at 0x000001B152E32828>
f = open("test.txt","w")
print(f)
#输出:<_io.TextIOWrapper name='test.txt' mode='w' encoding='cp936'>
#为什么同样都是产生实例,为什么结果不同呢?
1、__str__
class Test:
def __init__(self,name):
self.name = name
def __str__(self):
# return "str方法"
return "名字是%s" %self.name
t1 = Test('xfd')
print(t1)#名字是xfd
# 输出:str方法
#这个可以控制打印实例的显示类型
#打印操作实际是调用系统str的操作
str
2、__repr__
class Test:
def __init__(self,name):
self.name = name
def __repr__(self):
# return "repr方法"
return "名字是%s" %self.name
t1 = Test('xfd')
t1#名字是xfd 是在解释器里面触发
print(t1)
# 输出:repr方法
#repr(t1) 实际上调用的是t1.__repr__
#是在解释器里面触发
#如果str和repr共存,会找str,如果没有str,就把repr当做替代品显示
repr
#str 和 repr只能return 字符串
3、在类里面自定制__format__方法
# #一般我们用format传的是字符串
# x='{0},{1},{2}'.format('dog',"cat","pag")
# print(x)#输出dog,cat,pag
# #我们用类来来呢?
# class Date:
# def __init__(self,year,mon,day):
# self.year=year
# self.mon=mon
# self.day=day
# d1=Date(2016,12,26)
#
# x='{0.year}{0.mon}{0.day}'.format(d1)
# #d1.year d1.mon de.dad == 2016.12.26
# y='{0.year}:{0.mon}:{0.day}'.format(d1)
# z='{0.mon}-{0.day}-{0.year}'.format(d1)
# print(z)#12-26-2016
format_dic={
'ymd':'{0.year}{0.mon}{0.day}',
'm-d-y':'{0.mon}-{0.day}-{0.year}',
'y:m:d':'{0.year}:{0.mon}:{0.day}'
}#定义时间格式
class Date:
def __init__(self,year,mon,day):
self.year=year#
self.mon=mon#
self.day=day#
def __format__(self, format_spec):
#format_spec == 字典的key
if not format_spec or format_spec not in format_dic:
format_spec='ymd'
fm=format_dic[format_spec]
#fm ={0.year}{0.mon}{0.day}
return fm.format(self)
#{0.year}{0.mon}{0.day}.format(d1)
d1=Date(2016,12,26)
# format(d1) #d1.__format__()
# print(format(d1))
print(format(d1,'ymd'))
print(format(d1,'y:m:d'))
print(format(d1,'m-d-y'))
print(format(d1,'m-d:y')) #当执行format 方法的时候有就是在触发 类的__format__
--format--
四、__slots__
解释:
1、slots类变量,变量的值可以可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2、用用点。来访问数据属性本质就是再访问类或者对象的__dic__属性字典(类的字典是共享的,而每个实例是独立的)
3、为何使用__slots__后,__slots__j就会为实例使用一种更加紧凑的内部表示,实例通过一个很小的固定大小的数组来构建,而不是每个实例定义一个
字典,这跟元祖列表类似,再__slots__中列出的属性名再内部映射到这个数组的指定小标上,使用__slots__一个不好的地方我们不能给实例添加新的属性了,只能使用__slots__中定义的属性名
4、注意:__slots__的很多特性都依赖于普通的基于字典的实现,另外定义之后,类不在支持一些普通特性了,比如多继承,大多数情况下,你应该只在哪些经常被使用到的用作数据结构的类上定义__stots__ 比如程序中需要创建摸个类的百万个实例对象。
关于__slots__的一个常见误区是他可以作为一个封装公祖来放置用户给实例增加新的属性。尽管使用__slots__可以达到这样的摸底,但是这个斌不是他的初衷。更多的是用来做一个内存优化的工具。
class Foo:
__slots__=['name','age'] #类似于{'name':None,'age':None}
# __slots__='name' #{'name':None}
f1=Foo()
# f1.name='xfd'
# print(f1.name)
# f1.age=18
# 报错,设置属性时,触发setattr,实际上是找f1.__dict__
# 现在没有__dict__肯定没有了,取而代之 是f1.__slots__(实例没有去找类了)
print(Foo.__slots__)
print(f1.__slots__)
#都输出 ['name', 'age']
f1.name='XFD'
f1.age=17
print(f1.name)#print(f1.age)# 可以获取值
f2=Foo()
print(f2.__slots__)#['name', 'age']
#F2 也不能创建,只能用name ,age
__slots__
五、__doc__ 描述信息
class Test:
'描述信息'
pass print(Test.__doc__)#描述信息
#该属性无法继承
__doc__
六、__module__ ,__class__
from bin.E import G g1 = G()
print(g1.name)
print(g1.__module__)#bin.E
#g1,来自 bin下的E模块
print(g1.__class__)
#g1是由bin.E.G产生的
__class__/__module__
七、析构方法 __del__ / __call__
注:此方法一般无需定义,python3是一个高级语言,程序员再使用时,无需关心内存的分配和释放,因为此工作都是交给解释器来执行,所有,析构函数的调用是由解释器在进行垃圾回收时自动触发执行
1、__call__ 对象后面加()触发执行
备注:构造方法的执行是由创建对象触发,即: 对象= 类名();而队友call方法的执行是由对象后加()触发的。
例:类(),实例()
class System:
# def __init__(self,name):
# self.name = name
def __call__(self, *args, **kwargs):
print("实例执行") f1 = System()
f1()#实例执行
System()#触发call方法 然后产生实例
#一个对象加(),可以去执行,执行的是类下面的call方法
__call__
八、__next__,__iter__实现迭代器协议
class Foo:
def __init__(self,n):
self.n=n
def __iter__(self):
return self
def __next__(self):
if self.n == 13:
raise StopIteration('终止了')
#抛出异常
self.n+=1
return self.n
#可迭代协议,必须包含iter方法
#有next 就是迭代器
f1=Foo(10)
# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__())
# print(f1.__next__()) for i in f1: # obj=iter(f1)------------>f1.__iter__()
print(i) #obj.__next_()
--inter.next--
#1,1,2,3,5,8
class Fib:
def __init__(self):
self._a=1
self._b=1
def __iter__(self):
return self
def __next__(self):
if self._a > 100:
raise StopIteration('终止了')
self._a,self._b=self._b,self._a + self._b
#a,b = 1,1+1
#a(1),b(2) = 2,3
return self._a
f1=Fib()
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
print('==================================')
for i in f1:
print(i)
--斐波拉切数列--
九、__new__方法
我们知道实例化init会自动执行, 其实在init方法之前,还有一个new方法也会自动执行,你可以在new里执行一些实例化前的定制动作
class Person:
# class person(object):
def __init__(self,name):
self.name = name
print("name") # 先执行new
def __new__(cls, *args, **kwargs):
# new方法负责执行__init__,进行一些实例初始化前的工作
"""
cls : 代表Person这个类本身
:param args:
:param kwargs: 类的参数
:return:
"""
return object.__new__(cls)
# 调用父类的__new__方法,必须这么干 ,要不然__init__方法就不会执行了
p = Person("XFD")
__new__
1、设计模式:开发软件有一套模式,开发手机端的,有一套模式,开发一套网络软件,也有一条模式
设计模式一共有23种,有一个组织叫gof
单例模式:单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。
例如:你windows系统中,你用一个方法打开了一个软件,然后又用另外一个方法,还打开这个软件,但是这个软件不会产生新的,还是你刚才打开的,没有任何变化。
什么情况下用单例?
对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务;一个系统只能有一个窗口管理器或文件系统;一个系统只能有一个计时工具或ID(序号)生成器。如在Windows中就只能打开一个任务管理器。如果不使用机制对窗口对象进行唯一化,将弹出多个窗口,如果这些窗口显示的内容完全一致,则是重复对象,浪费内存资源;如果这些窗口显示的内容不一致,则意味着在某一瞬间系统有多个状态,与实际不符,也会给用户带来误解,不知道哪一个才是真实的状态。因此有时确保系统中某个对象的唯一性即一个类只能有一个实例非常重要。
如何保证一个类只有一个实例并且这个实例易于被访问呢?定义一个全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。一个更好的解决办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例被创建,并且它可以提供一个访问该实例的方法。这就是单例模式的模式动机。
class Print(object):
tasks = []#打印任务列表
instance = None
#公共属性,都可以访问,存放第一个实例对象
def __init__(self,name,):
self.name = name
# self.job = job
def add_job(self,job):
self.tasks.append(job)
print("[%s] 打印了 [%s],这是[%s]个任务" %(self.name,job,len(self.tasks)))
def __new__(cls, *args, **kwargs):
#只有第一次实例化的时候,正常运行,后面每次实例化,并不创建一个新的实例
if cls.instance is None:
#进行正常实例化,并把实例化的对象存放在cls.instance中
obj = object.__new__(cls)
#这个是实例化的过程
cls.instance = obj #把实例化好的对象存下来 ↑
return cls.instance
#以后每次实例化,直接返回第一次存的实例对象
#在上一次实例的基础上,再执行_init_ p1 = Print("xfd")
p2 = Print('sjc')
p1.add_job('word')
p2.add_job("excel") #感觉有问题,为什么名字没变?
打印任务模拟
十、描述符(__get__,__set__,__delete__)
1、描述符:描述符的本质就是一个新式类,在这个新式类中,至少实现了__get__,__set__,__delete__的一个。
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
class Foo:
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass 定义一个描述符
描述符
2、 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
#描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...')
#描述符Int
class Int:
def __get__(self, instance, owner):
print('Int调用')
def __set__(self, instance, value):
print('Int设置...')
def __delete__(self, instance):
print('Int删除...')
class People:
name=Str()
age=Int()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age
#代理后,给name,age,获取,设置值,删除值时就会触发get,set,del p1=People('alex',18) #描述符Str的使用
p1.name
p1.name='egon'
del p1.name #描述符Int的使用
p1.age
p1.age=18
del p1.age #我们来瞅瞅到底发生了什么
print(p1.__dict__) #空
print(People.__dict__)#{'__module__': '__main__', 'name': <__main__.Str object at 0x000001CC3517A860>,
# 'age': <__main__.Int object at 0x000001CC3517A898>,
描述符触发
3、 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性 # 类名.x = 1
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
4、描述符的应用
例:利用描述符功能,类的传参的时候必须为一种数据类型比如说,必须为str类型的参数才可以。(类型检测)
class Typed:
def __init__(self,key):
self.key = key #{name,age,salarty}
def __get__(self, instance, owner):
# instance:实例对象s1 owner:实例的拥有者 类 salary
return instance.__dict__[self.key]
def __set__(self, instance, value):#instance: value:
if not isinstance(value,str):#只能判断一个类型! str写死了
#isinstance 检查是不是这个类型
instance.__dict__[self.key] = value # instance:实例对象s1 value: 就是传进的值 raise TypeError("你传入的不是字符串")
class Salary:
name = Typed("name")#触发typed 类,被代理了
#参数name 传进了 Typed 类的key
age = Typed("age")
salarty = Typed("salarty")
def __init__(self,name,age,salary):
self.name = name
self.age = age
self.salarty = salary s1 = Salary('sjc',12,3,)
print(s1.__dict__)
判断类型是不是字符串类型
#智能判断一个类型,如果多个类型都要判断
class Typed:
def __init__(self,key,e_type):
self.key = key #{name,age,salarty}
self.e_type = e_type #{str,int,float}
def __get__(self, instance, owner):
# instance:实例对象s1 owner:实例的拥有者 类 salary
return instance.__dict__[self.key]
def __set__(self, instance,value,):# instance:实例对象s1 value: 就是传进的值
if not isinstance(value,self.e_type):#检测传进来的值是否匹配
raise TypeError("你传入的%s不是%s" %(value,self.e_type))
instance.__dict__[self.key] = value
class Salary:
name = Typed("name",str)#触发typed 类,被代理了
#参数name 传进了 Typed 类的key
age = Typed("age",int)
salarty = Typed("salarty",float)# 这里加上类型
def __init__(self,name,age,salary):
self.name = name
self.age = age
self.salarty = salary
s1 = Salary("sunjinchao",12,2,)
print(s1.__dict__)
判断多个值
十一、__enter__ 和 __exit__
上下文管理协议,及with语句(with open (test")as f:),为了让一个对象兼容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中代码块执行完毕时执行我啊') # f = Open('a.txt')
with Open('a.txt') as f:
print('=====>执行代码块')
#出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
=====>执行代码块
with中代码块执行完毕时执行我啊
with as
class Open:
def __init__(self,name):
self.name=name def __enter__(self):
return self
#with 的过程中,其实是在触发enter
def __exit__(self, exc_type, exc_val, exc_tb):
#with 语句完成之后,才会触发__exit__
#exc_type: 异常类型
#exc_val:异常错误的值
#exc_tb:异常追踪信息
return True # 这样的话,程序异常会报错,但是不会终止程序的运行
#with 代码块的代码出现异常后,会执行__exit__
# 出现异常后,with代码块里面的后面的内容不会运行
with Open('a.txt') as f:
print('=====>执行代码块')
# print(f,f.name)
解释
Day 21 python :面向对象 类的相关内置函数 /单例模式 /描述符的更多相关文章
- 洗礼灵魂,修炼python(36)--面向对象编程(6)—类的相关内置函数issubclass,hasattr等
啥?我靠,类也有内置函数?哈哈,确实有的.有哪些呢?请往下看 issubclass(cls, class_or_tuple, /) 1.基本属性: 方法全是特殊方法 2.使用方法:判断一个类是否由另一 ...
- python基础学习1-类相关内置函数
#!/usr/bin/env python # -*- coding:utf-8 -*- #===issubclass(class,classinfo) 检查class是否是classinfo类的子类 ...
- Day07:常用模块,面向对象编程(对象&类)及内置函数
今日内容:1.常用模块2.面向对象编程(*****) 介绍面向对象编程 类 对象3.内置函数------------------------------1.面向过程编程 核心“ ...
- python 类(object)的内置函数
python 类(object)的内置函数 # python 类(object)的内置函数 ### 首先 #### 以__双下划线开头的内置函数 __ #### __往往会在某些时候被自动调用,例如之 ...
- Python基础(七)内置函数
今天来介绍一下Python解释器包含的一系列的内置函数,下面表格按字母顺序列出了内置函数: 下面就一一介绍一下内置函数的用法: 1.abs() 返回一个数值的绝对值,可以是整数或浮点数等. 1 2 3 ...
- python基础12_匿名_内置函数
一个二分查找的示例: # 二分查找 示例 data = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35, 36, ...
- Python学习(八) —— 内置函数和匿名函数
一.递归函数 定义:在一个函数里调用这个函数本身 递归的最大深度:997 def func(n): print(n) n += 1 func(n) func(1) 测试递归最大深度 import sy ...
- python成长之路八 -- 内置函数
1,python内置函数 内置函数 abs() dict() help() min() setattr() all() dir() hex() next() slice() a ...
- Python【day 13】内置函数01
1.python3.6.2 一共有 68个内置函数2.分成6个大类 1.反射相关-4个 2.面向对象相关-9个 3.作用域相关--2个 1.globlas() #注意:最后是s,复数形式 查看全局作用 ...
随机推荐
- Struts1.3——Struts标签
1.struts标签的介绍 Struts框架提供了一组非常丰富的框架组件,同时也提供了一组标签库用于和这些组件交互,主要介绍以下三类: html标签 bean标签 logic标签 2.Html标签库 ...
- Windows下搭建Wampserver+Wordpress
安装wordpress windows 下载安装包 百度云 提取码:qxzp 安装wamp WampServer就是Windows Apache Mysql PHP集成安装环境,即在window下的a ...
- Java.util包教程
java.util.ArrayDeque 类提供了可调整大小的阵列,并实现了Deque接口.以下是关于阵列双端队列的要点: 数组双端队列没有容量限制,使他们增长为必要支持使用. 它们不是线程安全的;如 ...
- C#变量2
| 版权声明:本文为博主原创文章,未经博主允许不得转载. 数据类型: (1).值类型 类型名称 CTS类型 说明 范围 ^ - ^-(--) ^-^-(-~) ^-^- ^-^- -(-^-) - ...
- volatile在嵌入式系统中的用法
今天参加一家公司的嵌入式C语言笔试,其中有道主观题谈到在嵌入式系统中volatile变量的用法.平时学习C语言没怎么用到,只用到过static和extern的变量,很惭愧没答上来.嵌入式C语言笔试经常 ...
- mysql 密码
http://www.cnblogs.com/jonsea/p/5510219.html character-set-server=utf8 mysql 修改密码: ALTER USER 'root' ...
- CentOS6.5源码安装MySQL5.6.35
CentOS6.5源码安装MySQL5.6.35 一.卸载旧版本 1.使用下面的命令检查是否安装有mysql [root@localhost tools]# rpm -qa|grep -i mysql ...
- docker--环境搭建
我的电脑是win10,虽然现在win10开始也支持docker,但在linux机器会合适些,所以我先用VMware创建一个linux虚拟机--Centos7 安装虚拟机不多说,现在开始安装docker ...
- cas4.2.7 集群服务搭建
cas服务端集群,网上资料很多,无非就是session共享,ticket共享. 但是session共享是必须的吗?或者能实现集群吗? 实践: 1. ticket共享,直接上代码 package org ...
- Codeforces 1149D 最短路 状压DP
题意及思路:https://blog.csdn.net/yzyyylx/article/details/90145400 这题主要巧妙在分析了最短路算法的性质,得出大小小于等于3的连通块一定不会被再次 ...