python之面向对象深入探测
一 __doc__
表示类的描述信息
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class C:
""" 这是个大美女 """ def func(self):
pass print(C.__doc__)
#输出:这是个大美女
类的描述信息是无法被继承的
class Foo:
'我是描述信息'
pass class Bar(Foo):
pass
print(Bar.__doc__) #该属性无法继承给子类 输出信息:
None
二.isinstance和issubclass
# isinstance(obj,Foo)检查是否obj是否是类 Foo 的对象
class Foo(object):
pass obj = Foo() print(isinstance(obj,Foo)) # issubclass(Bar, Foo)检查Bar类是否是 Foo 类的派生类
class Foo():
pass class Bar(Foo):
pass print(issubclass(Bar, Foo)) # 输出结果:
# True
# True
三 __module__和__class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
说明:test和module_class 在同一级目录下
test.py
class C:
def __init__(self):
self.name = 'zzl'
module_class.py
from test import C obj = C()
print(obj.__module__)
print(obj.__class__) # 输出:
# test
# <class 'test.C'>
四:__init__
class Foo:
def __init__(self, name):
self.name = name
self.age = 18
obj = Foo('zzl') # 自动执行类中的 __init__ 方法
print(obj.name,obj.age)
#输出结果:
zzl 18
五 __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo()
# del f1
print('------->')
输出信息:
------->
执行我啦
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo()
del f1
print('------->')
# 输出信息:
执行我啦
------->
# 总结:当内存释放的时候,执行__del__
六. __call__
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() # 执行 __init__
obj() # 执行 __call__
输出结果:
__call__
七.二次加工标准类型(包装)
python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们刚学的继承/派生知识(其他的标准类型均可以通过下面的方式进行二次加工)
重写list的append方法:
class List(list):
def append(self, p_object):
if not isinstance(p_object,int):
raise TypeError('must be int')
super().append(p_object) l=List([1,2,3])
print(l)
l.append(5)
print(l)
授权:重写write的方法,并把当前时间写进去:
import time
class Open:
def __init__(self,file_path,mode='r'):
self.obj=open(file_path,mode) def write(self,msg):
msg='%s %s'%(time.strftime('%Y-%m-%d %X'),msg)
f.obj.write(msg) def __getattr__(self, item):
return getattr(self.obj,item) f=Open('a.txt','a')
f.write('111\n')
f.close() #f.obj.close() a.txt中写入的文件:
2017-05-17 23:14:58 111
2017-05-17 23:16:42 111
2017-05-17 23:18:13 111
八 __getattribute__
__getattr__:
# __getattribute__:不管是否存在我都会执行
class Foo:
def __init__(self,x):
self.x=x def __getattribute__(self, item):
print('from in __getattribute__ ') f1=Foo(10)
f1.x
f1.ssss 输出结果:
from in __getattribute__
from in __getattribute__
__getattr__:
class Foo:
def __init__(self,x):
self.x=x def __getattr__(self, item):
print('from in __getattr__ ') f1=Foo(10)
print(f1.x)
f1.ssss #不存在的属性访问,触发__getattr__
当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
class Foo:
def __init__(self,x):
self.x=x def __getattr__(self, item):
print('from in __getattr__')
# return self.__dict__[item]
def __getattribute__(self, item):
print('from in __getattribute__')
raise AttributeError() f1=Foo(10)
f1.x
f1.ssss
输出结果:
from in __getattribute__
from in __getattr__
from in __getattribute__
from in __getattr__
九 __setitem__,__getitem,__delitem__
#!/usr/bin/env python
#-*-coding:utf-8-*- #注意看item赋值的时候都是用的[] 中括号
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
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('zzl')
f1['age']=18
f1['age1']=19
del f1.age1
del f1['age']
f1['name']='cyy'
print(f1.__dict__) 输出结果:
del obj.key时,执行我
del obj[key]时,执行我
{'name': 'cyy'}
十__str__,__repr__,__format__
#__str__:str函数或者print函数--->obj.__str__(),也就是打印对象时,默认输出该方法的返回值
#repr或者交互解释器--->obj.__repr__()
# 如果__str__没有被定义,那么就会使用__repr__来代替输出
# 注意:这俩方法的返回值必须是字符串,否则抛出异常
class Foo: # def __str__(self):
# return 'zzl' def __repr__(self):
return 'cyy' obj = Foo()
print(obj) #输出cyy
class Foo:
def __str__(self):
return 'zzl'
def __repr__(self):
return 'cyy'
obj = Foo()
print(obj)
#输出zzl
date_dic={
'ymd':'{0.year}:{0.month}:{0.day}',
'dmy':'{0.day}/{0.month}/{0.year}',
'mdy':'{0.month}-{0.day}-{0.year}',
}
class Date:
def __init__(self,year,month,day):
self.year=year
self.month=month
self.day=day
def __format__(self, format_spec):
if not format_spec or format_spec not in date_dic:
format_spec='ymd'
fmt=date_dic[format_spec]
return fmt.format(self)
d1=Date(2016,12,29)
print(format(d1))
print('{:dmy}'.format(d1))
输出结果:
2016:12:29
29/12/2016
十一__slots__
#!/usr/bin/env python
#-*-coding:utf-8-*- class Foo:
__slots__=['x','y']
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z f=Foo(1,2,3)
报错:
AttributeError: 'Foo' object has no attribute 'z'
解释&总结:
1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个
字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给
实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义了__slots__后的类不再 支持一些普通类特性了,比如多继承。大多数情况下,你应该
只在那些经常被使用到 的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 。
关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。
十二:__next__和__iter__实现迭代器协议
# 实现range的迭代器
class Foo:
def __init__(self,start,stop):
self.num=start
self.stop=stop def __iter__(self):
return self def __next__(self):
if self.num == self.stop:
raise StopIteration
n=self.num
self.num+=1
return n
f=Foo(1,5)
# print(next(f))
# print(next(f))
# print(next(f))
# print(next(f))
# print(next(f))
# print(next(f)) for i in f:
print(i) 输出结果:
1
2
3
4 注:如果用next,当num等于5的时候会抛出异常
十三:反射
什么是反射?
通过一个字符串名字反射成一个数据属性,python中的一切事物都是对象(都可以使用反射)
四个可以实现自省的函数
hasattr getattr setatar delattr
class Chinese:
country='China'
def __init__(self,name,age):
self.name=name
self.age=age p1=Chinese('zzl',18) print(hasattr(p1,'x'))
print(getattr(p1,'name'))
print(getattr(p1,'x','not find'))
print(getattr(p1,'age','not find'))
setattr(p1,'x',100) #---》p1.x=100
print(p1.__dict__)
delattr(p1,'x')
print(p1.__dict__)
#输出结果:
False
zzl
not find
18
{'name': 'zzl', 'age': 18, 'x': 100}
{'name': 'zzl', 'age': 18}
导入其他模块,利用反射查找该模块是否存在某个方法
#!/usr/bin/env python
# -*- coding:utf-8 -*- def test():
print('from the test')
#!/usr/bin/env python
# -*- coding:utf-8 -*- """
程序目录:
module_test.py
index.py 当前文件:
index.py
""" import module_test as obj #obj.test() print(hasattr(obj,'test')) getattr(obj,'test')()
输出结果:
True
from the test
反射的好处:
一.实现可插拔机制
可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能
ftpserver端
#!/usr/bin/env python
#-*-coding:utf-8-*- class Ftpserver:
def __init__(self,ip):
self.ip=ip
#
# def conn(self):
# print('正在连接 %s...'%self.ip)
ftpclient端
#!/usr/bin/env python
#-*-coding:utf-8-*- import ftpserver if hasattr(ftpserver,'Ftpserver'):
cls_fs=getattr(ftpserver,'Ftpserver')
print(cls_fs)
obj=cls_fs('2.2.2.2')
if hasattr(obj,'conn'):
func=getattr(obj,'conn')
func()
print('其他代码') 如果server端不写conn的函数,输出结果是: <class 'ftpserver.Ftpserver'>
其他代码 已经写了conn函数,输出结果是:
<class 'ftpserver.Ftpserver'>
正在连接 2.2.2.2...
其他代码 这样就实现了可插拔机制
十四 __setattr__,__delattr__,__getattr__
#!/usr/bin/env python
#-*-coding:utf-8-*- class Foo:
x=1
def __init__(self,y):
self.y=y def __getattr__(self, item):
print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value):
print('----> from setattr')
# self.key=value #这就无限递归了,你好好想想
self.__dict__[key]=value #应该使用它 def __delattr__(self, item):
print('----> from delattr')
# del self.item #无限递归了
self.__dict__.pop(item) #__setattr__添加/修改属性会触发它的执行
f1=Foo(180)
print(f1.__dict__) # 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
f1.z=102
print(f1.__dict__) #__delattr__删除属性的时候会触发
f1.__dict__['a']=3#我们可以直接修改属性字典,来完成添加/修改属性的操作
del f1.a
print(f1.__dict__) #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
f1.aaaa 输出结果:
----> from setattr
{'y': 180}
----> from setattr
{'y': 180, 'z': 102}
----> from delattr
{'y': 180, 'z': 102}
----> from getattr:你找的属性不存在
十五 上下文管理
open函数既能够当做一个简单的函数使用,又能够作为上下文管理器。
with open('a.txt', 'w') as f:
f.write('hello')
f.write('world')
自定义上下文管理器:
要实现上下文管理器,必须实现两个方法 – 一个负责进入语句块的准备操作,另一个负责离开语句块的善后操作。同时,我们需要两个参数:文件名和打开方式。
Python类包含两个特殊的方法,分别名为:__enter__以及__exit__(双下划线作为前缀及后缀)。
__enter__ 方法将在进入代码块前被调用。
__exit__ 方法则在离开代码块之后被调用(即使在代码块中遇到了异常)。
class deamon:
def __enter__(self):
print('Entering the block') #出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量
def __exit__(self, *unused):
print('Exiting the block') #with中代码块执行完毕时执行
with deamon():
print('In the block')
# 输出:
# Entering the block
# In the block
# Exiting the block
- 没有传递任何参数。
- 在此没有使用“as”关键词。
- 下面我们将讨论__exit__方法的参数设置
class PyOpen:
def __init__(self, filename, mode): #通过__init__接受两个参数
self.filename = filename
self.mode = mode
def __enter__(self):
self.openedFile = open(self.filename, self.mode) #打来文件并返回
return self.openedFile
def __exit__(self, *unused): #当离开语句块的时候关闭文件
self.openedFile.close()
with PyOpen('b.txt', 'w') as f: #模仿文件使用我们自己的上下文管理
f.write('Hello World')
如何去处理异常?
如果语句块内部发生了异常,__exit__方法将被调用,而异常将会被重新抛出(re-raised)。当处理文件写入操作时,大部分时间你肯定不希望隐藏这些异常,所以这是可以的。而对于不希望重新抛出的异常,我们可以让__exit__方法简单的返回True来忽略语句块中发生的所有异常(大部分情况下这都不是明智之举)。
class PyOpen:
def __init__(self, filename, mode): #通过__init__接受两个参数
self.filename = filename
self.mode = mode
def __enter__(self):
self.openedFile = open(self.filename, self.mode) #打来文件并返回
return self.openedFile
def __exit__(self, exc_type, exc_val, exc_tb):
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with PyOpen('b.txt', 'w') as f: #模仿文件使用我们自己的上下文管理
f.write('Hello World')
raise AttributeError('出现异常啦')
print('还可以玩')
输出结果:
<class 'AttributeError'>
出现异常啦
<traceback object at 0x0000000000B7B988>
还可以玩
好处:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制,你无须再去关系这个问题,这将大有用处
十六 metaclass
元类就是用来创建类的“东西”。你创建类就是为了创建类的实例对象,不是吗?但是我们已经学习到了Python中的类也是对象。好吧,元类就是用来创建这些类(对象)的,元类就是类的类,可以这样理解:
MyClass = MetaClass()
MyObject = MyClass()
__metaclass__属性:
class Mytype(type):
def __init__(self,what,bases=None,dict=None):
print(what,bases,dict) def __call__(self, *args, **kwargs):
print('--->')
obj=object.__new__(self)
self.__init__(obj,*args,**kwargs)
return obj class Room(metaclass=Mytype):
def __init__(self,name):
self.name=name r1=Room('zzl')
print(r1.__dict__) 输出:
Room () {'__module__': '__main__', '__init__': <function Room.__init__ at 0x0000000000A8E2F0>, '__qualname__': 'Room'}
--->
{'name': 'zzl'}
python之面向对象深入探测的更多相关文章
- python基础——面向对象编程
python基础——面向对象编程 面向对象编程——Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的 ...
- Python的面向对象3
接下来,我们接着讲Python的面向对象,在上一次的博客中,我们详细介绍了类与对象的属性,今天,我们来详细介绍一下面向对象中的方法! 1.定义实例方法 一个实例的私有属性就是以__开头的属性,无法被外 ...
- Python的面向对象2
我们接着讲解Python的面向对象 1.初始化实例属性 在现实生活中,一种类型的实例会具有相同的某些属性,把这些实例划分为一个类型,则这些实例必然有相似的部分.但是,在创建实例之后,我们一个一个的为实 ...
- Python的面向对象1
今天,我们来介绍Python的面向对象编程,其实面向对象并不陌生,在C++ ,Java ,PHP中也有大量使用! 好了,我们来步入正题! 那什么是面向对象编程呢? 1. 面向对象编程是一种程序设计 ...
- My way to Python - Day05 - 面向对象-思维导图
My way to Python - Day05 - 面向对象 思维导图
- Python进阶---面向对象的程序设计思想
Python的面向对象 一.面向过程与面向对象的对比 面向过程的程序设计的核心是过程(流水线式思维),过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西. 优 ...
- Python之面向对象一
引子 小游戏:人狗大战 角色:人和狗 角色属性:姓名,血量,战斗力和性别(种类) 技能:打/咬 用函数实现人打狗和狗咬人的情形 def Dog(name,blood,aggr,kind): dog = ...
- python基础——面向对象进阶下
python基础--面向对象进阶下 1 __setitem__,__getitem,__delitem__ 把对象操作属性模拟成字典的格式 想对比__getattr__(), __setattr__( ...
- python基础——面向对象进阶
python基础--面向对象进阶 1.isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 ...
随机推荐
- 【C#】判断字符串中是否包含指定字符串,contains与indexof方法效率问题
#方法一:使用string.Contains方法 string.Contains是大小写敏感的,如果要用该方法来判断一个string是否包含某个关键字keyword,需要把这个string和这个key ...
- 用 python 写一个年会抽奖小程序
使用 pyinstaller 打包工具常用参数指南 pyinstaller -F demo.py 参数 含义 -F 指定打包后只生成一个exe格式的文件 -D –onedir 创建一个目录,包含exe ...
- 第二节:框架前期准备篇之AutoFac常见用法总结
一. 说在前面的话 凡是大约工作在两年以上的朋友们,或多或少都会接触到一些框架搭建方面的知识,只要一谈到框架搭建这个问题或者最佳用法这个问题,势必会引起一点点小小的风波,我说我的好,他说他的好,非常容 ...
- Geometric regularity criterion for NSE: the cross product of velocity and vorticity 1: $u\times \om$
在 [Chae, Dongho. On the regularity conditions of suitable weak solutions of the 3D Navier-Stokes equ ...
- pyqt5-按钮基类-QAbstractButton
QAbstractButton 是抽象类 from PyQt5.QtWidgets import QApplication, QWidget,QAbstractButton import sys f ...
- windows 7中的windows键相关的快捷键
引用 https://support.microsoft.com/zh-cn/help/976857 Windows 键的位置 如果不清楚 Windows 键的位置,请参照下图: 常用的 Window ...
- Basic Calculator I && II && III
Basic Calculator I Implement a basic calculator to evaluate a simple expression string. The expressi ...
- vim配置(使用Vundle)
1.前言 Vim的配置文件位于~/.vimrc,文件使用VimScript语法来编写. 2. vim插件管理 Vundle是一个全自动的插件管理器,让我们通过维护插件列表的方式管理插件.它为安装.更新 ...
- 有了GPRS为什么还要LoRa和NB-IoT?【转】
转自:https://blog.csdn.net/i_am_Banmei2/article/details/81869724 与其说是GPRS和NB-IoT的比较,不如说是传统网络与新兴网络的比较,我 ...
- android SDK模拟器环境搭建
一.下载安装android SDK 两种方式: (1)官网下载(需FQ):https://developer.android.com/studio/index.html (2)无需FQ下载:http: ...