面向对象
一,概述:
- 面向过程:根据业务逻辑从上到下写垒代码
- 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可
- 面向对象:对函数进行分类和封装,让开发“更快更好更强...”
面向对象设计:
def DOG(name,gender,type): def jiao(dog): print('一条狗%s,汪汪汪'%dog['name']) def chi(dog): print('一条%s狗%s在吃屎'%(dog['type'],dog['name'])) def init(): dog1 = { 'name' :name, 'gender':gender, 'type':type, 'jiao':jiao, 'chi':chi } return dog1 return init() d1 = DOG('吴岑','gong','藏獒') d2 = DOG('xiexiexie','mu','大金毛') # print(d1) # print(d2) d1['jiao'](d1) d1['chi'](d1)
类:把一类事物的相同的特征和动作整合在一起就是类,类是一个抽象的概念。
对象:就是基于类而创建的一个具体的事物(具体存在的),也是特征和动作整合在一起。
属性:数据属性(特征) , 函数属性(动作)
实例化: 就是把一个实例传给 类。
面向对象编程:
# 声明类 class Chinese: '这是一个中国人类' dang = '中党' def yong_kuai_zi(self): print('中国人%s用筷子吃饭'%self) def cha_dui(): print('中国人喜欢插队') # print(Chinese) ## <class '__main__.Chinese'> 类名 # print(Chinese.dang) # 使用点调用 Chinese.yong_kuai_zi('goulonghui') ## 类的属性字典 Chinese.__dict__ # print(Chinese.__dict__) # Chinese.__dict__['dang'] # Chinese.__dict__['yong_kuai_zi']('zhangqian') # Chinese.__dict__['cha_dui']()
对象类的相关知识:
''' 1.数据属性 2.函数属性 ''' class chinese: '这是一个中国人类' dang = '中场单党' def __init__(self,name,age,gender): self.mingzi = name #p1.mingzi=name self.nianling = age #p1.nianji=age self.xingbie = gender def suiditutang(self): print('%s喜欢随地吐痰' %self.mingzi) def chadui(self): print('%s插到了一个年龄是%s的人前面' %(self.mingzi,self.nianling)) p1 = chinese('alex','55','男') #--->__init__(self,name,age,gender) p1 传给了self print(p1.__dict__) ### {'mingzi': 'alex', 'nianling': '55', 'xingbie': '男'} print(p1.__dict__['mingzi']) ### alex print(p1.mingzi) ### alex 实质就是去得到的p1字典中取值 ## chinese.mingzi ### 报错 类属性访问不了 实例属性 print(p1.dang) ### 中场单党 # 风湿理论找上级参数 即为 实例属性 可访问类属性 chinese.suiditutang(p1) ### alex喜欢随地吐痰 chinese.chadui(p1) ### alex插到了一个年龄是55的人前面 p1.chadui() ### alex插到了一个年龄是55的人前面 / 自动给chadui()函数传入了 p1
增删改查:
class Chinese: dang = '中党' def play_ball(self): print('%s正在打球' %self.name) def eat(self,food): print('%s正在吃%s'%(self.name,food)) def __init__(self,name): self.name = name p1 = Chinese('alex') # 查看 print(Chinese.dang) # 中党 print(Chinese.play_ball) ## <function Chinese.play_ball at 0x0000000001E7A8C8> # 修改 Chinese.dang = 'guomigndang' print(Chinese.dang) ## guomigndang def test(self): print('来自test函数') Chinese.play_ball = test p1.play_ball() ### 来自test函数 ## 增加 Chinese.country = 'Japan' print(Chinese.country) ### Japan Chinese.new_test = test print(Chinese.__dict__) ## 'new_test': <function test at 0x0000000001D03E18> ### 删除 del Chinese.dang del Chinese.new_test print(Chinese.__dict__)
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.__dict__) ### 查看 print(p1.name) ### alex print(p1.play_ball) ### <bound method Chinese.play_ball of <__main__.Chinese object at 0x00000000027E9630>> ## 增加 p1.__dict__['sex'] = 'nan' print(p1.__dict__) # {'name': 'alex', 'sex': 'nan'} ### #不要修改底层的属性字典 p1.__dict__['name'] = 'alvin' print(p1.__dict__) ## {'name': 'alvin', 'sex': 'nan'} print(p1.name) ### alvin ## 删除 del p1.name print(p1.__dict__) ##{'sex': 'nan'}
特别注意
在面向对象中,程序逐行运行时,遇到一个类,就会在内存中开辟一个空间,这个空间的id就是类的地址, 同时会把这类中的静态属性的变量名和动态方法的地址,以及初始化函数__init__的地址放进去; 在实例化一个类产生对象的时候,每遇到一次实例化,就在内存中开辟一个空间(这个空间和第一次开辟的类的的空间不同),同时 把这空间和实例的对象obj,还有self同时对应起来;让后会在其中储存一个类的对象指针(相当于储存了类名),然后在进行实例化,执行__init__方法,把传入的变量(如self.name = name) 存在在其中; 因为有了这个类的对象指针,才使得不同的实例都可以调用类的属性和方法

# 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='日本' ### 写到实例属性的 属性字典中,不影响类的country # print('类的--->',Chinese.country) # print('实例的',p1.country) # country='中国' # 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) 找类的属性 country不是类,所以找不到 # country='中国' # class Chinese: # def __init__(self,name): # self.name=name # # def play_ball(self,ball): # print('%s 正在打 %s' %(self.name,ball)) # # def shi_li_hua(): # name=input('>>: ') # p1=Chinese(name) # # print(p1.country) # print(p1.name) # shi_li_hua() # country='中国-------------------' # class Chinese: # country='中国' # def __init__(self,name): # self.name=name # print('--->',country) ## 非点调用,不找类和实例的属性 # # def play_ball(self,ball): # print('%s 正在打 %s' %(self.name,ball)) # # print(Chinese.__dict__) # print(Chinese.country) # p1=Chinese('alex') # print('实例--------》',p1.country) ### 还有用点调用时才会找实例 和类 的 属性字典 # Chinese. # p. ###--------注意-------------------- class Chinese: l = ['a','b'] country = '中国' def __init__(self, name): self.name=name def play_ball(self,ball): print('%s 正在打 %s' %(self.name,ball)) p1 = Chinese('alex') print(Chinese.l) ### ['a', 'b'] print(p1.l) ###['a', 'b'] # p1.l = [1,2] ### 添加新的列表到实例属性字典中 # print(p1.l) ### ['a', 'b'] # print(p1.__dict__) ###{'name': 'alex', 'l': [1, 2]} p1.l.append('c') ### 添加元素 c 到类的属性字典中 print(Chinese.l) ### ['a', 'b', 'c']
#!/usr/bin/env python # -*- coding:utf8 -*- # __author__ = 'glh' import time class Person: def __init__(self, name, sex, hp, ad): # 初始化方法 self.name = name self.kind = sex self.hp = hp self.ad = ad def attack(self, dog): print('%s攻击了%s' % (self.name, dog.name)) dog.hp -= self.ad if dog.hp <= self.ad: print('%s剩余血量为%s,%sgg思密达' % (dog.name, dog.hp, dog.name)) else: print('%s掉了%s点血,%s剩余血量为%s' % (dog.name, self.ad, dog.name, dog.hp)) class Dog: country = 'china' # 静态属性 def __init__(self, name, kind, hp, ad): # 初始化方法 self.name = name self.kind = kind self.hp = hp self.ad = ad def bite(self, people): print('%s攻击了%s' % (self.name, people.name)) people.hp -= self.ad if people.hp <= self.ad: print('%s剩余血量为%s,%sgg思密达' % (people.name, people.hp, people.name)) else: print('%s掉了%s点血,%s剩余血量为%s' % (people.name, self.ad, people.name, people.hp)) d1 = Dog('松松gou', '藏獒', 100, 5) d2 = Dog('小蝌蚪gou', '金毛', 100, 5) p1 = Person('alex人', 'nv', 50, 20) p1.attack(d1, d2) Person.attack(d1, d2) 注意 while 1: time.sleep(1) p1.attack(d1) if d1.hp < 0: break time.sleep(0.5) d1.bite(p1) if p1.hp < 0: break
静态属性,静态方法,类方法
method 方法 —— 函数 由实例化对象去调用
property 伪装成属性的方法 —— 特性 由实例化对象去调用,类调用时,不加(),打印的时该方法的内存地址
classmethod 类方法 由类调用,只使用类中的静态属性,或者类方法,或者静态方法的时候用;注意:实例对象也可以调用,但没什么意义
staticmethod 静态方法 由类调用,一个方法既不会用到对象的资源(属性),也不会用到类的资源(属性),相当于一个普通函数
class Circle: def __init__(self, r): self.r = r @property # 将动态方法伪装成静态属性 def area(self): # 这里的area应该为Circle类的属性,但是又要通过计算得到,所以把他伪装成静态属性 return self.r ** 2 * pi @property def perimeter(self): return 2 * pi * self.r # c2 = Circle(3) # print(c2.perimeter) # 18.84955592153876 # print(c2.area) # 28.274333882308138
# 修改一个把动态方法伪装成静态属性的属性中的私有属性时用@x.setter class Goods: def __init__(self, discount, origin_price): self.__discount = discount self.__price = origin_price @property def price(self): return self.__discount * self.__price print(Goods.price) apple = Goods(0.8, 10) print(apple.price) apple.__price = 12 # 这样修改只能时添加一个叫__price的实例 属性,并没有真正的修改掉原来的__price(相当于_Goods__price) apple._Goods__price = 12 # 这样才能修改,不过python中一般不这么用,所以只能采用setter方法了 print(apple.price) class Goods: def __init__(self, discount, origin_price): self.__discount = discount self.__price = origin_price @property def price(self): return self.__discount * self.__price @price.setter def price(self, new): self.__price = new apple = Goods(0.8, 10) print(apple.price) apple.price = 12 # 看到这里 = 就去执行 被@price.setter 装饰的price方法 ,在该函数中进行了修改操作, # 实在类的内部对私有属性修改的 print(apple.price) # 9.600000000000001 property中的setter用法
# 删除一个被property装饰的方法时,用@x.deleter class A: def __init__(self, path): self._f = open(path, 'w', encoding='utf-8') @property def f(self): return self._f @f.deleter def f(self): self.close() # 所有的借用操作系统的资源,在删除一个变量之前都必须先归还资源 del self._f def write(self, comment): self._f.write(comment) def close(self): self._f.close() # obj = A('a.txt') # print(obj.f) # del obj.f # print(obj.f) property中的deleter用法
class Room: colour = 'haungse' def __init__(self,name,owner,length,width,height): self.name = name self.owner = owner self.length = length self.width = width self.height = height @classmethod ## 类的方法 def tell_info(cls): ### 用点调用时默认自动将类传给 cls print(cls) ### 相当于 Room print(cls.colour) ### 相当于 Room.colour Room.tell_info()
class Room: colour = 'haungse' def __init__(self,name,owner,length,width,height): self.name = name self.owner = owner self.length = length self.width = width self.height = height @staticmethod ## 类的工具包 无self 和 cls ,不能调用实例和类属性 def wash_body(a,b,c): print('%s,%s,%s正在洗澡' %(a,b,c)) ### 相当于 Room Room.wash_body('z','g','e') r1 = Room('zhaoxinjingdou','goulognhui',100,100,2) r1.wash_body('z','g','e') # r2 = Room('yufenhuayuan0','zhanggqian',10,10,200)
二,组合
class Head: print('form Head') pass class Finger: pass class Person: def __init__(self,name): self.name = name self.head = Head() ## 组合的 就是给类的数据属性(初始化函数)中 添加了一个 其他类的对象 self.finger = Finger() p1 = Person('goulonghui') p1.head ## form Head
### ------- 选课系统 ------ class School: def __init__(self,name,addr): self.name = name self.addr = addr class Course: def __init__(self,name,price,school,techer): self.name = name self.price = price self.school = school self.techer = techer class Techer: def __init__(self,name,salary,school): self.name = name self.salary = salary self.school = school s1 = School('oldboy','北京') s2 = School('oldboy','南京') s3 = School('oldboy','东京') t1 = Techer('武沛奇', '30000',s1 ) t2 = Techer('林海峰', '30000',s2 ) t3 = Techer('元昊', '30000',s3) msg = ''' 1,oldboy,北京,武沛奇 2,oldboy,南京,林海峰 3,oldboy,东京,元昊 ''' while True: print(msg) menu_dic = { '1':s1, '2':s2, '3':s3 } techer_dic = { '1':t1, '2':t2, '3':t3 } chioce = input('请输入学校:' ) school_obj = menu_dic[chioce] techer_obj = techer_dic[chioce] name = input('课程名:') price = input('价格:') new_course = Course(name,price,school_obj,techer_obj) print('%s学校的%s老师教授的%s课程'%(new_course.school.name,new_course.techer.name,new_course.name))
#!/usr/bin/env python # -*- coding:utf8 -*- # __author__ = 'glh' # 学生类 课程类 class Course: def __init__(self, name, price, period): self.name = name self.price = price self.period = period class Student: def __init__(self, name, sex, phone, course): self.name = name self.sex = sex self.phone = phone self.course = course c1 = Course('python', 20000, 6) c2 = Course('linux', 15000, 5) s1 = Student('苟陇辉', '男', '18829037944', c1) print(s1.course.name) # 圆环 圆形 from math import pi class Circle: def __init__(self, radius): self.r = radius def area(self): return pi*self.r*self.r def per(self): return 2*pi*self.r class Ring: def __init__(self, out_r, in_r): self.out_r = Circle(out_r) self.in_r = Circle(in_r) def area(self): return '圆形的面积是%s' % (self.out_r.area() - self.in_r.area()) def per(self): return '圆形的周长是{}'.format(self.out_r.per() + self.in_r.per()) print(Ring(10, 5).area()) print(Ring(10, 5).per())
三,继承
继承 # 父类也称为基类 # class Parent1: # pass # class Parent2: # pass # # class Son(Parent1): ## 单继承 # pass # # class Son(Parent1,Parent2): # 多继承 # pass # class Father: # money = 200000 # def __init__(self,name): # self.name = name # def hit_son(self,name): # print('%s正在打儿子'%self.name) # # class Son(Father): # money = 1200 # pass # # s1 = Son('alex') # s1.hit_son(s1) ###alex正在打儿子 # print(s1.money) ### 1200 # print(Father.money) ### 200000 找方法时 先在自己属性字典里面找,自己没有时,再去父类里找
1 #!/usr/bin/env python 2 # -*- coding:utf8 -*- 3 # __author__ = 'glh' 4 5 # 利用函数模拟抽象类 和接口类继承 6 7 8 # class WeChatpay: 9 # def pay(self, money): 10 # print('微信支付了%s元' % money) 11 # 12 # 13 # class Alipay(): 14 # def fuqian(self, money): 15 # print('支付宝支付了%s元' % money) 16 # 17 # 18 # def payment(obj, money): return obj.pay(money) # 归一化 为了规范 19 # 20 # 21 # w1 = WeChatpay() 22 # A1 = Alipay() 23 # payment(w1, 100) # 可以执行 24 # payment(A1, 100) # AttributeError: 'Alipay' object has no attribute 'pay' 因为Alipay类中没有实现pay方法 25 # 抽象继承 26 # 抽象类 : 27 # 在类的位置指定metaclass 是ABCMeta 28 # 在指定的方法上面添加@abstractmethod装饰器 29 # 目的:规范所有继承这个类的子类 必须实现被@abstractmethod装饰器装饰的这个方法 30 # 特点:抽象类和接口类不能被实例化 31 from abc import ABCMeta,abstractmethod 32 33 34 class Pay(metaclass=ABCMeta): # 相当于制定了一个规范,该规范指定继承它的类都必须实现pay方法,要不然无法实例化(会报错) 35 @abstractmethod 36 def pay(self): pass 37 38 39 class WeChatpay(Pay): 40 def pay(self, money): 41 print('微信支付了%s元' % money) 42 43 44 class Alipay(Pay): 45 def fuqian(self, money): 46 print('支付宝支付了%s元' % money) 47 48 49 # W1 = WeChatpay() # 可正常实例化,因为WeChatpay类中实现了pay方法 50 # A1 = Alipay() # 不能实例化,因为Alipay类中没有实现了pay方法,实例化会报错 51 # TypeError: Can't instantiate abstract class Alipay with abstract methods pay 52 53 54 # 接口类继承 55 # 规范 56 # 接口类 57 # python天生支持多继承 58 # java语言是不支持多继承的 59 from abc import ABCMeta,abstractmethod 60 61 62 class Walk_Animal(metaclass=ABCMeta): 63 @abstractmethod 64 def walk(self):pass 65 66 67 class Fly_Animal(metaclass=ABCMeta): 68 @abstractmethod 69 def fly(self):pass 70 71 72 class Swim_Animal(metaclass=ABCMeta): 73 @abstractmethod 74 def swim(self):pass 75 76 77 class Tiger(Walk_Animal,Swim_Animal): # 可同时继承2个规范 78 def walk(self): 79 print('walk') 80 81 def swim(self): 82 print('swim') 83 84 85 class Parrot: 86 def walk(self): 87 print('walk') 88 89 def fly(self): 90 print('fly') 91 92 93 class Swan: 94 def walk(self): 95 print('walk') 96 97 def fly(self): 98 print('fly') 99 100 def swim(self): 101 print('swim')
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值. 在python3中,子类执行父类的方法也可以直接用super方法. class A: def hahaha(self): print('A') class B(A): def hahaha(self): super().hahaha() #super(B,self).hahaha() #A.hahaha(self) print('B') a = A() b = B() b.hahaha() super(B,b).hahaha()
归一化

继承顺序(钻石继承)
1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

- 当类是经典类时,多继承情况下,会按照深度优先方式查找
- 当类是新式类时,多继承情况下,会按照广度优先方式查找
经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果 当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。

class D: def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> D --> C # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()
class D(object): def bar(self): print 'D.bar' class C(D): def bar(self): print 'C.bar' class B(D): def bar(self): print 'B.bar' class A(B, C): def bar(self): print 'A.bar' a = A() # 执行bar方法时 # 首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错 # 所以,查找顺序:A --> B --> C --> D # 在上述查找bar方法的过程中,一旦找到,则寻找过程立即中断,便不会再继续找了 a.bar()

注意: 在新式类可使用print(F.__mro__)或者(F.mro())来查看顺序。
# super class A: def func(self): print('A') class B(A): def func(self): print('B') super().func() class C(A): def func(self): print('C') super().func() class D(B,C): def func(self): print('D') super().func() # D().func() D.mro() # B().func() # print(B.mro()) # super并不是单纯的找父类,和mro顺序是完全对应的
# C3算法 归并算法 class A(object): pass class B(A): pass class C(A): pass class D(B): pass class E(C): pass class F(D, E): pass print(F.__mro__) # 第一步先找到继承的父类的MRO # D = [D, B, A, O] # E = [E, C, A, O] # 第二步 把父类这两个MRO 和 DE 进行归并 # 取每个表表头 并且其他表去掉表头的部分不能含有我们要取的那个表头 # 如果不满走就去取第二个表头 # merge([DBAO], [ECAO], [DE]) # FD merge([BAO], [ECAO], [E]) # FDB merge([AO], [ECAO], [E]) # FDBE merge([AO], [CAO]) # FDBEC merge([AO], [AO]) # FDBECAO # merge([AO], [OA])
四,多态
# python 天生支持多态 # 多态:由不同的类实例化得到的对象调用同一个方法,执行的逻辑不同。 class H2O: def __init__(self,name,temperature): self.name = name self.temperature = temperature def turn_ice(self): if self.temperature < 0: print('冰') elif self.temperature >0 and self.temperature <100: print('水') else: print('水蒸气') class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass W1 = Water('水',50) ## 产生三个不同类的实例化对象 I1 = Ice('冰',-20) S1 = Steam('水蒸气',105) W1.turn_ice() ### 以下三个不同类实例化的对象 调用同一个方法 I1.turn_ice() S1.turn_ice()
五,封装
1 封装 : 意义在于隐藏 2 #①: 第一层面封装:将属性(数据属性 和 函数属性)封装在类中 在调用模块时只能看见可调用的类名 ,内部的具体逻辑看不见 3 #第二层面的封装: 4 # ②:python 约定以一个_下划线开头的属性,是隐藏在内部的,外部不调用(但是Python不会阻止你调用,可以调用) 5 #③ :以 两个 __下划线开头的属性,python会自动做一个重命名的操作,变为_类名__属性方法名 6 7 # class People: 8 # __from = 'earth' 9 # def __init__(self,name): 10 # self.name = name 11 # print(People.__dict__) ### '_People__from': 'earth' 12 # p1 = People('goulonghui') 13 # print(p1._People__from) ## earth 14 15 ## 第三层面的封装:明确区分内外,定义一个访问借口,供外部调用,(即接口函数) 16 class Room: 17 def __init__(self,name,length,width,height): 18 self.name = name 19 self.__length = length 20 self.height = height 21 self.__width = width 22 def area(self): ### 接口函数 23 return self.__length * self.__width 24 25 R1 = Room('厨房',100,100,1000) 26 # print(R1.__length) ## 找不到 27 # print(R1._Room__length) ## 可以调用 28 print(R1.area()) ## 接口函数调用 10000
class Student: def __init__(self, name, pwd): self.name = name self.__pwd = pwd def __getpwd(self): # 把方法封装成私有的 return self.__pwd def login(self): # 接口函数 return self.__pwd s1 = Student('gou', 123) # print(s1._Student__pwd) # print(s1._Student__getpwd()) # 可以调到,但是一般不这么用 print(s1.login()) # 可通过接口函数去调用
六,反射
# 反射(即自省):程序可以访问,检测和修改它本身状态或行为的一种能力。 # 四个可以实现自省的函数 class People: tui = '两条腿' def __init__(self,name): self.name = name def eat(self): print('%s再吃'%self.name) p1 = People('苟') # 1、 hasattr(x,y) # 判断对象x中有么有一个y的方法 print(hasattr(p1,'tui')) # True# 1、 hasattr(x,y) # 判断对象x中有么有一个y的方法 print(hasattr(p1,'eat')) # True # 2、 getattr(x,y) # 查找对象x中y的值 print(getattr(p1,'tui')) ## 两条腿 print(getattr(p1,'eat')) ## <bound method People.eat of <__main__.People object at 0x0000000001E89B38>> getattr(p1,'eat')() ## 苟再吃 加上()可以运行 print(getattr(p1,'sdd','属性不存在')) # defalut = 属性不存在 defalut 默认为None 找不到时不写defalut 程序报错 # 3、 setattr(x,y) # 在x中创建或修改y的值 setattr(p1,'tui','大长腿') print(p1.__dict__) # 修改 {'name': '苟', 'tui': '大长腿'} setattr(p1,'gebo','细胳膊') print(p1.__dict__) # 创建 {'name': '苟', 'tui': '大长腿', 'gebo': '细胳膊'} # 4、 delattr(x,y) # 在x中删除y的值 delattr(p1,'gebo') print(p1.__dict__) #删除 {'name': '苟', 'tui': '大长腿'}
# 为什么用反射? class FTPclient: def __init__(self,addr): self.addr = addr print('正在连接服务器%s'%self.addr) # def put(self): # print('正在上传\n请等待') F1 = FTPclient('196.168.56.67') if hasattr(F1,'put'): func_put = getattr(F1,'put') func_put() else: print('不存在此方法,使用其他逻辑')
# 使用__import__,调用,传入字符串 # module_t = __import__('m1.test') # print(module_t) ### <module 'm1' from 'D:\\pythontest\\glh14 面向对象3\\m1\\__init__.py'> # ## 只找到顶级模块m1 # # 调用时 当做m1调用 # module_t.test.test1() ## test1 # module_t.test._test2() ### _test2 # 注意 # from m1.test import * # * 不能导入私有函数(即一下划线开头的) # # # test1() ### test1 # # _test2() ## name '_test2' is not defined 无法调用 # # from m1.test import test1,_test2 # _test2() ### # _test2 import importlib ### 直接找到模块下的方法 m = importlib.import_module('m1.test') print(m) ## <module 'm1.test' from 'D:\\pythontest\\glh14 面向对象3\\m1\\test.py'> m.test1() ## test1
七,双划线attr方法
class Foo: def __init__(self,name): self.name = name def __getattr__(self, item): ### 找属性不存在时,会触发该函数的运行,若无该函数,则会报错 print('你找的属性%s不存在'%item) # # f1 = Foo('alex') # print(f1.name) ## alex # f1.age ### 你找的属性age不存在 def __setattr__(self, key, value): ### 设置时 属性不存在时,执行该函数 print('执行setattr',key,value) if type(value) is str: print('kaishishezhi') # self.key = value ## 会触发__setattr__ ,函数无限递归 self.__dict__[key] = value else: print('%s类型错误'%value) # f1 = Foo('alex') # f1.age = 18 ### 18类型错误 # f1.new_age = '18' ### kaishishezhi def __delattr__(self, item): ### 删除时会触发 # del self.name ### 无限递归 self.__dict__.pop(item) f1 = Foo('alex') ## 实例化执行函数__setattr__ print(f1.__dict__) ## {'name': 'alex'} del f1.name print(f1.__dict__) ### {} 为空
八,继承的方式包装标准类型
class List(list): def append(self,object): ## 为标准类型的list类添加方法append,只能添加字符串类型的进去 if type(object) is str: # self.append(object) 此时的append是子类List的append 方法,还没定义好,故要调用类的append方法 super().append(object) else: print('只能添加字符串类型') def show_midle(self): ## 为标准类型的list类添加方法,找最中间字符 mid_index = int(len(self)/2) return self[mid_index] L1 = List('helloword') # print(L1,type(L1)) # ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd'] <class '__main__.List'> # print(L1.show_midle()) print(L1.append(11111111111)) # 只能添加字符串类型 L1.append('sd') # 只能加字符串类型 print(L1) ## ['h', 'e', 'l', 'l', 'o', 'w', 'o', 'r', 'd', 'sd']
九,授权
# class FileHandle: # def __init__(self,filename,mode = 'r',encoding = 'utf-8'): # self.file = open(filename,mode,encoding=encoding) # self.mode = mode # self.encoding = encoding # def __getattr__(self, item): # # 这里需要调用 文件read 方法 # return getattr(self.file,item) # # F1 = FileHandle('a.txt','r+') # print(F1.read) # 触发getattr方法 ## <built-in method read of _io.TextIOWrapper object at 0x0000000002049A68> # print(F1.write) # 触发getattr方法 ##<built-in method write of _io.TextIOWrapper object at 0x0000000002029A68> # F1.write('111111\n22222') ### 在a.txt文件中写 111111\n 222222 #---------------------加上修改功能---------------------- import time class FileHandle: def __init__(self,filename,mode = 'r',encoding = 'utf-8'): self.file = open(filename,mode,encoding=encoding) self.mode = mode self.encoding = encoding def write(self,line): t = time.strftime('%Y-%m-%d %X',time.localtime()) self.file.write('%s %s'%(t,line)) def __getattr__(self, item): # 这里需要调用 文件read 方法 return getattr(self.file,item) F1 = FileHandle('a.txt','r+') print(F1.read) # 触发getattr方法 ## <built-in method read of _io.TextIOWrapper object at 0x0000000002049A68> print(F1.write) # 触发自己类里的write方法 F1.write('cpu负载过高\n') ### 在a.txt文件中写 111111\n 222222 time.sleep(1) F1.write('内存剩余不足\n') time.sleep(1) F1.write('硬盘空间不足\n')
十,isinstance,issubclass,__getattribute__ 方法
class Foo: def __init__(self,x): self.x = x # f1 = Foo(4) # print(isinstance(f1,Foo)) ## True 判断一个对象 是否为 一个类 的属性 class Bar(Foo): def __init__(self,y): self.y = y # print(issubclass(Bar,Foo)) ##True 判断一个类是否为另一个类的子类 class Test: def __init__(self,x): self.x = x def __getattr__(self, item): print('执行__getattr_') def __getattribute__(self, item): print(' 执行__getattribute__') raise AttributeError('出错了') t1 = Test(4) t1.xxxx ## 当__getattr__和__getattribute__同时存在时,找不存在的属性时,只会执行__getattribute__, ## 除非__getattribute__在执行过程中抛出异常AttributeError,则执行__getattr__
十一,双划线item方法
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() f1['name'] = 'alex' ## 执行__setitem__ f1['age'] = 18 ## 执行__setitem__ f1['name'] ## 执行__getitem__ print(f1['name']) ## alex print(f1.__dict__) ## {'name': 'alex', 'age': 18} del f1['name'] ## 执行__delitem__ print(f1.__dict__) ## {'age': 18} ## 用[]字典的方式调用时,触发item系列,用点调用时,触发attr方法
#!/usr/bin/env python # -*- coding:utf8 -*- # __author__ = 'glh' from collections import namedtuple Card = namedtuple('Card', ['rank', 'suit']) class FranchDeck: ranks = [str(n) for n in range(2, 11)] + list('JQKA') suits = ['红心', '方快', '梅花', '黑桃'] def __init__(self): self.cards = [Card(rank, suit) for rank in FranchDeck.ranks for suit in FranchDeck.suits] def __len__(self): return len(self.cards) def __getitem__(self, item): return self.cards[item] def __setitem__(self, key, value): self.cards[key] = value deck = FranchDeck() # print(deck[0]) # print(deck) # print(len(deck)) # for card in deck: # print(card) from random import choice,shuffle # print(deck[choice(range(len(deck.cards)))]) # print(deck[choice(range(len(deck.cards)))]) # print(choice(deck))# 这里依赖与类中实现__len__, __getitem__方法,其中一个要是没有实现,就不行 shuffle(deck) # 这里依赖与类中实现__len__, __getitem__, __setitem__方法,其中一个要是没有实现,就不行 print(deck[0:10])
十二,__str__ , __repr__ __, __format__方法
class Foo: def __init__(self,name): self.name = name f1 = Foo('GOULONGHUI') print(f1) ### 显示<__main__.Foo object at 0x0000000001E295F8> class Foo: def __init__(self,name): self.name = name def __str__(self): return '名字是%s'%self.name f1 = Foo('GOULONGHUI') print(f1) ## 显示 名字是GOULONGHUI
# 用于python解释器中,直接使用f1查看,而————__str__使用print命令查看 class Foo: def __init__(self,name): self.name = name def __repr__(self): return '名字是%s'%self.name f1 = Foo('GOULONGHUI') print(f1) ## 显示 名字是GOULONGHUI 先找__str__,找不到时,用__repr__替代 class Foo: def __init__(self,name): self.name = name def __str__(self): ## 二者并存时,找__str__ return '名字是%s'%self.name def __repr__(self): return '名字是%s'%self.name ### 二者都必须return,且,return的必须是字符串,否则抛出异常 f1 = Foo('GOULONGHUI') print(f1) ##名字是GOULONGHUI
format_dict = { 'Y:M:D': '{0.year}:{0.month}:{0.day}', 'Y-M-D': '{0.year}-{0.month}-{0.day}', 'YMD': '{0.year}{0.month}{0.day}' } class Date: def __init__(self,year,month,day): self.year = year self.month = month self.day = day def __format__(self, format_spec): # print(format_spec) if not format_spec or format_spec not in format_dict: format_spec = 'YMD' fm = format_dict[format_spec] return fm.format(self) d1 = Date(2018,3,14) format(d1,'Y:M:D') ### 执行__format__ 属性 print(format(d1,'Y:M:D')) ## 2018:3:14 print(format(d1,'Y-M-D')) ## 2018-3-14 print(format(d1,'YMD')) ### 2018314 print(format(d1)) ##### 2018314 print(format(d1,'sfsfsfsf'))## ### 2018314
十三,__slots__方法

class Foo: __slots__ = ['name','age'] f1 = Foo() f2 = Foo() # f1.__dict__ ### 报错,slots 方法替代了__dict__ f1.name = 'alex' print(f1.name) ## alex f1.age = 18 print(f1.age) ## 18 # f1.gender = 'women' ## 只能调用slots设置的方法 f2 .name = 'goulognhui' print(f2.name) f2.age = 19 print(f2.age) ##
__module__ p1.__module__ 表示当前操作的对象p1在那个模块。
__class__ p1.__class__ 表示当前操作的对象p1的类是什么。
十四,__call__ 方法
## __call__ class Foo: def __call__(self, *args, **kwargs): print('实例执行啦') f1 = Foo() ## 本质也是在调用产生类的那个大类下的__call__方法 f1() ### 实例执行啦 # 加上 __call__方法后才能运行
十五,__len__ , __eq__,__hash__方法
# 2 内置函数的len函数时依赖类中的__len__ class Student: def __init__(self, name_list): self.name_list = name_list def __len__(self): return len(self.name_list) s1 = Student(['gou', 'guan']) print(len(s1))
# 3 __eq__ 判断值是否相等时,依赖__eq__的结果 # 应用:公司录入员工信息了,要是某个人入职时是一份工作,一段时间后又要换其他工作, # 这时候又要在录一次信息,导致该员工信息录入多次 # class Person: # def __init__(self, name, sex, age): # self.name = name # self.sex = sex # self.age = age # # def __eq__(self, other): # if type(self) == type(other) and \ # 验证type,必须是同一个类的实例对象比较 # self.name == other.name and\ # self.sex == other.sex: # return True # else: # return False # p1 = Person('gou', 'nan', 18) # p2 = Person('gou', 'nan', 20) # # print(p1 == p2)
# 面试题 # 如果两个对象的name 和 sex相同,那么这两个对象就是相同的对象,创建100个对象,去掉相同的对象 class Person: def __init__(self, name, sex, age): self.name = name self.sex = sex self.age = age def __hash__(self): return hash(self.name + self.sex) def __eq__(self, other): if type(self) == type(other) and \ self.name == other.name and\ self.sex == other.sex: return True else: return False # person_list = [Person('gou', 'nan', i) for i in range(100)] # print(set(person_list)) # 总结 # 集合去重,首先是比较2个值的哈希值是否相同,如果两个值的哈希值不同,表示不是重复的,直接储存,要是2个值的哈希值相同, # 再去比较这两个值的 '值' 是否相同,如果不同,直接储存下来, # 如果相同,会把其中一个值做一些处理(比如加上1等),让这两个值不同,储存下来. # 比较2个对象的哈希值时,该对象的类中必须实现__hash__方法,才能比较 # 比较2个对象的值是否相同时,依赖__eq__的结果
十六,__new__构造方法
1 # 一个类实例化的时候,先去调用的自己类中__new__(自己类中也是调用的object类)或者父类中的__new__构造方法,产生一个self实例对象,然后才会去执行自己的或者父类的__init__方法,给self实例每一个对象属性.
class A: def __init__(self): print('init') def __new__(cls, *args, **kwargs): print('new') self = object.__new__(cls) return self # a = A() # __new__ 构造方法 # __init__ 初始化方法
1 # 创造一个类,这个类始终只有一个实例 --- 单例模式 2 # 设计模式 ---> java开发过程中的一种规范或者设计范式 3 # 单例模式就是一种最简单的设计模式 4 5 # 什么是只有一个实例, 就是每次实例化创造的对象都是一块内存空间,就是不能开辟新的空间,只有一个空间 6 class Foo: 7 __instance = None 8 9 def __init__(self, name): 10 self.name = name 11 12 def __new__(cls, *args, **kwargs): 13 if not cls.__instance: 14 cls.__instance = object.__new__(cls) 15 return cls.__instance 16 17 18 # f1 = Foo('alex') # 创造了一个实例 19 # f2 = Foo('egon') # 第二次拿到的实例还是上一个实例,只是重新赋值了 20 # print(f1) # <__main__.Foo object at 0x000001F55533FE10> 21 # print(f2) # <__main__.Foo object at 0x000001F55533FE10> 22 # print(f1.name) # egon 23 # print(f2.name) # egon
十七,__del__析构方法
# __del__ 析构方法 # 对应着一个对象的删除. # 2个层面 # python解释器 # 能够主动回收不用的变量 # 在程序结束的时候所有的数据都会被清除 # 如果用户主动删除某个变量 # 那么这个变量就会主动的被清除 # 无论上述那种方式,再删除一个变量之前都会主动的执行析构方法 __del__ class B: def __del__(self): print('执行我了') b = B() # 这段程序运行结束,python垃圾回收,把b删除了,就执行了 __del__ 方法 手动删除 class B: def __del__(self): print('执行我了') b = B() del b # 调用__del__方法,从内存中将b删除 # 实际应用 class B(object): def __init__(self, path): self.f = open(path) def __del__(self): print('执行我了') self.f.close() # 删除之前做收尾工作,在这里比如删除文件句柄之前关闭文件 b = B('file') # 垃圾回收时,或者手动删除对象,即文件句柄时,在__del__中把文件先关掉, del b __del__ 析构方法
十八,迭代器协议
# class Foo: # def __init__(self,n): # self.n = n # def __iter__(self): # return self # def __next__(self): # if self.n == 3: # raise StopIteration('终止了') # self.n += 1 # return self.n # # f1 = Foo(1) # # print(f1.__next__()) # # print(f1.__next__()) # # print(f1.__next__()) # # for i in f1: # print(i)
class Fibo: 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 =Fibo() print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print(f1.__next__()) print('------->') for i in f1: # 接着上一个next循环下一个 print(i)
十九,描述符 __get__ ,__set__, __delete__:
- 描述符的本质就是一个新式类,在这个新式类中,至少实现了__get__ __set__ __delete__中的一个,也被称为描述符协议。
- __get__() 调用一个属性是触发;__set__()为一个属性赋值时触发;__delete__()采用del删除属性时触发
- 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的属性,不能定义到构造函数(初始化函数)中)
注意:描述符分为数据描述符和非数据描述符,数据描述符至少实现了__get__ __set__ 方法,非数据描述符只有__get__ 方法
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() ### 在另外的类中属性中,必须描述在类属性中 # def __init__(self): # self.x = 1 ## 这里实质也是在调用Foo里的set 描述符 b1 = Bar() b1.x ### 执行get ##另外的类实例的对象 调用时运行
# 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() # ---------- 类属性大于数据描述符--------- # Bar.x = 1 # 设置了一个类属性 不执行__set__方法,类属性优先级高于数据描述符, # print(Bar.__dict__) ## 'x': 1 # print(Bar.x) ## 1 # ------------- 数据描述符大于实例属性------ # b1 = Bar() # b1.x ### 执行get #执行了__get__方法,数据描述符优先级高于实例属性 # print(b1.__dict__) # 为空{} # -------------实例描述符大于非数据描述符------------ # class Foo: # def __get__(self, instance, owner): # print('执行get') # # class Bar: # x = Foo() # b1 = Bar() # b1.x = 111111111111 ## 不执行__set__方法,因为非数据描述符中就没有__set__方法, # print(b1.__dict__) # 加到自己的属性字典了{'x': 111111111111} #-----------------非数据描述符大于找不到触发__getattr__()方法 class Foo: def __get__(self, instance, owner): print('执行get') class Bar: x = Foo() def __getattr__(self, item): print('__getattr__') b1 = Bar() b1.xxxxxxxxxxxxxxxxxxxxx ## __getattr__ 执行__getattr__方法
优先级:
- 类属性
- 数据描述符
- 实例属性
- 非数据描述符
- 找不到的属性触发__getattr__方法
学无止境!


浙公网安备 33010602011771号