python封装enclosure

封装enclosure

  封装是指隐藏类的实现细节,让使用者不关心这些细节
  封装的目的是让使用者能过尽可能少的方法或属性操作对象
  python的封装是模拟的封装

私有属性和方法:
  python类中以双下划线'__' 开头,不以双下划线结尾的标识符为私有成员,私有成员只能使用方法进行访问和修改

  两种:
  私有属性
  私有方法--- 只能让该类的方法来调用

  class A:
    def __init__(self):
      self.__money = 0

    def show_money(self):
      print("self.__money = ",self.__money)
    def make_money(self, m):
      self.__money += m
  a = A()
  a.__money = 100 # 修改属性
  print(a.__money) # 属性取值
  a.show_money() # 0
  a.make_money(999)
  a.show_money() # 999
View Code

多态 polymorphic:
  字面意思是"多种状态"
  多态是指在有继承/派生关系的类中,调用基类的对象的方法,实际能调用子类的覆盖方法的现象叫多态
  状态:
    静态(编译时状态)
    动态(运行时状态)
  说明:
    python全部对象都只有运行时状态,没有编译时状态

  class A:
    def do(self):
      print("A")

  class B(A):
    def do(self):
      print("B")

  class C(B):
    def do(self):
      print('C')

  def work(obj):
    obj.do() # 请问调用谁?

  L = [A(), B(), C(), B()]
  for x in L:
    work(x)
View Code

多继承 multiple inheritance
  多继承是指一个子类继承自两个或两个以上的基类

  语法:
    class 类名(基类名1, 基类名2, ....):
      语句块
  说明:
    一个子类同时继承自多个父类,父类中的方法可以同时被继承下来
    如果两个父类中有同名的方法,而在子类中又没有覆盖此方法时,调用结果难以确定

  class Plane:
    def fly(self, height):
      print("飞机以海拔", height, "米的高度飞行")

  class Car:
    def run(self, speed):
      print("汽车以", speed, 'km/h的速度行驶')

  class PlaneCar(Plane, Car):
    '''PlaneCar同时继承自汽车类和飞机类'''

  pc = PlaneCar()
  pc.run(300)
  pc.fly(10000)
View Code

多继承的问题(缺陷)
  标识符冲突的问题
  要谨慎使用多继承

  # 小张写了一个类A:
  class A:
    def m(self):
      print("A")

  # 小李写了一个类B
  class B:
    def m(self):
      print("B")

  # 小王感觉小张和小李写的类自己可以用
  class AB(A, B):
    pass

  ab = AB()
  ab.m() # 调用谁由继承列表中先后顺序来决定
View Code

多继承的问题MRO(method resolution order)问题
  类的 __mro__属性
    用来记录每个类的方法的查找顺序

用MRO来确定钻石继承的方法查找顺序
    A
    / \
   B C
    \ /
    D

  class A:
    def go(self):
      print("A")

  class B(A):
    def go(self):
      print("B")
      super().go() # C

  class C(A):
    def go(self):
      print("C")
      super().go() # A

  class D(B, C):
    def go(self):
      print('D')
      super().go()

  d = D()
  d.go() # ???
View Code

面向对象编程语言特征
  封装
  继承
  多态

面向对象的编程语言:
  C++, C#, Python, Java, objective-c, swift, ...

函数(方法)重写
  在自定义的类内添加相应的方法,让自定义的类创建的实例像内建对象一样进行内建函数操作

对象转字符串函数的重写(覆盖)
  repr(obj) 返回一个符合Python语法规则的字符串:
    通常:
      eval(repr(obj)) == obj
  str(obj) 通过给定的对象返回一个字符串(这个字符串通常是给人阅读的)

说明:
  1. str(obj) 函数先查找obj.__str__() 方法,调用此方法并返回结果
  2. 如果obj.__str__() 方法不存在,则调用obj.__repr__()方法并返回结果
  3. 如果obj.__repr__方法不存在,则调用object类的__repr__实例方法显示<__main__.XXX object at 0xAABBCCDD>格式的字符串

  # 此示例示意 重写__repr__ 和 __str__方法,实现自定义类的
  # 个性化显示

  class MyNumber:
    def __init__(self, value=0):
      self.data = value

    def __str__(self):
      '''此方法必须返回字符串'''
      print("__str__方法被调用")
      return "数字:%d" % self.data

    def __repr__(self):
      return "MyNumber(%d)" % self.data

  n1 = MyNumber(100)
  print("repr(n1)=", repr(n1))
  # print("str(n1)=", n1.__str__()) # ???
  print("str(n1) =", str(n1)) # 数字: 100
  print(n1) # 内部会调用str(n1)

  n2 = MyNumber(200)
  print("repr(n2)=", repr(n2)) # repr(n2)-->n2.__repr__()
View Code

重载方法:
  repr() 函数对应 def __repr__(self):
  str() ---------> def __str__(self):

内建函数的重写
  __abs__      abs(obj)
  __len__      len(obj)
  __reversed__   reversed(obj)
  __round__     round(obj)

  class MyList:
    def __init__(self, iterable=()):
      self.data = [x for x in iterable]

    def __len__(self):
      '''此函数必须只有一个形参self,此函数必须返回整数'''
      # return self.data.__len__()
      return len(self.data)

    def __repr__(self):
      return 'MyList(%s)' % self.data

    def __abs__(self):
      L = [abs(x) for x in self.data]
      return MyList(L) # 创建一个新的MyList对象并返回

  myl = MyList([1, -2, 3, -4, 5])
  print(len(myl)) # myl.__len__()
  myl2 = abs(myl) # myl.__abs__()
  print(myl2) # MyList([1, 2, 3, 4, 5])
View Code

数据转换函数重写
  __complex__    complex(obj)
  __int__      int(obj)
  __float__     float(obj)
  __bool__     bool(obj)

  class MyNumber:
    def __init__(self, value=0):
      self.data = value

    def __repr__(self):
      return "MyNumber(%d)" % self.data

    def __int__(self):
      '''此方法必须返回整数'''
      return int(self.data)

  n1 = MyNumber(100)
  x = int(n1) # x = 100 # x = n1.__int__()
  print(x)
View Code

布尔测试函数重写
  作用:
    用于bool(obj) 函数取值
    用于if语句真值表达式取值
    用于while 语句真值表达式取值
  方法名: __bool__
  说明:
    当存在__bool__方法时,调用obj.__bool__() 取值
    当不存在__bool__方法时,调用obj.__len__() 取值
    当再不存在__len__方法时,直接返回True

  class MyList:
    def __init__(self, iterable=()):
      self.data = [x for x in iterable]

    def __len__(self):
      '''返回0为假值,返回非零值为真值'''
      return len(self.data)

    def __bool__(self):
      return all(self.data)

  myl = MyList([1, -2, 3, -4, 5])
  print(myl)
  print(bool(myl)) # ???
  if myl:
    print("")
  else:
    print("")
View Code

迭代器(高级)
  迭代器可以能过next(obj) 函数取值的对象,就是迭代器

  迭代器协议:
    迭代器协议是指对象能够使用next函数获取下一项数据,在没有下一项数据时触发一个StopIteration异常来终止迭代的约定

  迭代器协议的实现方法:
    __next__(self)

可迭代对象:
  是指能用iter(obj) 函数返回迭代器的对象
  可迭代对象的实现方法:
    __iter__(self)

  class MyList:
    def __init__(self, iterable=()):
      self.data = [x for x in iterable]

    def __repr__(self):
      return 'MyList(%s)' % self.data

    def __iter__(self):
      return MyListIterator(self.data)

  class MyListIterator:
    def __init__(self, data):
      self.data = data
      self.cur_index = 0 # 用来记录当前访问位置的索引

    def __next__(self):
      '''此方法需要实现迭代器协议'''
      if self.cur_index >= len(self.data):
        raise StopIteration # 通知调用者停止迭代
      r = self.data[self.cur_index]
      self.cur_index += 1
      return r

  # import time
  myl = MyList([1, -2, 3, -4, 5])
  print(sum(myl)) # 3
  print(max(myl)) # 5

  # it = iter(myl) # it = myl.__iter__()
  # while True:
  #  try:
  #    x = next(it) # x = it.__next__()
  #    print(x)
  #    time.sleep(1)
  #  except StopIteration:
  #    break

  for x in myl:
    print(x) # 1 -2 3 -4 5
View Code

 

posted @ 2019-04-14 21:04  你厉害。  阅读(267)  评论(0编辑  收藏  举报