Python 基础  四  面向对象杂谈

一、isinstance(obj,cls) 与issubcalss(sub,super)

isinstance(obj,cls)检查是否obj是否是类 cls 的对象
class Foo:
pass f1=Foo()
print(isinstance(f1,Foo)) #True issubclass(sub, super)检查sub类是否是 super 类的派生类
class Foo:
pass class Xoo(Foo):
pass print(issubclass(Xoo,Foo)) #True

二、__getattribute__
    在介绍__getattribute__之前是否还记得之前学过一个叫__getattr__的方法,这两者之间是否存在某种关系呢?实际上呢,还是有关系的,是个什么情况呢,就是大哥和小弟的关系,有大哥在的时候大哥上,大哥不在小弟上,或者大哥不想干了,让给了小弟,那你小弟就必须上了是吧。

先看一下__getattr__的例子:

class Foo:
def __init__(self,x):
self.x=x def __getattr__(self, item):
print('执行的是我')
# return self.__dict__[item] f1=Foo(10)
print(f1.x) #d当访问的属性存在的时候是不会触发__getattr__
#f1.xxxxxx #不存在的属性访问,触发__getattr__,若自己没有重写此方法时,就会触发系统默认的此方法,若重写了就会按你自己写的东西执行

好了,再看一下两个都存在的触发方式及结果:

class Foo:
def __init__(self,x):
self.x=x def __getattr__(self, item):
print('执行的是getattr')
# return self.__dict__[item]
def __getattribute__(self, item):
print('执行的是getattribute')
raise AttributeError('抛出异常了')
# raise TabError('xxxxxx')
f1=Foo(10)
#f1.x
f1.xxxxxx #不存在的属性访问,触发__getattr__,若有__getattribute__就先触发此方法(不管属性是否存在),若后面有raise方法抛出异常的时候,就会再次交给__getattr__处理

三、item系列
  看到这里是否还记得之前说过一个系列叫做:attr,这两者又是什么关系?我们先看看item系列

class Foo:
def __getitem__(self, item):
print('getitem',item)
#return self.__dict__[item] def __setitem__(self, key, value):
print('setitem')
self.__dict__[key]=value def __delitem__(self, key):
print('delitem')
self.__dict__.pop(key) f1=Foo()
#print(f1.__dict__) #对象f1的属性字典是空的————》{}
#f1.name='egon'#---->setattr-------->f1.__dict__['name']='egon'
#print(f1.__dict__) #{'name': 'egon'}
f1['name']='egon'#--->setitem--------->f1.__dict__['name']='egon'
f1['age']=18 #会触发 内部的__setitem__方法
#
print('===>',f1.__dict__) # ===> {}查看属性字典却没有添加进去,只是触发了内部的__setitem__方法,若要添加上,就必须对底层进行操作: self.__dict__[key]=value
# 这样就把属性字典添加上了 ===> {'name': 'egon', 'age': 18}
del f1.name # 删除属性值
print(f1.__dict__) # {'age': 18}
# #
print(f1.age)
del f1['name'] #触发__delitem__,若要真实的删除属性字典中的值就必须对底层进行操作: self.__dict__.pop(key)
#print(f1.__dict__)

总结一下item系列的触发是通过字典类型的方式操作完成的,而attr方式的触发是通过对象加点(.)的方式触发的,这就是两者的最大区别,但是两者最终的效果是一样的。

四 、 _str_ ;_reper_;__format__

_str_ ;_reper_;改变对象的字符串显示方式换句话就是展示print()函数的 执行结果的:

class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '名字是%s 年龄是%s' %(self.name,self.age)
# #
f1=Foo('egon',18)
print(f1) #str(f1)--->f1.__str__() 若没有__str__函数,则执行print()就会执行提供的默认的打印内容
#比如本实例中打印的内容为:<__main__.Foo object at 0x006166D0>,若我们在定义的时候写了__str__函数就会按照我们自己定义好的方式执行打印操作:名字是egon 年龄是18
#
x=str(f1)
print(x)
#
y=f1.__str__()
print(y)
class Foo:
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return '折是str'
def __repr__(self):
return '名字是%s 年龄是%s' %(self.name,self.age) f1=Foo('egon',19)
#repr(f1)---->f1.__repr__()
print(f1) #str(f1)---》f1.__str__()------>f1.__repr__()

总结:当 str 与repr同时存在的时候执行顺序是:先找str 若没有再去找repr,若都没有就去执行默认的print()打印结果。
__format__ 自定义方式来制定输出格式:

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):
print('我执行啦')
print('--->',format_spec)
if not format_spec or format_spec not in format_dic:
format_spec='ymd'
fm=format_dic[format_spec]
return fm.format(self)
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'))
print('===========>',format(d1,'asdfasdfsadfasdfasdfasdfasdfasdfasdfasd

五 、__slots__ (省内存)
    1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)

2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)

3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__

class Foo:
__slots__=['name','age'] #{'name':None,'age':None}
# __slots__='name' #{'name':None,'age':None} f1=Foo()
f1.name='egon'
#print(f1.name) f1.age=18 #--->setattr----->f1.__dict__['age']=18
#print(f1.__dict__) #AttributeError: 'Foo' object has no attribute '__dict__' 为何会出现这个结果,这就是不让各个实例对象自己封存自己的数据属性了。
print(Foo.__slots__) #['name', 'age']类中指存放了键的属性
print(f1.__slots__) # ['name', 'age']
f1.name='egon'
f1.age=17
print(f1.name)
print(f1.age)
f1.gender='male' #Foo' object has no attribute 'gender' 在定义数据属性的时候就没有定义性别的属性,so就加不进去

六、__doc__

class Foo:
'我是描述信息'
pass print(Foo.__doc__) # 我是描述信息

需要注意的是:此属性是不具有继承的:

class Foo:
'我是描述信息'
pass class Bar(Foo):
pass
print(Bar.__doc__) #该属性无法继承给子类 打印结果为:None

七、__module__和__class__
_module__ 表示当前操作的对象在那个模块

__class__     表示当前操作的对象的类是什么

八、__del__

析构方法,当对象在内存中被释放时,自动触发执行。

class Foo:

    def __del__(self):
print('执行我啦') f1=Foo()
del f1
print('------->') #输出结果
执行我啦
------->

九 、__call__方法
    对象后面加括号,触发执行。

注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

class Foo:

    def __init__(self):
print('你就是大傻逼') def __call__(self, *args, **kwargs): print('__call__') obj = Foo() # 执行 __init__
obj() # 执行 __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 # l=list('hello')
# for i in l:
# print(i)
f1=Foo(10)
print(f1.__next__())
print(f1.__next__())
print(f1.__next__())
print(f1.__next__()) for i in f1: # obj=iter(f1)------------>f1.__iter__() #此时的f1的值为最后一次迭代额值
print(i) #obj.__next_()

十一、描述符(__get__,__set__,__delete__)(这个东西很高大上,不过现在的级别还是没啥卵用,就先简单的了解一下下)
    1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
    __get__():调用一个属性时,触发
    __set__():为一个属性赋值时,触发
    __delete__():采用del删除属性时,触发

一个小小的例子:

class Foo: #在python3中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 #何地?:定义成另外一个类的类属性 #何时?:且看下列演示 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__) #补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__) 描述符应用之何时?何地?

描述符

3 描述符分两种
    一 数据描述符:至少实现了__get__()和__set__()

1 class Foo:
2 def __set__(self, instance, value):
3 print('set')
4 def __get__(self, instance, owner):
5 print('get')

二 非数据描述符:没有实现__set__()

1 class Foo:
2 def __get__(self, instance, owner):
3 print('get')

4 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()

今天的主要内容就这些,看起来还不错,实践,实践,还是实践!!!

Python 基础 四 面向对象杂谈的更多相关文章

  1. 自学Python之路-Python基础+模块+面向对象+函数

    自学Python之路-Python基础+模块+面向对象+函数 自学Python之路[第一回]:初识Python    1.1 自学Python1.1-简介    1.2 自学Python1.2-环境的 ...

  2. (转)Python成长之路【第九篇】:Python基础之面向对象

    一.三大编程范式 正本清源一:有人说,函数式编程就是用函数编程-->错误1 编程范式即编程的方法论,标识一种编程风格 大家学习了基本的Python语法后,大家就可以写Python代码了,然后每个 ...

  3. 二十. Python基础(20)--面向对象的基础

    二十. Python基础(20)--面向对象的基础 1 ● 类/对象/实例化 类:具有相同属性.和方法的一类人/事/物 对象(实例): 具体的某一个人/事/物 实例化: 用类创建对象的过程→类名(参数 ...

  4. python基础,函数,面向对象,模块练习

    ---恢复内容开始--- python基础,函数,面向对象,模块练习 1,简述python中基本数据类型中表示False的数据有哪些? #  [] {} () None 0 2,位和字节的关系? # ...

  5. Day7 - Python基础7 面向对象编程进阶

    Python之路,Day7 - 面向对象编程进阶   本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个 ...

  6. Python基础7 面向对象编程进阶

    本节内容: 面向对象高级语法部分 经典类vs新式类 静态方法.类方法.属性方法 类的特殊方法 反射 异常处理 Socket开发基础 作业:开发一个支持多用户在线的FTP程序 面向对象高级语法部分 经典 ...

  7. Python之路【第六篇】python基础 之面向对象(一)

    一.三大编程范式 1.面向过程编程 2.函数式编程 3.面向对象编程 二.编程进化论 1.编程最开始就是无组织无结构,从简单控制流中按步写指令 2.从上述的指令中提取重复的代码块或逻辑,组织到一起(比 ...

  8. python基础之面向对象高级编程

    面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个"函数"供使用(可以讲多函数中公用的变量封装到对象中) ...

  9. Python基础之面向对象2(封装)

    一.封装定义: 二.作用 三.私有成员: 1.基本概念及作用 2.__slots__手段私有成员: 3.@property属性手段私有成员: 四.基础示例代码 1.用方法封装变量 "&quo ...

随机推荐

  1. Fundebug上线Node.js错误监控啦

    作为全栈JavaScript错误实时监测平台,Fundebug的Node.js实时错误监测服务上线啦,我们能够帮助开发者及时,高效地发现并且解决Node.js错误,从而提高开发效率,并提升用户体验. ...

  2. linux系统和Windows系统共存

    最近接触了linux系统,因为对linux系统一直存在一种敬畏之心,所以决定研究研究 那么今天我在这里呢是要和大家分享一下在Windows存在的情况下安装双系统linux 那么第一步呢,就是斤BIOS ...

  3. 疑问:Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间

    问题:今天想写一个通用点的方法,根据传入的参数的类型(clazz对象),判断使用哪个mapper来插入mysql数据库. 下面是我的写法: public interface BizNeeqCommon ...

  4. 如何使用bootstrap

    前言: 前几天,本想做一个登陆界面,但自己写form表单必然很丑,所以想用下bootstarp框架,之前听别人说bootstrap很牛的样子.但我完全不会bootstrap... 下载&目录 ...

  5. Spring + qyartz+多任务实现任务调度功能。

    前记:如果配置多个任务不能触发的请仔细检查配置文件!!!!!! 不存在多个同时间任务不能触发的现象!!!! 这个东西记得不要设置成false.如果写了就是true.不写的话默认true. 下面开始贴配 ...

  6. Windbg DUMP分析(原创汇总)

    1. 引入篇 所谓技术分享,其实是一个自我总结和相互学习.不断成长的过程. 考虑到之前原创的文章http://www.cnblogs.com/LoveOfPrince/p/6032523.html&l ...

  7. PRINCE2学习

    今天对PRINCE2中提及的7大主题进行学习,主要的内容是通过概述和PMBOK之间的对比做一些总结,每个主题所包含的过程和方法并没有太多涉及,没有对整个体系有全面深入的学习,有些断章取义的地方也请博友 ...

  8. 【C++】浅谈三大特性之一继承(二)

    三,继承方式&访问限定符 派生类可以继承基类中除了构造函数和析构函数之外的所有成员,但是这些成员的访问属性是由继承方式决定的. 不同的继承方式下基类成员在派生类中的访问属性: 举例说明: (1 ...

  9. python 之栈的实现

    #!/usr/bin/env python # --------------------------------------- # author : Geng Jie # email : gengji ...

  10. CF766 E. Mahmoud and a xor trip [预处理][树形dp]

    题解: 二营长!你他娘的意大利炮呢? dp[i][j][0]: 从i,跋涉到以i为根的子树的每一个节点,在第j个数位上一共产生了多少个0. dp[i][j][1]: 从i,跋涉到以i为根的子树的每一个 ...