Python面向对象编程

Note

1.实例只有数据属性,函数属性是属于类的 对于类的函数属性的更改可以立刻反映在实例上 可以用__dict__查看  实例产生只是执行了__init__

2.风湿理论的应用

3. @property

类似于将函数属性变成数据属性那样去显示

 1 class Romm():
 2     def __init__(self,long, width):
 3         self.long = long
 4         self.width = width
 5         self.high = 100
 6         
 7     @property  
 8     def area(self):
 9         area = int(self.long) + int(self.width)+self.high
10         return area
11 
12 a1 = Romm(100,200)
13 print(a1.area)
View Code

自定义实现 property

a.装饰器 类也可以作为一个装饰器,只需要在定义__init__ 传入适当的参数

1 class LazyProperty():
2 
3     def __init__(self, func): #func 就是需要修饰的函数
4         self.func = func
5         print(self.func) 
View Code

b.描述符

 1 class LazyProperty():
 2 
 3     def __init__(self, func):
 4         self.func = func
 5         print(self.func) # self.func就是类Room的方法area
 6 
 7     def __get__(self, instance, owner):
 8         print('instance is %s'% instance) #instance 就是实例r1
 9 
10         res = self.func(instance) #传入self
11         return res
12 
13 
14 
15 
16 
17 class Room:
18     #area = Lazyproperty(area) #==》就是类中装饰器的效果 等于第16行
19     def __init__(self, name ,width, length):
20         self.name = name
21         self.width = width
22         self.lenth = length
23 
24     @LazyProperty #area = LazyProperty(area)   #既实现了装饰器还实现了描述符
25     def area(self):
26         return self.width * self.lenth
27 
28 r1 = Room('zhou', 60,60)
29 print(r1.area)   #触发get,返回r1.area()
View Code

 c.自定制property并实现延时计算

 1 class LazyProperty():
 2 
 3     def __init__(self, func):
 4         self.func = func
 5         print(self.func) # self.func就是类Room的方法area
 6 
 7     def __get__(self, instance, owner):
 8 
 9         print('instance is %s'% instance) #instance 就是实例r1,如果是类调用instance 为None
10         if instance is None:              #类调用模仿实际的静态属性 返回LazyProperty类的对象
11             return self
12         res = self.func(instance) #传入self
13         setattr(instance, self.func.__name__, res) #将属性及值加入到实例字典中这样下次调用就会直接在实例字典中寻找,不会重复计算
14         return res                                 #之所以写成非数据描述符是因为他优先级比实例属性低 写入字典之后就不会再去触发该非数据描述符 达到不重复计算的目的
15 
16 
17 
18 
19 
20 class Room:
21     #area = Lazyproperty(area) #==》就是类中装饰器的效果 等于第16行
22     def __init__(self, name ,width, length):
23         self.name = name
24         self.width = width
25         self.lenth = length
26 
27     @LazyProperty #area = LazyProperty(area)   #既实现了装饰器还实现了描述符
28     def area(self):
29         return self.width * self.lenth
30 
31 r1 = Room('zhou', 60,60)
32 print(r1.area)   #触发get,返回r1.area()
33 
34 #print(Room.area)
35 print(r1.__dict__)
延时计算

 

4.类方法  

与类绑定也是用装饰器来用

 1 class Romm():
 2     def __init__(self,long, width):
 3         self.long = long
 4         self.width = width
 5         self.high = 100
 6         
 7     @classmethod
 8     def test(cls):
 9         print('cls')
10         print('this is classmethod')
11 
12 print(Romm.test())  
View Code

自定制@classmethod 

5.静态方法

自定制@staticmethod

不与实例和类绑定 类的工具包

 1 class People():
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5         self.gender = 'man'
 6 
 7     @staticmethod
 8     def static_test(a, b):
 9         return(a+b)
10 
11     def no_test(a, b):
12         return(a+b)
13 
14 
15 
16 p1 = People('zhou', 3221)
17 print(p1.static_test(1, 2)) #3
18 print(p1.no_test(1, 2))  #会报错,因为实例调用会传入一个self  takes 2 positional arguments but 3 were given
View Code

 6.类的组合

 1 class School():
 2     def __init__(self, name, address):
 3         self.name = name
 4         self.address = address
 5 
 6 class Course():
 7     def __init__(self, course_name, price, period, shool):
 8         self.course_name = course_name
 9         self.price = price
10         self.period = period
11         self.shool = shool
12 
13 s1 = School('jialidun', 'wuxi')
14 s2 = School('Boshi', 'beijing')
15 s3 = School('qinghua', 'shanghai')
16 
17 menu = {
18     '1' :s1,
19     '2' :s2,
20     '3' :s3
21 }
22 
23 while True:
24     msg = """
25     1:jialidun, wuxi
26     2:Boshi, beijing
27     3:qinghua,shanghai
28     
29     """
30     print(msg)
31     choice = input('please choose a school>>>>')
32     shool_obj = menu[choice]
33 
34     name = input('please input lesson name>>>>')
35     price = input('please input price>>>>>')
36     period = input('please input period>>>')
37 
38     c1 = Course(name, price, period, shool_obj)
39 
40     print('课程%s的学校是%s'% (c1.course_name, c1.shool.name))
View Code

 8.子类中调用父类方法

a.在子类代码中父类调用并传入参数'self'

 1 class Verchile():
 2     def __init__(self, name, speed):
 3         self.name = name
 4         self.speed = speed
 5 
 6     def run(self):
 7         print('%s is runing with speed' % self.name, self.speed)
 8 
 9 
10 class Car(Verchile):
11     def __init__(self, name, speed, note):
12         Verchile.__init__(self,name, speed)  #父类来调用该init方法,尤其要传入一个参数self
13         self.note = note
14 
15     def run(self):
16         Verchile.run(self)       #父类来调用该run方法,尤其要传入一个参数self
17         print('note:only for %s' % self.note)
18 
19 car01 = Car('汽车', 100, 'only for people')
20 car01.run()
View Code

 b.使用super()来实现

 1 class Verchile():
 2     def __init__(self, name, speed):
 3         self.name = name
 4         self.speed = speed
 5 
 6     def run(self):
 7         print('%s is runing with speed' % self.name, self.speed)
 8 
 9 
10 class Car(Verchile):
11     def __init__(self, name, speed, note):
12        # Verchile.__init__(self,name, speed)  #父类来调用该init方法,尤其要传入一个参数self
13         super().__init__(name, speed)   #使用super() 或者 super(Verchile, Self) 也可以实现
14         self.note = note
15 
16     def run(self):
17         # Verchile.run(self)       #父类来调用该run方法,尤其要传入一个参数self
18         super().run()              #使用super()
19         print('note:only for %s' % self.note)
20 
21 car01 = Car('汽车', 100, 'only for people')
22 car01.run()
View Code

 

9.多态

 1 class TypeTest():
 2     def __init__(self,value):
 3         self.value = value
 4 
 5     def Count(self):
 6         i = 0
 7         for item in self.value:
 8             i += 1
 9         # print(self.value)
10         # print(i)
11         print("%s lenth is %d" % (self.value, i))
12 
13 class Type_str(TypeTest):
14     pass
15 
16 class Type_list(TypeTest):
17     pass
18 
19 
20 str1 = Type_str('abc')
21 list1 = TypeTest(['1', '2', '3', '4'])
22 
23 # str1.Count()
24 # list1.Count()
25 
26 def Count(obj):
27     obj.Count()
28 
29 Count(str1)   # 类似与 len()和 __len__()
30 Count(list1)
View Code

 10.反射/自省

 1 class People():
 2     Country = 'China'
 3     def __init__(self,name):
 4         self.name = name
 5 
 6     def eat(self):
 7         print('%s is now eating' % self.name)
 8 
 9 p1 = People('zhangsan')
10 p1.eat()
11 
12 # hasattr   实际是找实例能调用到的属性 注意第二个参数属性要加引号表示字符串
13 
14 print(hasattr(p1, 'Country')) #True
15 print(hasattr(p1, 'name'))   #True
16 print(p1.__dict__) #{'name': 'zhangsan'}
17 
18 # getattr 找不到会报错
19 
20 print(getattr(p1, 'name'))   # zhangsan
21 print(getattr(p1, 'eat'))    #bound method People.eat of <__main__.People object at 0x00000000021F3BA8>>
22 getattr(p1, 'eat')()         # zhangsan is now eating 基于上一条可以加括号调用
23 print(getattr(p1, 'smeil', 'Can not find!!!')) # 找不到会报错,可以加入第三个参数 给出提示信息
24 
25 # setattr
26 
27 setattr(p1, 'name', 'lisi')   # => p1.name = 'lisi'
28 print(getattr(p1, 'name'))    #lisi
29 setattr(p1, 'age', 13)
30 print(p1.__dict__)           #{'name': 'lisi', 'age': 13}
31 
32 # delattr
33 setattr(p1, 'age', 13)
34 print(p1.__dict__)      #{'name': 'lisi', 'age': 13}
35 delattr(p1, 'age')
36 print(p1.__dict__)      #{'name': 'zhangsan'}
View Code

 setattr 也可以添加新的函数属性

1 setattr(p1, 'adder', lambda x: x+1)
2 print(p1.adder(1))
3 print(p1.__dict__)         #{'name': 'lisi', 'age': 13, 'adder': <function <lambda> at 0x00000000021D6598>} 函数属性也会显示出来

事先先定义接口,后面实现

import fanshe

p2 = fanshe.People('lisi')
print(p2.showname())

if hasattr(p2,'showage'):
    showage = getattr(p2, 'showage')
    showage()
else:
    print('do not has this fuction')

 

11.动态导入模块

1 module = __import__('module.m') #会运行m里面的代码,但是导入只到module
2 print(module) #<module 'module' from 'F:\\PythonCharm\\20180610\\module\\__init__.py'>
3 
4 import importlib
5 
6 module = importlib.import_module('module.m')   #可以直接到 module.m
7 print(module) #<module 'module.m' from 'F:\\PythonCharm\\20180610\\module\\m.py'>
View Code

 12. 函数内置 __getattr__,__delattr__,__setattr__

 1 class People():
 2     z = 100
 3     def __init__(self,x):
 4         self.x = x
 5 
 6     #当找不到的时候才会触发
 7     def __getattr__(self, item):
 8         print('__getattr__getattr启动')
 9 
10     #删除时会触发
11     def __delattr__(self, item):
12         print('__delattr__delattr启动')
13         self.__dict__.pop(item)
14 
15     #设置属性值的时候出触发包括初始化的时候
16     def __setattr__(self, key, value):
17         print('__setattr__delattr启动')
18         #self.key = value   #这种写法会进入无限迭代
19         self.__dict__[key] = value #设置属性实际是对字典属性的操作
20 
21 p1 = People(10)
22 print(p1.x) #10
23 p1.y        #找不到数据属性y __getattr__启动
24 
25 del p1.x      #__delattr__启动 删除实例数据属性
26 del p1.z      #__delattr__启动 删除类数据属性
27 
28 p1.a = 100  #__setattr__delattr启动
View Code

 13.包装标准类型

 

14.授权 

 待补充。。。

15. isinstance and issubclass

 1 class Human():
 2     pass
 3 
 4 class People(Human):
 5     pass
 6 
 7 p1 = People()
 8 
 9 print(isinstance(p1,People))  #判断是否是类的实例
10 
11 print(issubclass(People, Human)) #判断是否是类的子类
View Code

16. __getattr__ and __getattribute__

调用属性的时候无论找到 找不到都会触发 __getattribute__

当找不到的时候,__getattribute__ 抛出异常,然后__getattr__会执行

__getattr__ 就像是 __getattribute__的小弟,而抛出的 AttributeError 异常就像是他们之间的口令

 1 class People():
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def __getattr__(self, item):
 6         print('this is __getattr__')
 7 
 8     def __getattribute__(self, item):
 9         print('this is __getattribute__')
10         raise AttributeError('can not find,go to __getattr__')
11 
12 p1 = People('zhangsan')
13 #print(p1.name)
14 
15 p1.xxxxx
16 p1.name
View Code

 17. __getitem__,setitem__,__delitem__

注意触发的写法

__getitem__   => instance[attribute]

__setitem__   =>instance[attribute] = value

__delitem__  =>del instance[atrribute]

 1 class People():
 2     def __init__(self, name):
 3         self.name = name
 4 
 5     def __getitem__(self, item):
 6         print(item)   #=> name
 7         print('This is __getitem__')
 8         return self.__dict__[item]
 9 
10 
11     def __setitem__(self, key, value):
12         print('This is __setitem__')
13         self.__dict__[key] = value
14 
15     def __delitem__(self, key):
16         print('This is __delitem__')
17         self.__dict__.pop(key)
18 
19 p1 = People('WOW')
20 
21 
22 print(p1['name'])   #触发__getitem__ 输出“WOW”
23 
24 p1['age'] = 18 #触发__getitem__
25 print(p1.__dict__) #{'name': 'WOW', 'age': 18} 可以看出已经成功写入
26 
27 del p1['age'] #触发__delitem__
28 print(p1.__dict__) #{'name': 'WOW', 'age': 18} 可以看出已经成功删除
View Code

 

18.__str__,__repr__, __format__

__str__,__repr__ 都会输出字符串,且__str__不存在的时候,__repr__会代替他的工作

 1 class People():
 2     def __init__(self, name, age):
 3         self.name = name
 4         self.age = age
 5 
 6     def __str__(self):
 7         return '%s\' age is %d' % (self.name, self.age)
 8 
 9     def __repr__(self):
10         return '%s\' age is %d,this is from __repr__' % (self.name, self.age)
11 
12 
13 p1 = People('Knight', 22)
14 print(p1) # print和str会调用__str__方法 当没有重载的时候 <__main__.People object at 0x00000000026B3A90>
15 print(p1) # 当重载之后,会调用__str__ ,输出 Knight' age is 22  一个字符串
16 
17 print(repr(p1))  # repr或者解释器会调用该方法,输出一个字符串 ‘Knight' age is 22,this is from __repr’
__str__ and __repr————

 19.__slots__

a.__slots__ 是hi一个变量,可以是字符串,列表,元组 甚至是可迭代对象 其针对的是实例,

b.优点是可以节约内存,实例的__dict__将会不存在

 1 class Foo:
 2     __slots__ = ('name','age')
 3     pass
 4 
 5 f = Foo()
 6 f.name = 'zs'
 7 f.age = 13
 8 
 9 #print(f.__dict__) #报错 AttributeError: 'Foo' object has no attribute '__dict__'
10 print(f.__slots__) #('name', 'age')
View Code

 

20.__iter__,__next__ 

实现一个迭代器协议:

 1 class Foo():
 2 
 3     def __init__(self, n):
 4         self.n = n
 5     
 6     def __iter__(self):
 7         return self    #返回他自己变成迭代对象
 8 
 9     def __next__(self):
10         if self.n>20:  #终止循环的条件
11             raise StopIteration('Please Stop') #抛出异常,但程序不会崩溃
12         self.n = self.n+1
13         return self.n
14 
15 p = Foo(8)
16 for i in p:
17     print(i)
一个简单的列子

 

迭代器实现斐波那契数列

引用自百度百科

斐波那契数列(Fibonacci sequence),又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……在数学上,斐波纳契数列以如下被以递归的方法定义:F(1)=1,F(2)=1, F(n)=F(n-1)+F(n-2)(n>=2,n∈N*)在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用,为此,美国数学会从1963年起出版了以《斐波纳契数列季刊》为名的一份数学杂志,用于专门刊载这方面的研究成果。

 1 class Fib:
 2 
 3     def __init__(self):
 4         self._a = 1
 5         self._b = 1
 6     
 7     def __iter__(self):
 8         return self    #返回他自己变成迭代对象
 9 
10     def __next__(self):
11 
12         self._a, self._b = self._b,self._a+self._b
13 
14         return self._a
15 
16 
17         
18 f = Fib()
19 
20 for i in f:
21     if i> 20:
22         break
23     print('%s ' %i,end='')
斐波那契数列

 

21.__doc__

子类无法继承父类的__doc__,因为子类的属性字典里已经有了而且无法删除

22.__module__,__class__

23.__del__

24.__enter__,__exist__

25.__call__

26.描述符

a.描述符本质是一个新式类,且实现了__get__,__set__,__del

b.描述符是用来描述另外一个新式类的且只能写在类属性中,不能写在构造函数中

c.数据描述符 实现了__get__和__set__

d.非数据描述符 没有实现__set__

e.描述符的优先级 类属性>数据描述符>实例属性>非属性描述符>找不到(触发__getattr__)

 1 class Type:
 2     
 3     def __get__(self, instance, owner):
 4         print('this is __get__ start--------->')
 5         print('[self] in __get__ is %s' % self)
 6         print('[instance] is %s' % instance)
 7         print('[owner] is %s'% owner)
 8         print('this is __get__ over--------->')
 9 
10     def __set__(self, instance, value):
11         print('this is __set__ start--------->')
12         print('[self]in __set__ is %s'% self)
13         print('[instance] is %s'% instance)
14         print('[value] is %s'% value)
15         print('this is __set__ over--------->')
16 
17     def __del__(self):
18         pass
19 
20 class People:
21     name = Type() #name属性由委托数据描述符Type()代理
22     def __init__(self, name, age):
23         self.name = name
24         self.age = age
25 
26 p1 = People('a1','18')
27 
28 print(p1.__dict__) #{'age': '18'} 因为name是数据描述符,比实例属性优先级高,而且数据描述符我们目前只是实现了打印,的没有实现赋值的时候 name不会再字典里
一个简单的例子

 描述符的应用

  类的属性查找赋值删除,需要使用数据描述符 因为它优先级比实例属性要高

 1 class Type:
 2 
 3     def __init__(self,key):
 4         self.key = key
 5         
 6     
 7     def __get__(self, instance, owner):
 8         print('this is __get__')
 9         return instance.__dict__[self.key] 
10 
11     def __set__(self, instance, value):
12         print('this is __set__')
13         instance.__dict__[self.key] = value
14        
15 
16     def __delete__(self, instance):
17         print('this is __delete__')
18         instance.__dict__.pop(self.key) 
19         #del instance.__dict__[self.key] 这个也可以删除
20 
21         
22         
23        
24 
25 class People:
26     name = Type('name') #name属性由委托数据描述符Type()代理
27     def __init__(self, name, age):
28         self.name = name
29         self.age = age
30 
31 p1 = People('a1','18')
32 
33 print(p1.__dict__)  #{'name': 'a1', 'age': '18'}
34 
35 print(p1.name)      #a1
36 
37 del p1.name
38 
39 print(p1.__dict__) #{'age': '18'}
给类的一个属性查找赋值删除

  可以对输入的数据进行限制,因为Python是弱数据类型的编程语言,可以通过描述符的方法对属性进行限制

 1 class Type:
 2 
 3     def __init__(self,key,exception_type):
 4         self.key = key
 5         self.exception_type = exception_type
 6       
 7         
 8     
 9     def __get__(self, instance, owner):
10         
11         return instance.__dict__[self.key] 
12 
13     def __set__(self, instance, value):
14         print('this is __set__')
15        
16         if not isinstance(value, self.exception_type):
17             print('%s\'s value is %s and it is not the type: %s' %(self.key, value, self.exception_type))
18             #raise TypeError('Expected %s' %str(self.exception_type))
19         else:
20             instance.__dict__[self.key] = value
21        
22 
23     def __delete__(self, instance):
24         print('this is __delete__')
25         instance.__dict__.pop(self.key) 
26         #del instance.__dict__[self.key] 这个也可以删除
27 
28         
29         
30        
31 
32 class People:
33     name = Type('name',str) #name属性由委托数据描述符Type()代理 str不能写成字符串
34     age = Type('age',int)   #int同理 多加一个类型参数 可以处理多种情况避免代码重复
35     def __init__(self, name, age):
36         self.name = name
37         self.age = age
38 
39 p1 = People(22, '18') #name's value is 22 and it is not the type: <class 'str'> ,age's value is 18 and it is not the type: <class 'int'>
40 
41 print(p1.__dict__)  #{}
给多个参数设定限制

 27.类的装饰器

一切皆对象,装饰器同样适用于类,语法都是一样的

1 def deco(obj):
2     print('这是类的装饰器deco')
3     return obj
4 @deco
5 class People():
6     pass
7 
8 p1 = People()

 通过装饰器给一个类赋值

 1 def deco(obj):
 2     print('这是类的装饰器deco')
 3     obj.x = 1
 4     obj.y = 2
 5     obj.z = 3
 6     return obj
 7 
 8 @deco # Pepple = deco(People)
 9 class People():
10     pass
11 
12 print(People.__dict__)
View Code

假如我们有新需求,给多个类赋不同的值呢?

 1 def Mul(**kwargs):
 2     def deco(obj):
 3         print('这是类的装饰器deco,对类%s装饰' % obj)
 4         for key, value in kwargs.items():
 5             setattr(obj, key, value)
 6         return obj
 7     return deco
 8 
 9 @Mul(x=1,y=2,z=3) #先运行Mul,将参数传递,然后运行 People=deco(People)
10 class People():
11     pass
12 
13 print(People.__dict__)
14 
15 @Mul(name='zhou')
16 class Bar():
17     pass
18 
19 print(Bar.__dict__)
给多个类赋不同的值

 

28.上下文管理协议

# with open('a.txt') as f:
# '代码块'

1.要有__enter__和 __exit__方法

2.__enter__的返回值返回给as 后面定义的变量

3.__exist__作为with语句的出口最后执行,且抛出异常中止,吞掉异常with可以正常结束,但异常后面的语句不会继续执行

4.

exc_type 异常类型

exc_val 异常值

exc_tb) 异常 traceback

 1 # with open('a.txt') as f:
 2 #     '代码块'
 3 
 4 class Open:
 5     def __init__(self, name):
 6         self.name = name
 7 
 8     def __enter__(self):
 9         print('this is __enter__')
10         return self
11 
12     
13     def __exit__(self, exc_type, exc_val, exc_tb):
14         print(exc_type)
15         print(exc_val)
16         print(exc_tb)
17         print('this is __exit')
18         return True      #返回True 可以将异常吃掉,with里面该异常后面的语句不会继续执行,但with 语句会正常结束。后面块的语句也可以正常执行
19 
20 
21 #__enter__ 的返回值会返回给as 语句,如果是文件则返回文件句柄
22 #__exit__语句运行结束之后 则with语句结束,所以在该语句里可以写自动清理的功能
23 with Open('a.txt') as f:
24     print(f)
25     print('---------->1')
26     print('---------->2')
27     print('---------->3')
28     print(实施的撒)
29     print('---------->4')
30     print('---------->5')
31 print('------------Final-----------') #即使有异常,但只要有__exit__ 的‘return True' 程序会正常结束
View Code

 

posted @ 2018-06-16 11:18  航点周  阅读(233)  评论(0)    收藏  举报