python—面向对象设计

一:三大编程范式

1.面向过程编程
2.函数式编程
3.面向对象编程

 (类:把一类事物的相同的特征和动作整合到一起就是类,类是一个抽象的概念)

 (对象:就是基于类而创建的一个具体的事物 [具体存在的] 也是特征和动作整合到一起)

 

 二:类与对象

(在python2中,分新式类经典类,python3统一都是新式类【新式类,class 类名:】【经典类,class 类名(object)】)

class Chinese:   #class是关键字,表示类名
    pass
print(Chinese)

p1=Chinese() #实例化过程,创建对象,类名后面加括号
print(p1)
小实例

      实例化,由类产生对象的过程叫做实例化,类实例化的结果就是一个对象,或者叫做一个实例   

      ps:类中的函数第一个参数必须是self  类中定义的函数叫做 “方法”

类是用来描述一类事物,类的对象指的是这一类事物中的一个个体
是事物就要有属性,属性分为:
1.数据属性:就是变量
2.函数属性:就是函数,在面向对象里通常称为方法
注:类和对象均是用点来访问自己的属性
属性
类是用来描述一类事物,类的对象指的是这一类事物中的一个个体
是事物就要有属性,属性分为:
1.数据属性:就是变量
2.函数属性:就是函数,在面向对象里通常称为方法
注:类和对象均是用点来访问自己的属性
属性
 1 class Chinese:
 2     dang='我爱中国'
 3     def tu_tan():
 4         print('张口就是一痰')
 5     def queue(self):
 6         print('随意就是一插')
 7 print(Chinese.dang) #调用类Chinese的数据属性
 8 Chinese.tu_tan() #调用方法
 9 Chinese.queue('zy') #queue方法必须传一个参数
10 print(Chinese.__dict__)  #Chinese所有的方法
11 print(Chinese.__dict__['dang'])  #在字典中找出了dang这个数据属性
12 print(Chinese.__dict__['tu_tan']) #内存地址,加()就是地址的内容
13 Chinese.__dict__['tu_tan']()
14 Chinese.__dict__['queue'](666) #必须给queue传一个参数
15 
16 # 我爱中国
17 # 张口就是一痰
18 # 随意就是一插
19 # {'__dict__': <attribute '__dict__' of 'Chinese' objects>, '__module__': '__main__', 'queue': <function Chinese.queue at 0x0000029230A14C80>, 'tu_tan': <function Chinese.tu_tan at 0x0000029230A148C8>, 'dang': '我爱中国', '__doc__': None, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>}
20 # 我爱中国
21 # <function Chinese.tu_tan at 0x0000029230A148C8>
22 # 张口就是一痰
23 # 随意就是一插

 

 对象

 1 class Chinese:
 2     dang='我爱中国'
 3     # def __init__(name,age,gender):  #开头结尾都有两个_ _表示是系统内置的方法
 4     #     dic={
 5     #         'name':name,
 6     #         'age':age,
 7     #         'gender':gender
 8     #     }
 9     #     return dic
10     def __init__(self,name,age,gender):
11         print('开始')
12         self.mingzi=name  # 其实就是字典中封装了名字,年级,性别
13         self.nianji=age
14         self.xingbie=gender
15         print('结束')
16 #class的__init__就是不需要返回任何值,它会自动返回
17     def tu_tan():
18         print('张口就是一痰')
19     def queue(self):
20         print('随意就是一插')
21 
22 person1=Chinese('zy',18,'female')  #实例化就是在触发系统内置的__init__
23 print(person1.__dict__)  #实例化后的字典形式 __dict__
24 print(person1.mingzi)  #调用person1字典的mingzi
25 print(person1.dang)  #person1调用类class的属性
26 
27 Chinese.tu_tan()
28 Chinese.queue(person1)  #必须传参数
29 
30 结果:
31 # 开始
32 # 结束
33 # {'xingbie': 'female', 'nianji': 18, 'mingzi': 'zy'}
34 # zy
35 # 我爱中国
36 # 张口就是一痰
37 # 随意就是一插

 

 类属性的增删改查:

 1 class Chinese:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5     def play_ball(self,ball):
 6         print("%s 正在打%s" %(self.name,ball))
 7 
 8 print(Chinese.country)  #查看
 9 
10 Chinese.country='Japan'
11 print(Chinese.country)   #修改
12 
13 p1=Chinese('alex')
14 print(p1.__dict__)
15 print(p1.country)
16 
17 Chinese.dang='dang' #增加
18 print(Chinese.dang)
19 print(p1.dang)
20 
21 del Chinese.dang   #删除
22 del Chinese.country
23 print(Chinese.__dict__)
24 
25 结果:
26 # China
27 # Japan
28 # {'name': 'alex'}
29 # Japan
30 # dang
31 # dang
32 # {'__module__': '__main__', '__init__': <function Chinese.__init__ at 0x000001FE771948C8>, '__weakref__': <attribute '__weakref__' of 'Chinese' objects>, '__dict__': <attribute '__dict__' of 'Chinese' objects>, 'play_ball': <function Chinese.play_ball at 0x000001FE77194C80>, '__doc__': None}

 

实例属性的增删改查:  (实例只有数据属性)

 1 class Chinese:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5     def play_ball(self,ball):
 6         print("%s 正在打%s" %(self.name,ball))
 7 p1=Chinese('alex')
 8 print(p1.__dict__)  #实例属性只有{'name': 'alex'}
 9 
10 #查看
11 print(p1.name)
12 print(p1.play_ball)  #这一步实际上是访问类
13 
14 #增加
15 p1.age=18
16 print(p1.__dict__)
17 print(p1.age)
18 
19 #修改
20 p1.age=19
21 print(p1.__dict__)
22 print(p1.age)
23 
24 #删除
25 del p1.age
26 print(p1.__dict__)
27 
28 结果:
29 #{'name': 'alex'}
30 # alex
31 # <bound method Chinese.play_ball of <__main__.Chinese object at 0x000002042B47A400>>
32 # {'age': 18, 'name': 'alex'}
33 # 18
34 # {'age': 19, 'name': 'alex'}
35 # 19
36 # {'name': 'alex'}

 

对象与实例属性:

 1 class Chinese:
 2     country='China'
 3     def __init__(self,name):
 4         self.name=name
 5     def play_ball(self,ball):
 6         print("%s 正在打%s" %(self.name,ball))
 7 p1=Chinese('alex')
 8 print(p1.country)
 9 p1.country='Japan'
10 print(Chinese.country) #类的
11 print(p1.country)  #实例的
12 结果:
13 #China
14 #China
15 #Japan
16 
17 country='China'
18 class Chinese:
19 
20     def __init__(self,name):
21         self.name=name
22     def play_ball(self,ball):
23         print("%s 正在打%s" %(self.name,ball))
24 p1=Chinese('alex')
25 print(p1.country)   #报错,因为p1调用country在class里面找,找不到不会出去找
26 
27 country='China'
28 class Chinese:
29     country='中国'
30     def __init__(self,name):
31         self.name=name
32         print(country)
33 #只是返回一个普通的变量,只有点调用的时候才在类属性或者实例属性字典里面去找,所以返回China
34 p1=Chinese('alex')
35 print(p1.country) #这才是调用实例属性,country才是'中国'
 1 class Chinese:
 2     country = 'China'
 3     def __init__(self,name):
 4         self.name=name
 5 p1=Chinese('alex')
 6 p1.country='Japan'
 7 print(Chinese.country)  #类属性没有变,所以结果还是China
 8 
 9 
10 class Chinese:
11     country = 'China'
12     li=['a','b']
13     def __init__(self,name):
14         self.name=name
15 p1=Chinese('alex')
16 print(p1.li)
17 # p1.li=[666]
18 # print(Chinese.li)  #类的列表还是没变的
19 p1.li.append('cc')   #直接改了类里面的列表
20 print(p1.__dict__)
21 print(Chinese.li)  #类里面的列表被改变之后,打印出来的里边当然是新列表['a', 'b', 'cc']

 

静态属性:

 1 class Room:
 2     def __init__(self,name,owner,width,length,heigh):
 3         self.name=name
 4         self.owner=owner
 5         self.width=width
 6         self.length=length
 7         self.heigh=heigh
 8     @property  #在类的普通方法上应用@property装饰器
 9     def cal_area(self):
10         print("%s住的%s总面积是%s" % (self.owner, self.name, self.width * self.heigh * self.length))
11 r1=Room('豪宅','zy',1000,1000,1000)
12 r2=Room('别墅','zt',1000,1200,1300)
13 r1.cal_area
14 r2.cal_area
15 
16 结果:
17 zy住的豪宅总面积是1000000000
18 zt住的别墅总面积是1560000000

 

类方法:

 1 class Room:
 2     tag=1
 3     def __init__(self,name,owner,width,length,heigh):
 4         self.name=name
 5         self.owner=owner
 6         self.width=width
 7         self.length=length
 8         self.heigh=heigh
 9     @property  
10     def cal_area(self):
11         print("%s住的%s总面积是%s" % (self.owner, self.name, self.width * self.heigh * self.length))
12     def test(self):
13         print('from test',self.name)
14     def tell_info(self):
15         print(self.tag)
16 print(Room.tag)    #类可以调用自己的数据属性
17 r1=Room('wc','alex',10,100,30) #折中方案,必须先实例化,再。。。。
18 Room.tell_info(r1)
19 
20 结果:1  1
21 
22 优化,类方法:
23 class Room:
24     tag=1
25     def __init__(self,name,owner,width,length,heigh):
26         self.name=name
27         self.owner=owner
28         self.width=width
29         self.length=length
30         self.heigh=heigh
31     @property
32     def cal_area(self):
33         print("%s住的%s总面积是%s" % (self.owner, self.name, self.width * self.heigh * self.length))
34     def test(self):
35         print('from test',self.name)
36     @classmethod
37     def tell_info(cls):
38         print(cls)
39         print('--->',cls.tag)
40 Room.tell_info()  #用类调用类方法,自动传值,把Room传给了tell_info
41 
42 结果:
43 #<class '__main__.Room'>
44 #---> 1

 

静态方法:

1 静态方法只是类的工具包
2 class Room:
3     tag=1
4     @staticmethod
5     def wash_body(a,b,c):
6         print('%s,%s,%s正在洗澡' %(a,b,c))
7 Room.wash_body('zy','zt','zc')
8 结果:zy,zt,zc正在洗澡

 

三:组合(类与类之间没有共同点,但是有关联,拼接类使之间能完成某项功能)

 1 #组合
 2 class School:
 3     def __init__(self,name,addr):
 4         self.name=name
 5         self.addr=addr
 6     def zhao_sheng(self):
 7         print('%s正在招生' %self.name)
 8 class Course:
 9     def __init__(self,name,price,period,school):
10         self.name=name
11         self.price=price
12         self.period=period
13         self.school=school
14 
15 s1=School('oldboy','beijin')
16 s2=School('oldboy','nanjin')
17 s3=School('oldboy','dongjin')
18 
19 c1=Course('linux','10','1h',s1)
20 
21 print(c1.__dict__)
22 print(c1.school.name)
23 
24 结果:
25 #{'price': '10', 'school': <__main__.School object at 0x00000229CB1EA898>, 'name': 'linux', 'period': '1h'}
26 #oldboy
改进,自己传值:
class School:
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr
    def zhao_sheng(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('oldboy','beijin')
s2=School('oldboy','nanjin')
s3=School('oldboy','dongjin')

# c1=Course('linux','10','1h',s1)
message='''
1 oldboy beijin
2 oldboy nanjin
3 oldboy dongjin
'''
while True:
    print(message)
    menu={
        '1':s1,
        '2':s2,
        '3':s3
    }
    choice=input('选择学校:')
    school_obj=menu[choice]

    name=input('课程名:')
    price=input('课程费用:')
    period=input('课程周期:')

    new_course=Course(name,price,period,school_obj)
    print('课程%s属于%s学校' %(new_course.name,new_course.school.name))

结果:
#1 oldboy beijin
#2 oldboy nanjin
#3 oldboy dongjin

#选择学校:2
#课程名:linux
#课程费用:100
#课程周期:1h
#课程linux属于oldboy学校

 

四:面向对象编程三大特性

     【1】继承(分:单继承,多继承)

 1 class Dad:
 2     money=10000
 3     def __init__(self,name):
 4         print('baba')
 5         self.name=name
 6     def hit_son(self):
 7         print('%s 正在打儿子' %self.name)
 8 
 9 class Son(Dad):
10     pass
11 
12 s1=Son('zy')
13 print(s1.money)
14 print(s1.__dict__)
15 
16 结果:
17 #baba
18 #10000
19 #{'name': 'zy'}
1.当类之间有显著不同,且较小的类是较大类所需的组件时,用组合比较好。
2.当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好。
什么时候用组合,什么时候用继承
含义一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
含义二:声明某个子类兼容于某个基类,定义一个接口类,子类继承接口类,并且实现接口中定义的方法。
继承的两种含义
接口继承
接口继承实际上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无须关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这个在程序设计上叫做归一化。(归一化使得高层的外部使用者可以不加区分的处理所有的接口兼容的对象集合)
归一化

继承顺序:深度优先广度优先

(当时经典类时,多继承情况下,会按照深度优先的方法查找。当时新式类时,会按照广度优先的方式查找。)

 

在子类中如何调用父类的方法:

(子类继承父类的方法,然后想基于原有的基础上进行修改,那么就需要在子类中调用父类的方法。)

 1 class Vehicle:
 2     Country='china'
 3     def __init__(self,name,speed,load,power):
 4         self.name=name
 5         self.speed=speed
 6         self.load=load
 7         self.power=power
 8     def run(self):
 9         print('开动了')
10 class Subway(Vehicle):
11     def __init__(self,name,speed,load,power,line):
12         Vehicle.__init__(self,name,speed,load,power)
13         self.line = line  #子类中派生出的新的方法
14     def show_info(self):
15         print(self.name,self.speed,self.load,self.power,self.line)
16 line13=Subway('北京地铁','10km/s',10000,'',13)
17 line13.show_info()
18 line13.run()
19 
20 结果:
21 #北京地铁 10km/s 10000 电 13
22 #开动了

super调用父类方法:

 1 class Vehicle:
 2     Country='china'
 3     def __init__(self,name,speed,load,power):
 4         self.name=name
 5         self.speed=speed
 6         self.load=load
 7         self.power=power
 8     def run(self):
 9         print('开动了')
10 class Subway(Vehicle):
11     def __init__(self,name,speed,load,power,line):
12         # Vehicle.__init__(self,name,speed,load,power)
13         super().__init__(name,speed,load,power)  #不用写父类了,用super调到父类的方法
14         self.line = line  #子类中派生出的新的方法
15     def show_info(self):
16         print(self.name,self.speed,self.load,self.power,self.line)
17 line13=Subway('北京地铁','10km/s',10000,'',13)
18 line13.show_info()
19 line13.run()
20 
21 结果:
22 北京地铁 10km/s 10000 电 13
23 开动了
super()方法

 

  【2】多态(多态的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需要考虑他们具体的类。执行过程中才显示出多态。)

  【3】封装

(三个层面的封装,第一,类本身就是一种封装;第二,类中定义私有的,只在类的内部使用外部无法访问;第三,明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用

 1 class People:       
 2     __star='earth' 
 3     def __init__(self,id,name,age,salary):
 4         print('--->',self.__star)
 5         self.id=id
 6         self.name=name
 7         self_age=age
 8         self._salary=salary
 9     def get_id(self):
10         print('这是私有方法,它的id是【%s】' %self.id)
11     #访问函数,间接访问
12     def get_star(self):
13         print(self.__star)
14 p1=People('216513548','zy','18',100000000)
15 print(People.__dict__)
16 print(p1._People__star)
17 p1.get_star()
18 结果:
19 #---> earth
20 #{'__module__': '__main__', '__dict__': <attribute '__dict__' of 'People' objects>, '__init__': <function People.__init__ at 0x000001AB8B8248C8>, 'get_star': <function People.get_star at 0x000001AB8B824D08>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None, '_People__star': 'earth', 'get_id': <function People.get_id at 0x000001AB8B824C80>}
21 #earth
22 #earth
 1 class Room:
 2     def __init__(self,name,owner,width,length,high):
 3         self.name=name
 4         self.owner=owner
 5         self.__width=width   #加__后变成私有的,外部访问不到
 6         self.__length=length
 7         self.__high=high
 8     def tell_area(self):   #求面积函数在类class内部,可以访问长宽高;求面积;等于开了一个接口
 9         return self.__width*self.__length*self.__high
10 r1=Room('Bighouse','zy',100,60,90)
11 area=r1.tell_area()  #实例化求体积
12 print(area)
13 结果:540000

 

五:面向对象进阶

     【1】反射(反射指的是程序可以访问,检测和修改它本身状态或行为的一种能力[自省])

        !!!!!python面向对象中的反射:通过字符串的形式操作对象相关的属性;python中的一切事物都是对象(都可以使用反射)!!!!!

              四种可以实现自省的函数:

 1.hasattr 2.setattr 3.getattr 4.delattr

 1 例子:
 2 class Zhongjie:
 3     feature='black'
 4     def __init__(self,name,addr):
 5         self.name=name
 6         self.addr=addr
 7     def sell_house(self):
 8         print('%s正在卖房子'%self.name)
 9     def rent_house(self):
10         print('%s正在租房子' %self.name)
11 z1=Zhongjie('sb','jinmao')
12 #对象是否有某种属性
13 print(hasattr(z1,'name'))  #True
14 print(hasattr(z1,'sell_house'))   #True
15 print(hasattr(z1,'zyy'))  #False
16 #取对象的某种属性
17 print(getattr(z1,'name'))  #sb
18 print(getattr(z1,'rent_house'))#<bound method Zhongjie.rent_house of <__main__.Zhongjie object at 0x0000021A6AA2A780>>
19 print(getattr(z1,'i am a sheep','没有这个属性')) #没有这个属性,找不到只会返回后面的值,不会报错
20 #为对象设置某种属性
21 setattr(z1,'sbb',True)
22 print(z1.__dict__)  #{'addr': 'jinmao', 'sbb': True, 'name': 'sb'}
23 #删除对象某种属性
24 delattr(z1,'sbb')
25 print(z1.__dict__)  #{'name': 'sb', 'addr': 'jinmao'}

 

    !!!!!反射机制的好处:

1 好处一:可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能。
2 好处二:动态导入模块(基于反射当前模块成员)

     【2】类的内置attr属性

 1. __getattr__ 2. __delattr__ 3.__setattr__ 

 1 实例:
 2 #__getattr__
 3 class Foo:
 4     x=666
 5     def __init__(self,y):
 6         self.y=y
 7     def __getattr__(self, item):   #__getattr__是在调用一个不存在的属性时才会被执行
 8         print('执行__getattr__')
 9 f1=Foo(888)
10 print(f1.y)   #888
11 print(getattr(f1,'y'))  #888
12 f1.zzzzzzz   #执行__getattr__
13 
14 #__delattr__
15 class Foo:
16     x=666
17     def __init__(self,y):
18         self.y=y
19     def __delattr__(self, item):
20         print('删除操作__delattr__')  #删除的时候会被执行
21 f1=Foo(360)
22 print(f1.y)  #360
23 del f1.y  #删除操作__delattr__
24 del f1.x  #删除操作__delattr__
25 
26 #__setattr__
27 class Foo:
28     x=666
29     def __init__(self,y):
30         self.y=y
31     def __setattr__(self, key, value):
32         print('__setattr__执行')
33         self.__dict__[key]=value  
34 f1=Foo(985)
35 print(f1.__dict__)   #__setattr__执行{'y': 985}
36 f1.z=211   #触发__setattr__
37 print(f1.__dict__)   #__setattr__执行{'z': 211, 'y': 985}

     【3】二次加工标准数据类型(包装标准类型)

             包装:python为大家提供了标准数据类型,以及丰富的内置方法,其实在很多场景下我们都需要基于标准数据类型来定制我们自己的数据类型,新增/改写方法,这就用到了我们继承/派生知识

                     (其他的标准类型均可以通过下面的方式进行二次加工)

 1 #包装标准数据类型
 2 class List(list):
 3     def append_xixi(self,object):
 4         if type(object) is str:
 5             super().append(object)
 6         else:
 7             print('请添加字符串类型数据!!!')
 8 
 9     def show_middle(self):
10         mid_index=int(len(self)/2)
11         return self[mid_index]
12 
13 L1=List('i am a beautiful girl')
14 print(L1,type(L1))  #['i', ' ', 'a', 'm', ' ', 'a', ' ', 'b', 'e', 'a', 'u', 't', 'i', 'f', 'u', 'l', ' ', 'g', 'i', 'r', 'l'] <class '__main__.List'>
15 print(L1.show_middle())  #u
16 L1.append_xixi('ojbk')
17 print(L1)  #['i', ' ', 'a', 'm', ' ', 'a', ' ', 'b', 'e', 'a', 'u', 't', 'i', 'f', 'u', 'l', ' ', 'g', 'i', 'r', 'l', 'ojbk']

 

      【4】组合的方式完成授权

              授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性

                   实现授权的关键点就是覆盖__getattr__方法

 

       【5】面向对象内置函数的补充:

isinstance(判断是否是某种数据类型) & issubclass(判断是否是子类)

                (1)__getattribute__

 1 class Foo:
 2     def __init__(self,x):
 3         self.x=x
 4 
 5     def __getattr__(self, item):
 6         print('执行的是我')
 7 
 8     def __getattribute__(self, item):
 9         print('不管是否存在,都会执行')
10         raise AttributeError('哈哈')
11 
12 f1=Foo(10)
13 f1.x
14 f1.xxxxxx
15 #当__getattribute__与__getattr__同时存在,只会执行__getattrbute__,除非__getattribute__在执行过程中抛出异常AttributeError
16 
17 结果:
18 #不管是否存在,都会执行
19 #执行的是我
20 #不管是否存在,都会执行
21 #执行的是我

                 (2)item系列【强调:点.的方式操作属性就是与attr相关,中括号[]的方式操作属性就是与item相关

 1 class Foo:
 2     def __init__(self,name):
 3         self.name=name
 4 
 5     def __getitem__(self, item):
 6         print(self.__dict__[item])
 7 
 8     def __setitem__(self, key, value):
 9         self.__dict__[key]=value
10     def __delitem__(self, key):
11         print('del obj[key]时,我执行')
12         self.__dict__.pop(key)
13     def __delattr__(self, item):
14         print('del obj.key时,我执行')
15         self.__dict__.pop(item)
16 
17 f1=Foo('sb')
18 f1['age']=18
19 f1['age1']=19
20 del f1.age1
21 del f1['age']
22 f1['name']='alex'
23 print(f1.__dict__)
24 
25 结果:
26 #del obj.key时,我执行
27 #del obj[key]时,我执行
28 #{'name': 'alex'}

                  (3)__str____repr____format__  (__str__规定必须return一个值)

 1 改变对象的字符串显示__str__,__repr__   #print触发的是str,repr是在解释器中触发的,都是对输出进行控制!当print找不到str就是去找repr作为替代品!!!
 2 
 3 class Foo:
 4     def __init__(self,name,age):
 5         self.name=name
 6         self.age=age
 7     def __str__(self):
 8         return 'my name is %s,and age is %s!' %(self.name,self.age)
 9 
10 f1=Foo('zy',18)
11 print(f1)  #print执行的其实是系统提供的str(F1),所以每次print的时候都是字典字符串,当自己定义__str__后就可以自己控制输出了
12 
13 结果:my name is zy,and age is 18!
14 
15 class Foo:
16     def __init__(self,name,age):
17         self.name=name
18         self.age=age
19     def __repr__(self):
20         return 'my name is %s,and age is %s!' %(self.name,self.age)
21 
22 f1=Foo('zy',18)
23 print(f1)  #repr(f1)触发——》__repr__()
24 
25 结果一样!!!
26 但是当没有str就是去找repr作为替代品!!!
 1 自定制format:
 2 date_dic={
 3     'ymd':'{0.year}:{0.month}:{0.day}',
 4     'dmy':'{0.day}/{0.month}/{0.year}',
 5     'mdy':'{0.month}-{0.day}-{0.year}',
 6 }
 7 class Date:
 8     def __init__(self,year,month,day):
 9         self.year=year
10         self.month=month
11         self.day=day
12 
13     def __format__(self, format_spec):
14         if not format_spec or format_spec not in date_dic:
15             format_spec='ymd'
16         fmt=date_dic[format_spec]
17         return fmt.format(self)
18 
19 d1=Date(2016,12,29)
20 print(format(d1))
21 print('{:mdy}'.format(d1))
22 
23 结果:
24 #2016:12:29
25 #12-29-2016

                (4)__slots__属性:

1.__slots__是什么:是一个类变量,变量值可以是列表,元祖,或者可迭代对象,也可以是一个字符串(意味着所有实例只有一个数据属性)。
2.引子:使用点来访问属性本质就是在访问类或者对象的__dict__属性字典(类的字典是共享的,而每个实例的是独立的)。
3.为何使用__slots__:字典会占用大量内存,如果你有一个属性很少的类,但是有很多实例,为了节省内存可以使用__slots__取代实例的__dict__。
当你定义__slots__后,__slots__就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__中列出的属性名在内部被映射到这个数组的指定小标上。使用__slots__一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__中定义的那些属性名。
4.注意事项:__slots__的很多特性都依赖于普通的基于字典的实现。另外,定义__slots__后的类不再支持一些普通类特性了,比如多继承。大多数情况下,你应该只在那些经常被使用到的用作数据结构的类上定义__slots__比如在程序中需要创建某个类的几百万个实例对象 ,关于__slots__的一个常见误区是它可以作为一个封装工具来防止用户给实例增加新的属性。尽管使用__slots__可以达到这样的目的,但是这个并不是它的初衷。更多的是用来作为一个内存优化工具。
__slots__到底是什么
 1 class Foo:
 2     __slots__ = ['name','age']  #定义在类当中的类属性,使之不在具有__dict__字典
 3 f1=Foo()
 4 f1.name='zy'
 5 f1.age=18
 6 print(f1.name)
 7 print(f1.age)
 8 print(f1.__slots__)  #帮助省内存
 9 
10 结果:
11 #zy
12 #18
13 #['name', 'age']

                  (5)doc属性

1 class Foo:
2     '我是描述信息'
3     pass
4 class Bar(Foo):
5     pass
6 print(Bar.__doc__) #该属性无法继承给子类
7 #原理就是在每一个类当中都会加一个__doc__,之要调就有
8 
9 结果:None

                (6)__module____class__

1 __module__ 表示当前操作的对象在那个模块
2 __class__     表示当前操作的对象的类是什么

                (7)__del__析构方法

 1 析构方法,当对象在内存中被释放时,自动触发执行。
 2 #注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__
 3 
 4 class Foo:
 5     def __init__(self,name):
 6         self.name=name
 7     def __del__(self):
 8         print('我执行了')
 9 f1=Foo('zy')
10 del f1
11 print('ennnn')
12 #结果:我执行了
13 #      ennnn
14 
15 但是:
16 class Foo:
17     def __init__(self,name):
18         self.name=name
19     def __del__(self):
20         print('我执行了')
21 f1=Foo('zy')
22 #del f1
23 print('ennnn')
24 #结果:ennnn
25 #      我执行了

                 (8)__call__

1 class Foo:
2     def __call__(self, *args, **kwargs):
3         print('实例执行了')
4 f1=Foo()  #
5 f1()  #调用Foo类下的__call__
6 结果:实例执行了

                 (9)__next____iter__实现迭代器协议

 1 class Foo:
 2     pass
 3 f1=Foo()
 4 for i in f1:  #因为f1是对象所以可以for循环
 5     print(i)
 6 #但是:TypeError: 'Foo' object is not iterable 报错说Foo不是可迭代的对象
 7 #怎么实现可迭代呢???
 8 class Foo:
 9     def __init__(self,n):
10         self.n=n
11     def __iter__(self):
12         return self
13     def __next__(self):
14         self.n+=1
15         return self.n
16 f1=Foo(1)
17 print(f1.__next__())
18 for i in f1:  #for其实就是f1实现__iter__方法,迭代器,实际就是iter(f1)——》f1.__iter__
19     print(i)
20 
21 结果:无限加1
22 
23 抛出异常,使之停止一直循环
24 class Foo:
25     def __init__(self,n):
26         self.n=n
27     def __iter__(self):
28         return self
29     def __next__(self):
30         if self.n==12:
31             raise StopIteration('停止')
32         self.n+=1
33         return self.n
34 f1=Foo(1)
35 print(f1.__next__())
36 for i in f1:  #for其实就是f1实现__iter__方法,迭代器,实际就是iter(f1)——》f1.__iter__
37     print(i)
38 
39 结果:2----12
 1 利用迭代器实现的裴波那契序列:
 2 class Fib:
 3     def __init__(self):
 4         self._a=1
 5         self._b=1
 6     def __iter__(self):
 7         return self
 8     def __next__(self):
 9         if self._a>100:
10             raise StopIteration('停了')
11         self._a,self._b=self._b,self._a+self._b
12         return self._a
13 f1=Fib()
14 print(f1.__next__())
15 for i in f1:
16     print(i)
17 
18 结果:1----114
posted @ 2018-09-14 21:41  周圆  阅读(1494)  评论(0编辑  收藏  举报