三大编程范式(面向过程编程、函数式编程、面向对象编程)python
编程范式就是编程的方法论,表示一种编程风格,不一样风格没有高低之分编程
编程进化论:非结构化程序不断地结构化(函数区分功能,面向对象把功能和数据整合到一块儿)后端
面向对象设计例子(不必定要用class来写,def也能够写):app
def dog(name, gender, type):
def jiao(dog):
print("一条狗[%s], barking" %dog["name"])
def play(dog):
print("一条[%s]playing" %dog["type"])
def init(name, gender, type):
dog1 = {"name": name,
"gender": gender,
"type": type,
"jiao": jiao,
"play": play,
}
return dog1
return init(name, gender, type)
d1 = dog('aaa', 'male', 'za')
d2 = dog('bbb', 'female', 'jb')
print(d1)
print(d2)
d1['jiao'](d1)
d2['play'](d2)
类:把一类事物的相同特征和动做(数据属性和函数属性)整合到一块儿就是类,类是一个抽象的概念(只是一个模板、总结概括)函数式编程
对象:就是基于类而建立的一个具体的事物(具体存在的),也是特征和动做整合到一块儿函数
面向对象设计:把数据属性和函数属性整合到一块儿造成类,就是面向对象设计,经过类实例化出对象,就叫实例化的过程工具
面向对象编程:固定格式,用class定义类的方式去写面向对象设计的程序this
在python中声明函数和声明类很类似spa
声明类名时,规范是类名首字母要大写设计
类名加()表示实例化出一个对象(对象=实例),类的返回值就是一个具体的实例,本质也是一个return,函数加()表示运行一段逻辑
class Chinese:
'this is a class of Chinese'
pass
print(Chinese)#结果是<class '__main__.Chinese'>,右键执行文件时,文件名变为__main__
p1 = Chinese()#实例化
print(p1)
经典类与新式类:python2中区分经典类和新式类
经典类特色:类名后直接是冒号
新式类特色:类名后是(object)
python3中统一都是新式类
类是用来描述一类事物,类的对象指的是这一类事物中的一个个体
是事物就要有属性,属性分为:
1.数据属性:就是变量
2.函数属性:就是函数,在面向对象里一般称为方法
类和对象均用点来访问本身的属性
类生产对象的过程叫作实例化,类实例化的结果就是一个对象,或者叫作一个实例 (对象=实例)
class Chinese:
'这是一个中国人的类'
party = 'cp'
def spit():
print('正在spit')
def cut_in_line(self):
print('走到了前面')
print(Chinese.party)#类和对象均用点来访问本身的属性,本质上是到本身的属性字典里找东西
Chinese.spit()
print(dir(Chinese))#查看函数属性,输出是一个列表,里面是属性名
print(Chinese.__dict__)#查看类的属性字典,key为属性名,value为属性值
print(Chinese.__dict__['party'])
Chinese.__dict__['spit']()
类的其余属性:
class Chinese:
'这是一个中国人的类'
party = 'cp'
def spit():
print('正在spit')
def cut_in_line(self):
print('走到了前面')
print(Chinese.__name__)#显示类名
print(Chinese.__doc__)#显示类的文档
print(Chinese.__base__)#python中全部的类都有一个共同的祖先:object
print(Chinese.__bases__)#以元组的形式显示类的祖先
print(Chinese.__module__)#显示类所在模块
print(Chinese.__class__)#实例对应的类(仅新式类中)
class Chinese:
'这是一个中国人的类'
party = 'cp'
def __init__(name, age, gender): #类会自动检索到这个初始化函数,会自动将类接受的参数传给初始化参数,
初始化函数逻辑加载一遍后会自动return 一个字典,不须要用return __init__()来接收它return的值
dic = {'name': name, 'age': age, 'gender': gender}
return dic
def spit():
print('正在spit')
def cut_in_line(self):
print('走到了前面')
p1 = Chinese('cyx', 13, 'male')#实例化,参数会自动传给__init__函数
class Chinese:
'这是一个中国人的类'
party = 'cp'
def __init__(self, name, age, gender):#类当中必须有一个初始化的函数来定制每个对象的属性,函数必须有一个self参数,其次再写数据属性
print('start running')
self.mingzi = name #self是实例自己,就是p1,self.mingzi表明给self赋予了一个mingzi属性
self.nianji = age #p1.nianji = age
self.xingbie = gender
print('end running')
def spit():
print('正在spit')
def cut_in_line(self):
print('%s 走到了前面' %self.mingzi)
p1 = Chinese('cyx', 13, 'male')#实例化,参数会自动传给__init__函数,实例化本质上就是调用了init函数的运行,p1传给了self作参数
print(p1.__dict__)#输出p1的字典形式,实例只有数据属性,没有函数属性,由于实例是执行__init__方法生成的一个字典,里面并不包含函数属性
print(p1.__dict__['mingzi'])#同下一行代码
print(p1.xingbie)
print(p1.party)#实例如今__init__的做用域里找key,没找到,再到外层Chinese中找到party,若是类中找不到就会报错,因此实例能够调到类的数据属性,跟函数的做用域同样
Chinese.cut_in_line(p1)
# p1.spit()#class会默认将p1传给 spit(),spit()不须要参数,因此会报错
p1.cut_in_line()#class会默认将p1传给cut_in_line()
实例只有数据属性,函数属性找类要,这么作的好处是:实例经过引用的方式去调类的属性,这样能够省内存
class Chinese:
'这是一个中国人的类'
party = 'cp'
def __init__(self, name, age, gender):
self.mingzi = name
self.nianji = age
self.xingbie = gender
def spit(self):
print('%s正在spit' %self.mingzi)
def cut_in_line(self):
print('%s 走到了前面' %self.mingzi)
def eat_food(self, food):
print('%s正在吃%s' %(self.mingzi, food))
p1 = Chinese('cyx', 13, 'male')
p1.spit()
p1.eat_food('banana')
p2 = Chinese('jik', 12, 'male')
p2.eat_food('apple')
print(dir(p2))#实例也有dir方法
凡是类调用的方法,默认都有一个参数self,放在函数的第一个位置,这是函数独有的语法结构要求的,这样在调用每一个函数时,类会自动把实例传到第一个位置
class Chinese:
'这是一个中国人的类'
party = 'cp'
def __init__(self, name, age, gender):
self.mingzi = name
self.nianji = age
self.xingbie = gender
def spit(self):
print('%s正在spit' %self.mingzi)
def cut_in_line(self):
print('%s 走到了前面' %self.mingzi)
def eat_food(self, food):
print('%s正在吃%s' %(self.mingzi, food))
#查看类属性
print(Chinese.party)
#修改类属性
#改数据属性
Chinese.party = 'CP'
print(Chinese.party)
p1 = Chinese('yjj', 23, 'girl')
print(p1.party)
#改函数属性
def test(self):
print('test')
Chinese.play_ball = test
p1.play_ball()#类的函数属性修改会立马体现给实例,由于实例是经过调用类的函数
#增长类属性
#加数据属性
Chinese.country = 'China'
print(Chinese.country)
print(p1.country)
#加函数属性
def play_ball(self, ball):
print('%s在打%s' %(self.mingzi, ball))
Chinese.play = play_ball
p1.play('football')
#删除类属性
del Chinese.party
del Chinese.country
print(Chinese.__dict__)
class Chinese:
'这是一个中国人的类'
party = 'cp'
def __init__(self, name, age, gender):
self.mingzi = name
self.nianji = age
self.xingbie = gender
def eat_food(self, food):
print('%s正在吃%s' % (self.mingzi, food))
#生成实例
p1 = Chinese('ypp', '18', 'boy')
#查看实例属性字典
print(p1.__dict__)
#查看实例属性
print(p1.mingzi)
print(p1.eat_food)
#增长
p1.hobby = 'reading'
print(p1.__dict__)
print(p1.hobby)
def test(self):
print('实例的函数属性')
p1.test = test
print(p1.__dict__)
print(p1.test)
# p1.test()#报错,这里p1调用的是实例的类,class只有在实例调用类的方法时,才会自动传self
p1.test(p1)#上一行代码修改为此行便可运行
# #不要修改底层的属性字典,虽然能够实现
# p1.__dict__['gh'] = 'jk'
# print(p1.__dict__)
# print(p1.gh)
#修改
p1.nianji = 45
print(p1.__dict__)
print(p1.nianji)
#删除
del p1.nianji
print(p1.__dict__)
例1:
class Chinese:
country='China'
def __init__(self, name):
self.name = name
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese('alex')
print(p1.country)#访问类的属性
p1.country = 'Japan'#在p1字典里新增,跟类字典没有关系
print(Chinese.country)#China
print(p1.country)#Japan
例2:
country = 'China'
class Chinese:
def __init__(self, name):
self.name = name
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese('alex')
print(p1.country)#报错,p1只在类里面找,找不到不会去外面找
例3:init只特殊在self,不能return值,其他跟函数没有区别
country = 'China'
class Chinese:
def __init__(self):
name = input('请输入用户名:')
self.name = name
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese()
print(p1.__dict__)
此例属于输入和函数耦合到一块儿,不符合规范,修改以下
country = 'China'
class Chinese:
def __init__(self, name):
self.name = name
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
name = input('>>>:')
p1=Chinese(name)
print(p1.__dict__)
例4:
country = 'China'
class Chinese:
def __init__(self, name):
self.name = name
print(country)#没加点代表其既不是类的属性也不是实例的属性,只是一个普通变量,能够到类外面找到全局变量
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese('cyx')
例5:
country = 'China2'
class Chinese:
country = 'China1'#只有类或实例加.能够调用到,country = 'China1'存在于类的字典里,普通变量country不会跑到类或实例的字典里去找
def __init__(self, name):
self.name = name
print(country)#调不到类的country
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese('cyx')
例6:
class Chinese:
country = 'China'#只有类或实例加.能够调用到,country = 'China1'存在于类的字典里,普通变量country不会跑到类或实例的字典里去找
l = ['a', 'b']
def __init__(self, name):
self.name = name
def play_ball(self, ball):
print('%s 正在打 %s' %(self.name, ball))
p1=Chinese('cyx')
print(p1.l)
# p1.l = [1, 2, 3]#给p1新增一个属性
# print(p1.__dict__)
# print(Chinese.l)
p1.l.append('c')#没有给p1新定义属性,l.append操做的是类的属性
print(p1.__dict__)
print(Chinese.l)
class Room:
def __init__(self, name, owner, width, length, height):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.height = height
@property #能够封装逻辑,本身定制一段逻辑,让用户调用的时候彻底感知不到后端执行的是什么样的逻辑,就像是在调用普通的数据属性同样
def cal_area(self):
return self.width * self.length
r1 = Room('bedroom', 'tom', 100, 100, 10000)
r2 = Room('baseroom', 'jerry', 10, 10, 100)
print(r1.cal_area)
print(r2.cal_area)#让函数属性看起来像数据属性,调用方式不须要加()
用处:跟实例没有任何关系,只是类级别的操做的时候会用
class Room:
tag = 1
def __init__(self, name, owner, width, length, height):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.height = height
@property
def cal_area(self):
return self.width * self.length
def test(self):
print('from test', self.name)
@classmethod#专门给类用的
def tell_info(cls, x):
print(cls)
print(cls.tag, x)
Room.tell_info(10)#会自动传入第一个参数Room
class Room:
tag = 1
def __init__(self, name, owner, width, length, height):
self.name = name
self.owner = owner
self.width = width
self.length = length
self.height = height
@property
def cal_area(self):
return self.width * self.length
def test(self):
print('from test', self.name)
@classmethod#专门给类用的
def tell_info(cls, x):
print(cls)
print(cls.tag, x)
@staticmethod
def play_ball(a, b, c):
print('%s %s %s正在踢球' %(a, b, c))#类和实例调用都没有问题
def test2(x, y):
print(x, y)#毫无心义,这不是静态方法,用类调用没问题,用实例调用会出问题 ,由于实例会把本身传入第一个参数,无人接收
Room.play_ball('tom', 'jerry', 'jack')
r1 = Room('bedroom', 'tom', 100, 100, 10000)
r1.play_ball('tom', 'jerry', 'jack')
Room.test2(1, 2)
r1.test2(1, 2)#会报错
class School:
def __init__(self, name, addr):
self.name = name
self.addr = addr
def enroll_stu(self):
print('%s 正在招生' %self.name)
class Course:
def __init__(self, name, price, period, school):
self.name = name
self.price = price
self.period = period
self.school = school
s1=School('xdf','北京')
s2=School('xdf','南京')
s3=School('xdf','天津')
msg = '''
1新东方 北京校区
2新东方 南京校区
3新东方 天津校区
'''
while True:
print(msg)
menu = {
'1': s1,
'2': s2,
'3': s3,
}
choice = input('请选择学校:')
sch_obj = menu[choice]
name_choice = input('课程名:')
price_choice = input('课程费用:')
period_choice = input('课程周期:')
new_course = Course(name_choice, price_choice, period_choice, sch_obj)
print("课程%s属于%s学校" %(new_course.name, new_course.school.name))
继承分单继承(括号里有一个父类)和多继承(括号里有多个父类)
class SubClass(ParentClass1, ParentClass2):
子类继承了父类的全部属性,子类自定义的属性若是跟父类重名,等于子类在本身的字典里新建了一个属性,找的时候如今本身这里找
class Dad:
'这个是父类'
money = 10
def __init__(self, name):
print('father')
self.name = name
def hit_son(self):
print('%s正在打儿子' %self.name)
class Son(Dad):
money = 1000000
s1 = Son('cyx')
print(s1.money)
print(Dad.money)
接口继承:表明父类当中规定好了子类必须实现什么方法,可是父类里不去实现,子类只要继承了父类,子类必须在本身的类中去具体的实现父类规定的方法
接口:一个方法,一个具体的函数
归一化设计:使得高层的外部使用者能够不加区分的处理全部接口兼容的对象集合
import abc
class All_file(metaclass=abc.ABCMeta):#父类规定全部子类必须实现的方法,接口类的方法不用实现内部逻辑,只是来规范子类,没有必要实例化
@abc.abstractmethod
def read(self):#接口
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')
m1 = Mem()#会报错,由于父类当中规定好了子类必须实现什么方法,可是父类里不去实现,子类只要继承了父类,子类必须在本身的类中去具体的实现父类规定的方法
继承顺序
class A:
def test(self):
print('A')
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 E C A 新式类的继承顺序
F D B A E C 经典类的继承顺序
经典类深度优先,新式类广度优先
print(F.__mro__)
#(<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
python2中的经典类和新式类
子类中调用父类的方法:
方法1:可扩展性差,一旦基类名修改 ,子类里都得改
class Vehicle:
Country='China'
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power
def run(self):
print('开动啦')
print('开动啦')
class Subway(Vehicle):
def __init__(self,name,speed,load,power,line):
Vehicle.__init__(self,name,speed,load,power)
self.line=line
def show_info(self):
print(self.name,self.speed,self.load,self.power,self.line)
def run(self):
Vehicle.run(self)
print('%s %s 线,开动啦' %(self.name,self.line))
line13=Subway('北京地铁','10km/s',1000000000,'电',13)
line13.show_info()
line13.run()
方法2:不用写父类名,不用传self参数
class Vehicle:
Country='China'
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power
def run(self):
print('开动啦')
print('开动啦')
class Subway(Vehicle):
def __init__(self,name,speed,load,power,line):
# Vehicle.__init__(self,name,speed,load,power)
super().__init__(name, speed, load, power)#=super(Subway, self).__init__(name, speed, load, power)#不用加self
self.line=line
def show_info(self):
print(self.name,self.speed,self.load,self.power,self.line)
def run(self):
# Vehicle.run(self)
super().run()#不用加self
print('%s %s 线,开动啦' %(self.name,self.line))
line13=Subway('北京地铁','10km/s',1000000000,'电',13)
line13.show_info()
line13.run()
由不一样的类实例化获得的对象,调用同一个方法,执行的逻辑不一样
class H2O:
def __init__(self, name, temperature):
self.name = name
self.temperature = temperature
def turn_ice(self):
if self.temperature < 0:
print('【%s】 变成冰' %self.name)
elif self.temperature > 0 and self.temperature < 100:
print('【%s】 变成水')
elif self.temperature > 100:
print('【%s】 变成水蒸气')
class Water(H2O):
pass
class Ice(H2O):
pass
class Steam(H2O):
pass
w1 = Water('水', 5)
i1 = Ice('冰', -6)
s1 = Steam('蒸汽', 134)
def func(obj):
obj.turn_ice()
func(w1)
func(i1)
func(s1)
# w1.turn_ice()
# i1.turn_ice()
# s1.turn_ice()
第一个层面的封装:类自己就是在封装数据属性和函数属性
第二个层面的封装:类中定义私有的,只在类内部使用,外部没法访问
约定1:任何以单下划线开头的名字都应该是内部的、私有的
真要调用也能够调用,只是不符合约定
约定2:双下划綫开头的名字
直接__名字调用不了,要用_类名__名字调用才能够
class H2O:
__sdf = "jkl"
def __init__(self, name, temperature):
self.name = name
self.temperature = temperature
def turn_ice(self):
if self.temperature < 0:
print('【%s】 变成冰' %self.name)
elif self.temperature > 0 and self.temperature < 100:
print('【%s】 变成水')
elif self.temperature > 100:
print('【%s】 变成水蒸气')
class Water(H2O):
pass
class Ice(H2O):
pass
class Steam(H2O):
pass
w1 = Water('水', 5)
# print(w1._sdf)
# print(w1.__sdf)
print(w1._H2O__sdf)
第三个层面的封装:真正意义的封装,明确区份内外,内部的实现逻辑,外部没法知晓,而且为封装到内部的逻辑提供一个访问接口给外部使用
class Room:
def __init__(self, name, owner, width, length, height):
self.name = name
self.owner = owner
self.__width = width
self.__length = length
self.__height = height
def tell_area(self):
return self.__width * self.__length
r1 = Room('restroom', 'cyx', 100, 100, 45)
print(r1.tell_area())
指程序能够访问、检测和修改它自己状态或行为的一种能力。
四个能够实现自省的函数:hasattr getattr setattr delattr
class DishonestMiddleman:
feature = 'ugly'
def __init__(self, name, addr):
self.name = name
self.addr = addr
def sell_house(self):
print('%s正在卖房子' %self.name)
def rent_house(self):
print('%s正在租房子' %self.name)
#hasattr检测d1可否调用到''里的属性
d1 = DishonestMiddleman('dabeitou', 'toilet')
print(hasattr(d1, 'name'))
print(hasattr(d1, 'sell_house'))
print(hasattr(d1, 'sell_hrtyuuouse'))#返回false
#getattr(x, 'y')=x.y
print(getattr(d1, 'name'))#=d1.name
print(getattr(d1, 'sell_house'))
func = getattr(d1, 'sell_house')
func()
# print(getattr(d1, 'selsdfl_house'))#没有则报错
print(getattr(d1, 'sell_houfghhse', 'no such attribute'))#写了默认参数找不到也不后会报错,会返回默认参数
setattr(d1, 'sb', True)#=d1.sb = Truekey值不存在时,新增属性
setattr(d1, 'name', 'SB')#key值存在时,修改属性
setattr(d1, 'func', lambda x:x+1)
setattr(d1, 'func1', lambda self:self.name + 'sb')
print(d1.__dict__)
print(d1.func(10))
print(d1.func1(d1))
#delattr(x, 'y') = del x.y
delattr(d1, 'name')
print(d1.__dict__)
动态导入模块:__import__('文件名 ')
from m1 import t#m1/t
#如何以字符串形式导入模块
module = __import__('m1.t')#导入时会将t.py运行一遍,无论套多少层,最后返回的是最顶层的模块
print(module)#__import__经过字符串的形式导入模块,导入是最顶级的模块
module.t.test1()
# from m1.t import *
#
# test1()
# test2()#若是在模块属性前加_,就不能在import*时被导入,可是Python没有真正意义上的限制,解决方法以下
from m1.t import test1, _test2
test1()
_test2()
import importlib
m = importlib.import_module('m1.t')
print(m)#获得的结果是m1.t模块,不一样于__import__
class DishonestMiddleman:
feature = 'ugly'
def __init__(self, name, addr):
self.name = name
self.addr = addr
def sell_house(self):
print('%s正在卖房子' %self.name)
def rent_house(self):
print('%s正在租房子' %self.name)
print(hasattr(DishonestMiddleman, 'feature'))#类本质上也是对象
class Foo:
x = 1
def __init__(self, y):
self.y = y
def __getattr__(self, item):
print('执行__getattr__')
#调用对象不存在的属性时,__getattr__才会触发运行
f = Foo(10)
f.ggggg
class Foo:
x = 1
def __init__(self, y):
self.y = y
def __delattr__(self, item):
print('执行__delattr__')
f = Foo(10)
#删除时会触发__delattr__
del f.y
del f.x
class Foo:
x = 1
def __init__(self, y):
self.y = y
def __setattr__(self, key, value):
print('执行__setattr__')
# self.key = value会进入无限递归,由于一执行就会触发__setattr__
self.__dict__[key] = value
f = Foo(10)
f.z = 3
print(f.__dict__)
class Foo:
pass
f1 = Foo()
# print(f1.x)#只有属性不存在时,会自动触发__getattr__,直接报错,如有自定义__getattr__,则使用自定义的__getattr__
# del f1.x#删除属性时会触发__delattr__
f1.x = 10#设置属性时会触发__setattr__
class Foo:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('你找的属性【%s】不存在' %item)
f1 = Foo('cyx')
print(f1.age)
需求:添加的属性必须是字符串类型
class Foo:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('你找的属性【%s】不存在' %item)
def __setattr__(self, key, value):
print('执行setattr', key, value)
if type(value) is str:
print('开始设置')
# self.k = v#会触发__setattr__,继而进入死循环
self.__dict__[key] = value.upper()#能够定制设置属性的过程
else:
print('必须是字符串类型')
f1 = Foo('cyx')#触发self.name = name,进而触发__setatr__
f1.age = 18#触发__setattr__
f1.gender = 'male'
print(f1.__dict__)
需求:不容许删除属性
class Foo:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('你找的属性【%s】不存在' %item)
def __setattr__(self, key, value):
print('执行setattr', key, value)
if type(value) is str:
print('开始设置')
# self.k = v#会触发__setattr__,继而进入死循环
self.__dict__[key] = value.upper()#能够定制设置属性的过程
else:
print('必须是字符串类型')
def __delattr__(self, item):
print('不容许删除属性【%s】' %item)
# # del self.item#触发__delattr__,继而进入死循环
# self.__dict__.pop(item)
f1 = Foo('cyx')#触发self.name = name,进而触发__setatr__
print(f1.__dict__)
del f1.name
print(f1.__dict__)
class List(list):
def append(self, p_object):
if type(p_object) is str:
# self.append(p_object)会陷入无限递归
list.append(self, p_object)#推荐用super().append(p_object)
else:
print('必须是字符串类型')
def show_middle(self):
middle_index = int(len(self)/2)
return self[middle_index]
l1 = List('helloworld')
print(l1, type(l1))
print(l1.show_middle())
l1.append('cyx')
print(l1)
l1.append(1765)
isinstance 和issubclass
class Foo:
pass
class Bar(Foo):
pass
f1 = Foo()
print(isinstance(f1, Foo))
print(issubclass(Bar, Foo))
__getattribute__
class Foo:
def __init__(self, x):
self.x = x
def __getattr__(self, item):
print('执行__getattr__')
def __getattribute__(self, item):#无论属性找不找的到,都会触发getattribute
print('执行__getattribute__')
raise AttributeError('抛出异常了')#__getattribute__抛出AttributeError异常时才会触发__getattr_运行
f1 = Foo(10)
f1.x
f1.xxxxxx
__setitem__ __getitem__ __delitem__:[]的方式操做才会触发,.的方式操做不会触发
class Foo:
def __getitem__(self, item):
print('getitem')
def __setitem__(self, key, value):
print('setitem')
def __delitem__(self, key):
print('delitem')
f1 = Foo()
print(f1.__dict__)
f1['name'] = 'cyx'
f1['age'] = 18
print(f1.__dict__)#由于setitem里没有定制属性的逻辑,因此输出是{}
class Foo:
def __getitem__(self, item):
print('getitem')
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'] = 'cyx'
f1['age'] = 18
print(f1.__dict__)#由于setitem有定制属性的逻辑,因此输出是{'name': 'cyx', 'age': 18}
del f1.name#会触发__delattr__,不会触发__delitem__
print(f1.__dict__)
print(f1.age)#会触发__getattr__,不会触发__getitem__
class Foo:
def __getitem__(self, item):
print('getitem')
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'] = 'cyx'
f1['age'] = 18
print(f1.__dict__)#由于setitem有定制属性的逻辑,因此输出是{'name': 'cyx', 'age': 18}
del f1['name']
print(f1.__dict__)
print(f1['age'])
改变对象的字符串显示:__str__ __repr__
class Foo:
pass
f1 = Foo()
print(f1)#print触发系统内的__str__(f1)→f1.__str__(),输出<__main__.Foo object at 0x0000000001E7A9E8>
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('cyx', 18)#再也不输出系统默认的格式,而是输出类中定制的格式名字是cyx 年龄是18
print(f1)
x = str(f1)
print(x)#至关于print(f1)
y = f1.__str__()
print(y)#至关于print(f1)
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('cyx', 18)
print(f1)#print找的顺序str(f1) f1.__str__() repr(f1) f1.__repr__()
总结:str函数或者print函数→obj.__str__()
repr或者交互式解释器→obj.__repr__()
若是__str__没有被定义,那么就会使用__repr__
注意:这两个方法的返回值必须是字符串 ,不然抛出异常
__format__
x = '{0}{0}{0}'.format('dog')
print(x)#dogdogdog
class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
d1 = Date(2018, 5, 20)
x = '{0.year}{0.mon}{0.day}'.format(d1)
y = '{0.year}:{0.mon}:{0.day}'.format(d1)
z = '{0.mon}-{0.day}-{0.year}'.format(d1)
print(x)
print(y)
print(z)
format_dic = {
'ymd': '{0.year}{0.mon}{0.day}',
'y:m:d': '{0.year}:{0.mon}:{0.day}',
'm-d-y': '{0.mon}:{0.day}:{0.year}'
}
class Date:
def __init__(self, year, mon, day):
self.year = year
self.mon = mon
self.day = day
def __format__(self, 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(2018, 5, 20)
print(d1.__format__('ymd'))
print(d1.__format__('y:m:d'))
print(d1.__format__('m-d-y'))
print(d1.__format__(''))
print(d1.__format__('hkhg'))
print(format(d1, ''))
print(format(d1))
__slots:定义在类中的类变量,用来省内存,实例只能定义slots提供的属性
class Foo:
__slots__ = 'name'#{''name': None},这个类产生的实例再也不具备__dict__属性,限制了实例的属性建立
f1 = Foo()
f1.name = 'cyx'
print(f1.name)
# print(f1.__dict__)
# f1.age = 18本质是触发__setattr__,进一步触发f1.__dict__['age'] = 18
print(Foo.__slots__)
print(f1.__slots__)
__doc__:查看描述信息
class Foo:
'描述信息'
pass
class Bar(Foo):
pass
print(Foo.__dict__)
print(Bar.__dict__)
print(Foo.__doc__)
print(Bar.__doc__)#__doc__属性没法被继承
__module__和__class__查看实例来自哪一个模块和来自哪一个类
析构方法__del__
class Foo:
def __init__(self, name):
self.name = name
def __del__(self):
print('执行__del__')
f1 = Foo('cyx')
del f1
print('---->')
class Foo:
def __init__(self, name):
self.name = name
def __del__(self):
print('执行__del__')
f1 = Foo('cyx')
print('---->')#文件执行完后,内存释放,会触发__del__
class Foo:
def __init__(self, name):
self.name = name
def __del__(self):
print('执行__del__')
f1 = Foo('cyx')
del f1.name#del在实例被删除时才会触发,删除属性时不会触发
print('---->')#文件执行完后,内存释放,会触发__del__
__call__对象后面加括号,触发执行,调用对象类下的__call__方法
class Foo:
def __call__(self, *args, **kwargs):
print('执行__call__')
f1 = Foo()
f1()#执行f1类下的__call__方法
Foo()#执行Foo类下的__call__方法,返回一个实例
__next__和__iter__实现迭代器协议
class Foo:
def __init__(self, n):
self.n = n
def __iter__(self):#__iter__将对象变成一个可迭代的对象(在类中必须有一个__iter__方法,才能将对象变成一个可迭代对象)
return self
def __next__(self):
if self.n == 13:
raise StopIteration('终止了')
self.n += 1
return self.n
f1 = Foo(10)
print(f1.__next__())
print(next(f1))
print(next(f1))
print(next(f1))#会报错
class Foo:
def __init__(self, n):
self.n = n
def __iter__(self):#__iter__将对象变成一个可迭代的对象(在类中必须有一个__iter__方法,才能将对象变成一个可迭代对象)
return self
def __next__(self):
if self.n == 13:
raise StopIteration('终止了')
self.n += 1
return self.n
f1 = Foo(10)
for i in f1:#iter(f1)→f1.__iter__()
print(i)#不会报错
迭代器协议实现斐波那契数列
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
return self._a
f1 = Fib()
print(next(f1))
print(next(f1))
print(next(f1))
print(next(f1))
print('------>')
for i in f1:#for会接着当前位置继续往下走,不会从头来过
print(i)
描述符理论
描述符定义:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete()中的一个,这也被称为描述器协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete():采用del删除属性时,触发
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
def __delete__(self, instance):
print('__delete__方法')
f1 = Foo()
f1.name = 'cyx'
print(f1.name)
del f1.name#描述符产生的实例进行属性操做并不会触发三个方法的执行
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()
print(Bar.__dict__)
b1 = Bar()
print(b1.x)#另一个类产生的实例调用时,触发描述符Foo下的__get__方法
b1.x = 1#触发描述符Foo下的__set__方法
print(b1.__dict__)
del b1.x#触发描述符Foo下的__delete__方法
描述符分类:数据描述符和非数据描述符
数据描述符:至少实现了__get__(),__set__()
非数据描述符:没有实现__set__()
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法')
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()#一旦定义,后续对x属性的调用全都去找Foo
def __init__(self, n):
self.x = n
b1 = Bar(10)#self.x = 10,触发set方法
print(b1.__dict__)
注意事项:
描述符自己应该定义成新式类,被代理的类也应该是新式类
必须把描述符定义成被代理类的类属性,不能为定义到构造函数中
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法', instance, value)
instance.__dict__['x'] = value
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()
def __init__(self, n):
self.x = n
b1 = Bar(10)#self.x = 10,触发set方法
print(b1.__dict__)
b1.x = 111111
print(b1.__dict__)
b1.y = 'hji'
print(b1.__dict__)#没有被代理的属性就按正常操做便可
描述符优先级:
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
类属性>数据描述符
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法', instance, value)
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()
print(Bar.x)#属性字典里找x,x被代理,找Foo,触发__get__
Bar.x =1 #类属性优先级>描述符,从新定义赋值,和描述符不要紧了,实质是底层字典的覆盖/修改操做
print(Bar.__dict__)
print(Bar.x)
数据描述符>实例属性
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法', instance, value)
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()
print(Bar.__dict__)
b1 = Bar()
b1.x#先在b1的字典里找x,找不到再去类的字典里找,类x对应的是描述符对象,触发__get__方法
b1.x =1 #先在b1的字典里找x,找不到再去类的字典里找,类x对应的是描述符对象,触发__set__方法
print(b1.__dict__)
del b1.x#先在b1的字典里找x,找不到再去类的字典里找,类x对应的是描述符对象,触发__delete__方法
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
print('__set__方法', instance, value)
def __delete__(self, instance):
print('__delete__方法')
class Bar:
x = Foo()
b1 = Bar()
Bar.x = 187655#描述符被覆盖
b1.x#再也不调用描述符
del Bar.x
b1.x
实例属性>非数据描述符
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
class Bar:
x = Foo()
b1 = Bar()
# b1.x#先在b1的字典里找x,找不到再去类的字典里找,类x对应的是描述符对象,触发__get__方法
b1.x =1
print(b1.__dict__)
数据描述符>实例属性
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
pass
class Bar:
x = Foo()
b1 = Bar()
# b1.x#先在b1的字典里找x,找不到再去类的字典里找,类x对应的是描述符对象,触发__get__方法
b1.x =1
print(b1.__dict__)
找不到触发__getattr__
class Foo:
def __get__(self, instance, owner):
print('__get__方法')
def __set__(self, instance, value):
pass
class Bar:
x = Foo()
def __getattr__(self, item):
print('------>')
b1 = Bar()
b1.x =1
print(b1.__dict__)
b1.xxxxxxxxxxxxx
#自省
hasattr(obj,'属性') #obj.属性 是否存在
getattr(obj,'属性') #获取obj.属性 不存在则报错
getattr(obj,'属性','默认值') #获取obj.属性 不存在不会报错,返回那个默认值
setattr(obj,'属性','属性的值') #obj.属性=属性的值
delattr(obj,'属性') #del obj.属性
#__getattr__,__setattr__,__delattr__
obj点的方式去操做属性时触发的方法
__getattr__:obj.属性 不存在时触发
__setattr__:obj.属性=属性的值 时触发
__delattr__:del obj.属性 时触发
#__getitem__,__setitem_,__delitem__
obj[‘属性’]的方式去操做属性时触发的方法
__getitem__:obj['属性'] 时触发
__setitem__:obj['属性']=属性的值 时触发
__delitem__:del obj['属性'] 时触发
#__get__,__set__,__delete__
描述就是一个新式类,这个类至少要实现上述三个方法的一个
class 描述符:
def __get__():
pass
def __set__():
pass
def __delete__():
pass
class 类:
name=描述符()
obj=类()
obj.name #get
obj.name='egon' #set
del obj.name #delete
#__del__:析构方法
垃圾回收时触发
上下文管理协议
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)
with Foo('a.txt') as f:#with Foo('a.txt')触发__enter__,__enter__返回的值赋值给f
print(f)
print(f.name)#无异常时代码块执行完毕时触发__exit__
print('5555')
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)#异常traceback
with Foo('a.txt') as f:#with Foo('a.txt')触发__enter__,__enter__返回的值赋值给f
print(f)
print(ahdkhjjv)#有异常时直接执行__exit__,后面代码再也不执行
print(f.name)
print('5555')
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)#异常traceback
return True#将异常吸取掉了,with正常结束掉
with Foo('a.txt') as f:#with Foo('a.txt')触发__enter__,__enter__返回的值赋值给f
print(f)
print(ahdkhjjv)#有异常时直接执行__exit__,后面代码再也不执行,除非在__exit__中return True
print(f.name)
print('1111')
print('5555')
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语句的执行完毕
描述符应用
用描述符为Python加上类型检测
class Typed:
def __init__(self, key, expected_type):
self.key = key
self.expected_type = expected_type
def __get__(self, instance, owner):
print('get方法')
# print('instance参数【%s】' %instance)
# print('owner参数【%s】' % owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
# print('instance参数【%s】' % instance)
# print('value参数【%s】' % value)
if not isinstance(value, self.expected_type):
raise TypeError('%s传入的类型不是%s' %(self.key, self.expected_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('delete方法')
# print('instance参数【%s】' % instance)
instance.__dict__.pop(self.key)
class People:
name = Typed('name', str)
age = Typed('age', int)
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
p1 = People('cyx', '12', 15.9)
print(p1.__dict__)
# p1.name
# p1.name = 'ypp'
# print(p1.__dict__)
类的装饰器的基本原理
def deco(obj):
print('=====')
obj.x = 1
obj.y = 2
obj.z = 3
return obj
@deco #Foo = deco(Foo)
class Foo:
pass
print(Foo.__dict__)
def Typed(**kwargs):
def deco(obj):
for key, val in kwargs.items():
setattr(obj, key, val)
return obj
return deco
@Typed(x=1, y=2, z=3)
class Foo:
pass
print(Foo.__dict__)
@Typed(name = 'cyx')
class Bar:
pass
print(Bar.__dict__)
经过装饰器给类加上描述符
class Typed:
def __init__(self, key, expected_type):
self.key = key
self.expected_type = expected_type
def __get__(self, instance, owner):
print('get方法')
# print('instance参数【%s】' %instance)
# print('owner参数【%s】' % owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set方法')
# print('instance参数【%s】' % instance)
# print('value参数【%s】' % value)
if not isinstance(value, self.expected_type):
raise TypeError('%s传入的类型不是%s' %(self.key, self.expected_type))
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('delete方法')
# print('instance参数【%s】' % instance)
instance.__dict__.pop(self.key)
def deco(**kwargs):
def wrapper(obj):
for key, val in kwargs.items():
setattr(obj, key, Typed(key, val))
return obj
return wrapper
@deco(name = str, age = int, salary = float)
class People:
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
p1 = People('cyx', 12, 15.9)
print(People.__dict__)
利用描述符自定制property&实现延迟计算功能
class Lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):#类调用时,传入的instance是None
print('get')
if instance is None:
return self
res = self.func(instance)
setattr(instance, self.func.__name__, res)
return res
# def __set__(self, instance, value):一旦加上它变成数据描述符,就没法实现延时计算,由于数据描述符优先级高于实例属性
# pass
class Room:
def __init__(self, name, length, width):
self.name = name
self.length = length
self.width = width
@Lazyproperty #area = Lazyproperty(area),实现了给类增长描述符的功能
def area(self):
return self.length * self.width
@property
def area1(self):
return self.length * self.width
r1 = Room('restroom', 3, 8)
print(r1.area)#调用area会触发代理Lazyproerty的__get__方法
print(r1.__dict__)
print(r1.area)#当实例属性中存在area属性时,再也不去找非数据描述符
print(r1.area)
print(r1.area)
print(Room.area)
class Foo:
@property
def AAA(self):
print('调用时运行')
@AAA.setter
def AAA(self, val):
print('设置时运行')
@AAA.deleter
def AAA(self):
print('删除时运行')
#只有在属性AAA定义property后,才能定义AAA.setter,AAA.deleter
f1 = Foo()
f1.AAA
f1.AAA = 11
class Foo:
def get_AAA(self):
print('调用时运行')
def set_AAA(self, val):
print('设置时运行')
def del_AAA(self):
print('删除时运行')
AAA = property(get_AAA, set_AAA, del_AAA)#get, set, delete顺序不能变
f1 = Foo()
f1.AAA
f1.AAA = 11
del f1.AAA
#type方法建立类
def __init__(self, name, age):
self.name = name
self.age = age
def test(self):
print('------')
res = type('Foo', (object,), {'x': 1, '__init__': __init__, 'test': test})
print(res)
print(res.__dict__)
f1 = res('cyx', 18)
print(f1.name)
f1.test()
自定义元类
class MyType(type): def __init__(self, a, b, c): print('元类的构造函数') def __call__(self, *args, **kwargs): obj = object.__new__(self) self.__init__(obj, *args, **kwargs) return objclass Foo(metaclass=MyType):#执行Foo = MyType(Foo,'Foo', (object,), {}) def __init__(self, name): self.name = namef1 = Foo('cyx')#触发__call__执行print(f1.name)