PythonI/O进阶学习笔记_3.2面向对象编程_python的封装

系统 1777 0

 

前言:

本篇相关内容分为3篇多态、继承、封装,这篇为第三篇 封装。

本篇内容围绕 python基础教程这段:
在面向对象编程中,术语对象大致意味着一系列数据(属性)以及一套访问和操作这些数据的方法。使用对象而非全局变量和函数的原因有多个,下面列出了使用对象的最重要的好处。
 多态:可对不同类型的对象执行相同的操作,而这些操作就像“被施了魔法”一样能够正常运行。
 封装:对外部隐藏有关对象工作原理的细节。
 继承:可基于通用类创建出专用类。
内容较多,这篇为下篇。

Content:

- 封装

1.数据封装和私有属性

2. 类变量和实例变量(对象变量)

3. 类属性和实例属性得查找顺序(MRO)

4. 静态方法 类方法和对象方法使用以及参数

5. python的接口和自省机制

6. 上下文管理器

====================================

1.python的数据封装和私有属性

a.python的__私有属性

python用__开头完成私有属性的封装。用__开头的属性名或者方法就没法直接外部获取,只有类中的公共方法才可以访问。

python的数据封装和java c++这种静态语言不同的是,静态语言其实本身有private类型的。而python是用小技巧实现了这种私有属性。

 
b.如何实现的?
以__开头的变量,python会对它进行变形,变形的模式是加上当前的class和变形的名称。
例: 如下的User中的__birthday变量,最后调用的时候变为 _User__birthday
实际上在python中这并不是真正的安全。其实即使在java里的private关键词对反射机制比较了解其实也不是绝对安全性。
python比java突破这个安全性更加简单。
 
c.一般什么情况用这种私有属性?
  • 隐藏起一个属性,不想让外部调用
  • 保护这个属性,不想让这个属性随意改变
  • 保护这个属性不被子类继承

 

2.类变量和实例变量

a.什么是python的类变量?

类下的变量。

例:
                
                  class
                
                
                   A():
    aa
                
                =1
              
其中aa就是类变量。
 
b.什么是实例变量?
                
                  class
                
                
                   A:
    aa
                
                =1
    
                
                  def
                
                
                  __init__
                
                
                  (self,x,y):
        self.x
                
                =
                
                  x
        self.y
                
                =y
              
其中,self是传递的对象(实例本身),x,y是对象参数。
先查找对象变量,再查找类变量。
 
c.类变量和实例变量的区别
类A是没有对象x和y的。 但是实例化的a有。
 
d.类变量被修改的影响 和实例变量被修改的影响
 
如果修改实例对象中aa的值,修改结果如何改变呢?
修改对象变量的类变量的值的时候,相当于多新建了一个对象a中的aa的值,并且实例a的对象值得查找顺序是:
先查找自己实例中,是否有这个变量,再往上查找。
 
3. 类属性和实例属性得查找顺序(MRO)
在继承那篇中,就有讲到MRO查找顺序,但是重点是在于查找子类的父类继承顺序,那么同理得到的属性查找顺序是什么样的呢?
回顾一下C3算法,这篇讲的比较明白: https://blog.csdn.net/u011467553/article/details/81437780
咱们再来看下面的输入,是否能看出输出是什么呢?
                
                  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)
              

PythonI/O进阶学习笔记_3.2面向对象编程_python的封装_第1张图片

 把代码中的print注释都拿掉,可以发现整个流程为:

PythonI/O进阶学习笔记_3.2面向对象编程_python的封装_第2张图片

 

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()
< __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
                  
                  
                    "
                  
                  )
                

或者简单版:

PythonI/O进阶学习笔记_3.2面向对象编程_python的封装_第3张图片

 

这个装饰器装饰的一定要是生成器。
__enter__中的代码都是yield之前的逻辑代码。
__exit__代码实在yield之后实现的代码逻辑。

 


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论