python面向对象
1.面向对象的定义
面向对象实质是一种编程框架结构,只要使用类编程就是面向对象编程,这种说法是有问题的。
使用函数也可以做到面向对象编程
def school(name,addr,type):
def init(name, addr, type):
sch = {
'name': name,
'addr': addr,
'type': type,
'kao_shi': kao_shi,
'zhao_sheng': zhao_sheng,
}
return sch
def kao_shi(school):
print('%s 学校正在考试' %school['name'])
def zhao_sheng(school):
print('%s %s 正在招生' %(school['type'],school['name']))
return init(name,addr,type)
s1=school('oldboy','沙河','私立学校')
print(s1)
print(s1['name'])
s1['zhao_sheng'](s1)
s2=school('清华','北京','公立学校')
print(s2)
print(s2['name'],s2['addr'],s2['type'])
s2['zhao_sheng'](s2)
Class 类
一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。在类中定义了这些对象的都具备的属性(variables(data))、共同的方法
Object 对象
一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同
Encapsulation 封装
在类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法
Inheritance 继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承
Polymorphism 多态
一个接口,多种实现
2.类的创建
#用面向对象编程独有的语法class去实现面向对象设计
class Dog:
def __init__(self,name,gender,type):
self.name=name
self.gender=gender
self.type=type
def bark(self):
print('一条名字为[%s]的[%s],狂吠不止' %(self.name,self.type))
def yao_ren(self):
print('[%s]正在咬人' %(self.name))
def chi_shi(self):
print('[%s]正在吃屎' %(self.type))
dog1=Dog('alex','female','京巴')
3.面向对象的继承
class Dad:
'这个是爸爸类'
money=10
def __init__(self,name):
print('爸爸')
self.name=name
def hit_son(self):
print('%s 正在打儿子' %self.name)
class Son(Dad):
money = 1000000000009
def __init__(self,name,age):
self.name=name
self.age=age
def hit_son(self):
print('来自儿子类')
继承的循序
#coding:utf-8
class A:
# def test(self):
# print('A')
pass
class B(A):
# def test(self):
# print('B')
pass
class C(A):
# def test(self):
# print('C')
pass
class D(B):
# def test(self):
# print('D')
pass
class E(C):
# def test(self):
# print('E')
pass
class F(D,E):
# def test(self):
# print('F')
pass
f1=F()
f1.test() #经典类:F->D->B->A-->E-->
# print(F.__mro__)
#F-->D->B-->E--->C--->A新式类
4.接口继承
import abc
class All_file(metaclass=abc.ABCMeta): ##不能被实例化
@abc.abstractmethod
def read(self): #被abc.abstractmethod 修饰的方法必须被复写,不然会报错
pass
@abc.abstractmethod
def write(self):
pass
class Disk(All_file):
def read(self):
print('disk read')
def write(self):
print('disk write')
class Cdrom(All_file):
def read(self):
print('cdrom read')
def write(self):
print('cdrom write')
class Mem(All_file):
def read(self):
print('mem read')
def write(self):
print('mem write')
#
m1=Mem()
m1.read()
m1.write()
5.类的组合
class school(object):
def __init__(self,name,addr,course):
self.name=name
self.addr=addr
self.course=course
def zhao(self):
print('%s可以找1000人' %self.name)
class course(object):
def __init__(self,name,period):
self._name=name
self.period=period
def start(self):
print('%s 开课了' %self.name)
c1=course('英语','10')
s=school('beida','beij',c1)
print(s.__dict__)
6.类的反射
class People:
country = 'china'
def __init__(self,name,age):
self.name = name
self.age = age
def talk(self):
print('%s is talking' % self.name)
obj=People('egon',18)
# print(obj.name)
# print(obj.talk)
# hasattr
print(hasattr(obj,'name')) #obj.name #obj.__dict__['name']
print(hasattr(obj,'talk'))
# getattr
print(getattr(obj,'namexxx',None))
print(getattr(obj,'talk',None))
# setattr
setattr(obj,'sex','male')
print(obj.sex)
# delattr
delattr(obj,'age')
print(obj.__dict__)
7.动态导入模块
第一种python内部使用,不建议使用
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:CarsonLi
'''Python 解释器内部动态导入方式'''
module_name='import_lib.metaclass' #模块名的字符串
import_lib=__import__(module_name) #这是解释器自己内部用的
'''import_lib代表的其实是这个模块,而不是下面的metaclass'''
c=import_lib.metaclass.Ccc("Bert")#调用下面的方法
print(c.name) #运行结果:Bert
第二种 官方建议使用
#!/usr/bin/env python
# _*_ coding:utf-8 _*_
# Author:CarsonLi
'''官方建议用这个'''
import importlib
module_name='import_lib.metaclass' #模块名的字符串
metaclass=importlib.import_module(module_name) #导入的就是需要导入的那个metaclass
c=metaclass.Ccc("Bert") #调用下面的方法
print(c.name) #运行结果:Bert
8.双下划线的attr方法
只有在属性不存在时会自动触发__getattr__
删除属性是会触发__delattr__
设置属性是会触发__setattr__
class Foo:
def __init__(self,name):
self.name=name
def __getattr__(self, item):
print('你找的属性【%s】不存在' %item)
def __setattr__(self, k,v):
print('执行setattr',k,v)
if type(v) is str:
print('开始设置')
# self.k=v #触发__setattr__
self.__dict__[k]=v.upper()
else:
print('必须是字符串类型')
def __delattr__(self, item):
print('不允许删除属性【%s】' %item)
# print('执行delattr',item)
# del self.item
# self.__dict__.pop(item)
f1=Foo('alex')
# f1.age=18 #触发__setattr__
# print(f1.__dict__)
# print(f1.name)
# print(f1.age)
# print(f1.gender)
# print(f1.slary)
print(f1.__dict__)
del f1.name
print(f1.__dict__)
9.授权
可以读某些内建方法改写,并添加权限管理
import time
class FileHandle(object):
def __init__(self,filename,mode='r',encoding='utf-8'):
# self.filename=filename
self.file=open(filename,mode,encoding=encoding)
self.mode=mode
self.encoding=encoding
def write(self,line):
print('------------>',line)
t=time.strftime('%Y-%m-%d %X')
self.file.write('%s %s' %(t,line))
def __getattr__(self, item):
# print(item,type(item))
# self.file.read
return getattr(self.file,item)
f1=FileHandle('a.txt','w+')
# print(f1.file)
# print(f1.__dict__)
# print('==>',f1.read) #触发__getattr__
# print(f1.write)
f1.write('1111111111111111\n')
f1.write('cpu负载过高\n')
f1.write('内存剩余不足\n')
f1.write('硬盘剩余不足\n')
# f1.seek(0)
# print('--->',f1.read())
10.__call__方法
类中实现了__call__方法,则对应的实例可以被调用。
class Foo:
def __call__(self, *args, **kwargs):
print('实例执行啦 obj()')
f1=Foo()
f1() #f1的类Foo 下的__call__
Foo() #Foo的类 xxx下的__call__
11.item系列方法
__getitem__、__setitem__ 、__delitem__ 相对于__setattr__ 、__getattr__ 、__delattr__
使用[ ]方式调用字典,而attr系列是使用‘.’方式调用底层字典的
class Foo(object):
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.name='egon' #---->setattr-------->f1.__dict__['name']='egon'
f1['name']='egon'#--->setitem--------->f1.__dict__['name']='egon'
f1['age']=18
print('===>',f1.__dict__)
# del f1.name
# print(f1.__dict__)
#
# print(f1.age)
del f1['name']
print(f1.__dict__)
print(f1['age'])
raise S
12.__slots__方法
这个方法定义是可以节省内存的,试想一下一个类实例化很多对象,每个对象都有一个底层的字典,自然会很占用内存
。使用__slots__方法的类,是没有底层字典的。
另外__slots__是无法被继承的
class Foo(object):
__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__)
print(Foo.__slots__)
print(f1.__slots__)
f1.name='egon'
f1.age=17
print(f1.name)
print(f1.age)
# f1.gender='male'
f2=Foo()
print(f2.__slots__)
f2.name='alex'
f2.age=18
print(f2.name)
13.迭代器协议
迭代器的实质是实现了next()方法的对象,常见的元组、列表、字典都是迭代器。
迭代器中重点关注两种方法:
__iter__方法:返回迭代器自身。可以通过python内建函数iter()调用。
__next__方法:当next方法被调用的时候,迭代器会返回它的下一个值,如果next方法被调用,但迭代器没有只可以返回,就会引发一个StopIteration异常。该方法可以通过 python 内建函数next()调用。
举例
class Foo(object):
def __init__(self,n):
self.n=n
def __iter__(self):
return self
def __next__(self): ####注 python2中使用的是next()方法
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__()
print(i) #obj.__next_()
14.__format__
###自定制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,'asdfasdfsadfasdfasdfasdfasdfasdfasdfasdfasdfasdfasd'))
15.上下文管理协议
with obj as f:
'代码块'
1.with obj ----》触发obj.__enter__(),拿到返回值
2.as f----->f=返回值、
3.with obj as f 等同于 f=obj.__enter__()
4.执行代码块
一:没有异常的情况下,整个代码块运行完毕后去触发__exit__,它的三个参数都为None
二:有异常的情况下,从异常出现的位置直接触发__exit__
a:如果__exit__的返回值为True,代表吞掉了异常
b:如果__exit__的返回值不为True,代表吐出了异常
c:__exit__的的运行完毕就代表了整个with语句的执行完毕
class Foo:
def __init__(self,name):
self.name=name
def __enter__(self):
print('执行enter')
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print('执行exit')
print(exc_type)
print(exc_val)
print(exc_tb)
return True
with Foo('a.txt') as f:
print(f)
print(asdfsaasdfasdfasdfasdfasfasdfasdfasdfasdfasfdasfd) #触发__exit__
print(f.name)
print('-----------------')
print('-----------------')
print('-----------------')
print('-----------------')
print('-----------------')
print('-----------------')
print('-----------------')
print('000000000000000000000000000000000000000000000')
16.__getattr__和__getattribute__的区别
object.__getattr__(self, name)
找不到attribute的时候,会调用getattr,返回一个值或AttributeError异常。
object.__getattribute__(self, name)
无条件被调用,通过实例访问属性。如果class中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或引发AttributeError异常)
(1)调用一个不存在的属性
class User:
def __init__(self,info={}):
self.info = info
# def __getattr__(self, item):
# return self.info[item]
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
print(user.name)
(2)加了__getattr__之后就可以调用了
class User:
def __init__(self,info={}):
self.info = info
#__getattr__是在查找不到属性的时候调用
def __getattr__(self, item):
return self.info[item]
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
print(user.name) #derek
(3)__getattribute__
class User:
def __init__(self,info={}):
self.info = info
#__getattr__是在查找不到属性的时候调用
def __getattr__(self, item):
return self.info[item]
#__getattribute不管属性存不存在,都访问这个
def __getattribute__(self, item):
return "zhang_derek"
if __name__ == '__main__':
user = User(info={"name":"derek","age":24})
#不管属性存不存在,都走__getattribute__
print(user.name) #zhang_derek #即使属性存在也走__getattribute__
print(user.test) #zhang_derek #不存在的属性也能打印
print(user.company) #zhang_derek #不存在的属性也能打印
17.__new__和__init__的区别
(1)__new__方法如果不返回对象,不会执行init方法
class User:
def __new__(cls, *args, **kwargs):
print("in new")
def __init__(self,name):
print("in init")
self.name = name
# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
user = User("derek")
运行结果:没有调用init方法
(2)返回对象就会执行init方法
class User:
def __new__(cls, *args, **kwargs):
print("in new") #in new
print(cls) #cls是当前class对象 <class '__main__.User'>
print(type(cls)) #<class 'type'>
return super().__new__(cls) #必须返回class对象,才会调用__init__方法
def __init__(self,name):
print("in init") #in init
print(self) #self是class的实例对象 <__main__.User object at 0x00000000021B8780>
print(type(self)) #<class '__main__.User'>
self.name = name
# new是用用来控制对象的生成过程,在对象生成之前
# init是用来完善对象的
# 如果new方法不返回对象,则不会调用init函数
if __name__ == '__main__':
user = User(name="derek")
#总结
# __new__ 用来创建实例,在返回的实例上执行__init__,如果不返回实例那么__init__将不会执行
# __init__ 用来初始化实例,设置属性什么的