赞
踩
类,作为一个比较大的整体,大规模程序的编写难免少得了类的使用,相当于一个大包,大包里包括各部分的代码,类之间通过继承来联系起来,通过封装进行打包,形成一个整体。
a. 明确内外
b. 通过继承和多态在语言层面支持归一化的设计
a. 抽象实现 b. 封装/接口 c. 组合(合成)
d. 派生(子类出新的特性)/继承/继承结构
e. 泛化(子类与父类相同特点)/特化(子类自定义,与父类不同)
f. 自省/反射
① 声明函数 def fun(args): 函数体
② 声明类 class 类名: 类体 (class Chinese:pass)
③ 实例化 p1 = Chinese()
④ 分类 新式类Chinese(object): 经典类Chinese:
⑥ 属性 数据属性(函数外) 与 函数属性(函数内)
⑦ 查看属性字典 p = Chinese.dict()
⑧ 查看属性名称 Chinese.dict[‘name’] or p.name
import time t = time.asctime() class School: def __init__(self,name,address,type): self.name = name self.address = address self.type = type def eaxm(self): print('%s学校正在考试' %self.name) def zhaosheng(self): print('%s%s学校正在%s招生,时间%s' %(self.name,self.type,self.address,t)) school = School('清华大学','北京','公立') #实例化 school.eaxm() school.zhaosheng()
# 类名
print('类名:',School.__name__)
# 类的文档字符串
print('类的文档字符串:',School.__doc__)
# 类的第一个父类
print('类的第一个父类:',School.__base__)
# 类的属性
print('类的属性:',School.__dict__)
# 类定义所在的模块
print('类定义所在的模块:',School.__module__)
# 增
School.add = 'add'
# 删
del School.eaxm
# 改
School.eaxm = 'eaxms'
# 查
print(School.eaxm)
print(School.add)
# 查
print(school.name)
print(school.address)
# 改
school.name = '北京大学'
print('类的属性:',School.__dict__)
print(school.name)
# 删
school.zhaosheng()
del school.name
# school.zhaosheng() name属性值已经删除,无法再调用函数
class Room: tag = 1 def __init__(self,name,width,length,height,owner): self.name = name self.width = width self.length = length self.height = height self.owner = owner @property # @property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。 def cal_area(self): return self.width*self.height @classmethod # classmethod修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。 # 默认自动传一个参数cls def tell_info(cls): print(cls) print('--->',cls.tag) # 可以自己添加参数,后面调用需自己传入数据 def tell_info1(cls,x): print(cls) print('--->', x) @staticmethod #返回函数的静态方法 # 静态方法只是名义上的归属类管理,不能使用类变量和实例变量,是类的工具包 def wash(a,b,c): print('%s,%s,%s正在洗漱' %(a,b,c)) p = Room('房子',100,100,1000,'alex') print(p.cal_area) p.tell_info() p.tell_info1(10) # 两种调用方法 Room.wash('a','b','c') p.wash('a','b','c')
class Father:
money = 10
def __init__(self,name):
print('father')
self.name = name
def hit_son(self):
print('%s正在看儿子' %self.name)
class Mother:
money = 100
def __init__(self,name):
print('mother')
self.name = name
def kid_son(self):
print('%s正在看儿子' %self.name)
class Son(Father):
money = 20
def __init__(self,name,age):
self.name = name
self.age = age
s1 = Son('alex',5)
# 父类与子类含同一属性时
# 调用子类信息
print(s1.money,s1.name)
# 调用父类信息
print('父类信息:',Father.money)
class Son1(Father,Mother):
money = 30
def __init__(self,name,age):
self.name = name
self.age = age
s2 = Son1('kim',6)
# 父类与子类含同一属性时
# 调用子类信息
print(s2.money,s2.age)
# 调用父类信息
print('父类1信息:',Father.money,'父类2信息:',Mother.money)
注
a. 子类继承父亲的所有属性,若父亲与子类重名,不存在覆盖这一说,先找子类的,再找父类的
b. 方法改写,以本身类为准
# 子类继承父类,子类必须有父类方法才可实例化 import abc class All_file(metaclass=abc.ABCMeta): def read(self): pass def write(self): pass class Disk(All_file): def read(self):#必须有 print('Disk') def write(self):#必须有 print('Disk') p = Disk() p.write() p.read() # 接口(函数)继承,定义一个基类,基类中的方法定义成接口函数,只要来一个子类继承他,那子类必须实现这个方法 # 接口类方法不用去实现,不用实例化,只是规范
a. python2—深度优先
b. python3—广度优先
c. MRO列表,存放继承顺序
print(Son.mro) #基类(最小的)放在最后
a.子类会先于父类被检查
b.多个父类会根据他们在列表中的顺序被检查
c.如果对下一个类存在两个合法的选择,选择第一个父类
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('开动了') 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调用父类方法,与上等同 self.line = line def show_info(self): print(self.name,self.line) def run(self): # Vehicle.run(self) super().run() # super调用父类方法,与上等同 print('%s开动啦' %self.name) line = Subway('北京线','10km/h',10000,'电',12) line.show_info() line.run()
a. 当类之间显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好。
b. 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好。
调用相同的父类,运用相同的方法,得到不同的结果,多态实质上是继承的实现细节。
class H2O: def __init__(self,name,tem): self.name = name self.tem = tem def turn_ice(self): if self.tem<0: print('[%s]温度太低,结成了冰' %self.name) elif self.tem>=0 and self.tem<=100: print('[%s]温度正常,状态为水' %self.name) else: print('[%s]温度太高,形成水蒸气' %self.name) class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass w1 = Water('水',25) w1.turn_ice() i1 = Ice('水',-12) i1.turn_ice() s1 = Steam('水',120) s1.turn_ice()
在另一个文件中,使用import调用,封装的本质就是将用户用不到的属性进行隐藏(可以使用接口函数来调用)
a. 第一层面的封装:类就是麻袋,这本身就是一种封装。
b. 第二层面的封装:类中定义私有的,只在类的内部使用,外部无法访问。
c. 第三层面的封装:明确区分内外,内部实现逻辑,外部无法实现。并且为封装到内部的逻辑提供一个访问接口给外部使用(真正意义)。
类的继承有两层意义:改变 扩展,多态就是类的这两层意义的一个具体的实现机制。即:调用不同的类实例化得到对象下的相同方法,实现的过程不一样,Python中的标准类型就是多态概念的一个很好的示范
class test:
status = 'abc'
def __init__(self,name,tem):
self.name = name
self.tem = tem
def turn_ice(self):
if self.tem<0:
print('[%s]温度太低,结成了冰' %self.name)
elif self.tem>=0 and self.tem<=100:
print('[%s]温度正常,状态为水' %self.name)
else:
print('[%s]温度太高,形成水蒸气' %self.name)
c = test('水',120)
print(c.name,c.tem)
print(hasattr(c,'name'))
print(getattr(c,'name'))
print(getattr(c,'nam','abc'))
if hasattr(c,‘turn_ice’):
getattr(c,‘turn_ice’)()
import time
setattr(c,'times',time.asctime())
print(c.__dict__)
delattr(c,'tem')
print(c.__dict__)
if hasattr(c,'turn_ice'):
getattr(c,'turn_ice')()
p = Foo(100)
# 调用不存在的参数,执行__getattr__
p.sss
# 调用存在的参数,不执行__getattr__
p.y
# 删除已有属性时,执行__delattr__方法;若属性没有则会报错
print(p.__dict__)
del p.y
print(p.__dict__)
# 赋值修改时执行__setattr__
p1 = Foo(120)
import time class Open: def __init__(self,filename,mode='r',encoding='utf-8'): self.file = open(filename,mode,encoding=encoding) self.mode = mode self.encoding = encoding # 重新授权一种新的write方式,具有新的格式(定制) def write(self,line): t = time.strftime('%Y-%m-%d %x') self.file.write('%s %s' %(t,line)) # 如果没有函数则放开所有权限(通用性) def __getattr__(self, item): return getattr(self.file,item) f = Open('a.txt','w+') f.write('cpu负载\n') f.write('内存不足\n')
# isinstance(obj,cls) 判断obj是否为cls的实例,跨族谱也可以
print(isinstance(f,Open))
# issubclass(sub,super) 判断sub是否为super的子类
class Foo:
pass
class Goo(Foo):
pass
print(issubclass(Goo,Foo))
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) # 只有按照字典方法才可显示提示信息 # 改变对象的字符串显示 class Foo: def __init__(self,name,age): self.name = name self.age = age def __str__(self): return '姓名%s,年龄%s' %(self.name,self.age) f = Foo('Li',12) print(f) # 1.平常,只会显示f是Foo实例得来的,其他无任何信息 # 2.加__str__,可以定义显示内容,无则为默认__str__,,如平常显示
# 迭代器协议 class Foo: def __init__(self,n): self.n = n def __iter__(self): return self def __next__(self): if self.n == 16: raise StopIteration('终止') self.n+=1 return self.n f = Foo(12) print(f.__next__()) next(f) print(next(f)) f.__next__() print(next(f))
# 斐波那契数列(相邻两个数相加等于第三个数) class Fib: def __init__(self): self.a = 1 self.b = 1 def __iter__(self): return self def __next__(self): if self.a > 12: raise StopIteration('终止') self.a,self.b = self.b,self.a+self.b return self.a f = Fib() print(f.__next__()) print(next(f)) print('---') for i in f: print(i)
简要概述
# 实质上是一个新式类,至少实现了__get__(),__set__(),__delete__() # __get__()调用属性触发 # __set__()为一个属性赋值时触发 # __delete__()采用del删除属性时触发 # 包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法(在实例调用中才可触发) class Foo: def __get__(self,instance,owner): print('触发get') def __set__(self,instance,owner): print('触发set') def __delete__(self, instance): print('触发delete') p = Foo() p.name = 'abc' p.name del p.name
描述符str
# 为描述符的对象的类属性进行服务 class Str: def __get__(self, instance, owner): print('Str调用...') print(instance, owner) def __set__(self, instance, value): print('Str设置...') print(instance, value) def __delete__(self, instance): print('Str删除...') print(instance) class People: name = Str() # name 属性被代理,将这个类作用于另外一个类的属性来使用 def __init__(self, name): # name被Str类代理 self.name = name p1 = People('long') # 描述符Str的使用 p1.name p1.name = 'sss' del p1.name print(p1.__dict__) print(People.__dict__)
描述符种类
# 描述符分为两种 # 1.数据描述符,至少实现__get__和__set__ class Foo: def __set__(self, instance, value): print('set') def __get__(self, instance, owner): print('get') # 2.非数据描述符,没有__set__的实现 class Foo: def __get__(self, instance, owner): print('get') # 1.描述符本身应该定义成新式类,被代理的类也应该是新式类 # 2.必须把描述符定义成这个类的类属性,不能定义到构造函数中 # 3.要严格遵循该优先级,优先级由高到底:类属性>数据描述符>实例属性>非数据描述符>找不到的属性触发__getattr__()
类这个大的整体在各个程序中都普遍被使用,而且是代码显得比较规整,看起来逻辑比较清晰明了,简单来说就是重要的一批。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。