前言:html
本篇相关内容分为3篇多态、继承、封装,这篇为第三篇 封装。java
Content:python
- 封装c++
1.数据封装和私有属性算法
2. 类变量和实例变量(对象变量)sql
3. 类属性和实例属性得查找顺序(MRO)编程
4. 静态方法 类方法和对象方法使用以及参数安全
5. python的接口和自省机制app
6. 上下文管理器框架
====================================
1.python的数据封装和私有属性
a.python的__私有属性
python用__开头完成私有属性的封装。用__开头的属性名或者方法就无法直接外部获取,只有类中的公共方法才能够访问。
python的数据封装和java c++这种静态语言不一样的是,静态语言其实自己有private类型的。而python是用小技巧实现了这种私有属性。
2.类变量和实例变量
a.什么是python的类变量?
类下的变量。
class A(): aa=1
class A: aa=1 def __init__(self,x,y): self.x=x self.y=y
class Init(object): def __init__(self, v): #print("init") self.val = v #print("init:",self.val) class Add2(Init): def __init__(self, val): #print("Add2") super(Add2, self).__init__(val) #print("add2:",self.val) self.val += 2 class Mult(Init): def __init__(self, val): #print("Mult") super(Mult, self).__init__(val) #print("Mult:",self.val) self.val *= 5 class HaHa(Init): def __init__(self, val): #print("HAHA") super(HaHa, self).__init__(val) #print("Haha:",self.val) self.val /= 5 class Pro(Add2,Mult,HaHa): # pass class Incr(Pro): def __init__(self, val): super(Incr, self).__init__(val) self.val+= 1 # Incr Pro Add2 Mult HaHa Init p = Incr(5) print(p.val) c = Add2(2) print(c.val)
把代码中的print注释都拿掉,能够发现整个流程为:
4. 静态方法 类方法和对象方法使用以及参数
a.静态方法 staticmethod
- 静态方法定义:
使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,可是方法体中不能使用类或实例的任何属性和方法
- 静态方法的一些特色:
静态方法是类中的函数,不须要实例。
静态方法主要是用来存放逻辑性的代码,主要是一些逻辑属于类,可是和类自己没有交互,即在静态方法中,不会涉及到类中的方法和属性的操做。
能够理解为将静态方法存在此类的名称空间中。事实上,在python引入静态方法以前,一般是在全局名称空间中建立函数。-
- 静态方法调用:
例:我要在类中实现一个获得如今时间的方法。与传进去的任何参数都无关那种。
import time class TimeTest(object): def __init__(self, hour, minute, second): self.hour = hour self.minute = minute self.second = second @staticmethod def showTime(): return time.strftime("%H:%M:%S", time.localtime()) print(TimeTest.showTime()) t = TimeTest(2, 10, 10) nowTime = t.showTime() print(nowTime)
b.类方法
- 类方法定义:
使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名通常约定为“cls”,经过它来传递类的属性和方法(不能传实例的属性和方法)
- 类方法的一些特色:
将类自己做为对象进行操做。
无论这个方式是从实例调用仍是从类调用,它都用第一个参数把类传递过来
- 类方法使用:
例:实现一个基类作一个有颜色属性的抽象共性,对于实际的颜色的值须要结合实际子类传递的值进行匹配
class ColorTest(object): color = "color" @classmethod def value(self): return self.color class Red(ColorTest): color = "red" class Green(ColorTest): color = "green" g = Green() print(g.value()) print(Green.value())
这时候可能有人会以为,这个跟实例方法(普通方法)不是同样的嘛,继承父类,而且用继承中的知识重写父类中的属性或者方法?
重点就在于,若是咱们把@classmethod这个方法去掉,Green.value()这样去调用是会报错的。
由于须要传递实例参数进去,而不能直接用类调用。
c.对象方法(实例方法)
- 实例方法定义:
第一个参数必须是实例对象,该参数名通常约定为“self”,经过它来传递实例的属性和方法(也能够传类的属性和方法)
- 实例方法的一些特色:
只能由类的实例来调用,就是咱们平时最经常使用的。
比较简单,没有特殊装饰器,暂不举例。
5.python的接口和自省机制
a.什么是python的自省机制
当咱们须要实现一个通用的DBM框架时,可能须要对数据对象的字段赋值,但咱们没法预知用到这个框架的数据对象都有些什么字段,换言之,咱们在写框架的时候须要经过某种机制访问未知的属性。
也就是说,咱们须要在不少时候去访问python本身为咱们作了哪些隐藏的事情,或者某个框架里具体实现了哪些方法等。
经过python的自省机制去让python告诉咱们,咱们查询的对象是什么,有哪些功能等。
b.python自省之访问对象的属性
例有下面这个类,而且实例化了一个a对象。
class Company(object): def __init__(self,company_name,staffs=[]): self.company_name=company_name self.staffs=staffs def add(self,staff): self.staffs.append(staff) def remove(self,staff): self.staffs.remove(staff) user_list=['tangrong1','tangrong2','tangrong3'] a=Company("aaa",user_list)
我须要去获得类里的一些方法和属性:
####访问对象的属性 #dir() 调用这个方法将返回包含obj大多数属性名的列表(会有一些特殊的属性不包含在内)。obj的默认值是当前的模块对象。 print("dir()") print(dir(Company)) print(dir(a)) #hasattr(obj,attr) 这个方法用于检查obj是否有一个名为attr的值的属性,返回一个布尔值 print("hasattr()") print(hasattr(a,"add")) print(hasattr(a,"staffs")) print(hasattr(a,"a")) #getattr(obj, attr) 调用这个方法将返回obj中名为attr值的属性的值,例如若是attr为'staffs',则返回obj.staffs。 print("getattr()") print(getattr(a,"add")) print(getattr(a,"staffs")) #setattr(obj, attr, val) 调用这个方法将给obj的名为attr的值的属性赋值为val。例如若是attr为'bar',则至关于obj.bar = val。 print("setattr()") print(setattr(a,"staffs",["tangrong4","tangrong5"])) print(a.staffs)
输出为:
dir() ##ps:能够发现,实例和类的dir()列出来的有些不同 ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'add', 'remove'] ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__',
'add', 'company_name', 'remove', 'staffs']
hasattr() True True False
getattr() <bound method Company.add of <__main__.Company object at 0x000002D3172F2518>> ['tangrong1', 'tangrong2', 'tangrong3']
setattr() None ['tangrong4', 'tangrong5']
c.python自省之访问对象的元数据
包括各类__dict__()\__doc__\__bases__等
内容比较多,可看这篇:https://www.cnblogs.com/huxi/archive/2011/01/02/1924317.html
6.上下文管理器
a.什么是上下文管理器?
上下文管理器就是实现了上下文管理协议的对象。主要用于保存和恢复各类全局状态,关闭文件等,上下文管理器自己就是一种装饰器。
感受上句很像白说是否是- -。实际例就是,相似于with语句,就是遵循了上下文管理协议,才能在内部咱们看不到的地方,帮咱们完成了退出时作出关闭文件、执行自定义代码块的操做的。就不用咱们显示判断调用读取完了就关闭文件这种操做。
with open("test/test.txt","w") as f_obj: f_obj.write("hello")
b.用with看他遵循的上下文管理协议
上下文管理协议包括两个方法:
contextmanager.__enter__()
从该方法进入运行时上下文,并返回当前对象或者与运行时上下文相关的其余对象。若是with语句有as关键词存在,返回值会绑定在as后的变量上。
contextmanager.__exit__(exc_type, exc_val, exc_tb)
退出运行时上下文,并返回一个布尔值标示是否有须要处理的异常。若是在执行with语句体时发生异常,那退出时参数会包括异常类型、异常值、异常追踪信息,不然,3个参数都是None。
能用with语句的对象,也是由于这个对象里,遵循了这个协议。
with语句就是为支持上下文管理器而存在的,使用上下文管理协议的方法包裹一个代码块(with语句体)的执行,并为try...except...finally提供了一个方便使用的封装。
咱们建立一个能支持with(上下文管理协议)的类,这个类实现了db最开始创建链接,退出时关闭链接的操做。
import sqlite3 class DataConn: def __init__(self,db_name): self.db_name = db_name def __enter__(self): self.conn = sqlite3.connect(self.db_name) return self.conn def __exit__(self,exc_type,exc_val,exc_tb): self.conn.close() if exc_val: raise if __name__ == "__main__": db = "test/test.db" with DataConn(db) as conn: cursor = conn.cursor()
c.用contextlib自定义上下文管理器
from contextlib import contextmanager @contextmanager def file_open(path): try: f_obj = open(path,"w") yield f_obj except OSError: print("We had an error!") finally: print("Closing file") f_obj.close() if __name__ == "__main__": with file_open("test/test.txt") as fobj: fobj.write("Testing context managers")
或者简单版: