look321 发表于 2018-8-13 10:02:05

Python第八课----面向对象

  一、面向对象
  1、封装:
  1、组装:将数据和操作(即属性和方法)组装到一起
  2、隐藏数据:对外只暴露一些接口,通过接口访问对象
  2、继承:
  1、多复用,继承的便不用自己写了
  2、多继承少修改,OCP-----减少冗余,增加复用
  3、多态:
  python不太需要了解
  二、Python的类
  1、定义:
  1、必须使用class关键字
  2、类名必须是大驼峰
  3、类定义完成后就产生了一个类对象,绑定到了ClassName上
  class MyClass: # 定义一个类

  """A example>  x = 'abc' # 类属性
  def foo(self): # 类方法,self自带

  return 'My>  print(MyClass.x)
  print(MyClass.foo)
  print(MyClass.__doc__)
  三、类对象及类属性
  1、类对象,类的定义就会生成一个类对象
  2、类的属性,类定义中的变量和类中定义的方法都是类的属性
  3、类变量,x是MyClass的变量
  MyClass中,x和foo以及__doc__都是类的属性
  foo是method方法对象,不是普通的function,它必须至少一个参数,第一个必须是self。
  self纸袋当前实例本身
  4、实例化:a = MyClass( )
  5、__init__方法
  Python类实例化后,会自动调用__init__方法,这个方法第一个参数必须是self
  MyClass( )实际上调用的是__init__(self)方法,可以不定义,如果没有会在实例化后隐式调用
  作用:对实例进行初始化
  class MyClass:
  def __init__(self):
  print('init')
  a = MyClass() # 这个就会调用__init__
  初始化函数可以多个参数,第一个位置必须给self
  class Person:
  def __init__(self,name,age):
  self.name = name
  self.age = age
  def showage(self):
  print('{} is {}'.format(self.name,self.age))
  tom = Person('Tom',20) # 实例化
  jerry = Person('Jerry',25)
  print(tom.name,jerry.age)
  jerry.age += 1
  print(jerry.age)
  jerry.showage() # 调用方法
  __init__()方法不能有返回值,也就是只能是None
  6、实例对象instance
  类实例化后一定会获得一个对象,就是一个实例对象,tom,jerry都是Person的实例
  __init__方法的第一参数self就是指代某一个实例
  class MyClass:
  def __init__(self):
  print('self in init = {}'.format(id(self)))
  c = MyClass()
  print('c = {}'.format(id(c)))--------->实例化会把c送到self的位置
  7、实例变量和类变量
  class Person:
  age = 3
  def __init__(self,name):
  self.name = name
  tom = Person('Tom')
  jerry = Person('Jerry')
  print(tom.name,tom.age)
  print(jerry.name,jerry.age)
  print(Person.age)
  Person.age = 30
  print(Person.age,tom.age,jerry.age)
  实例变量是每一个实例自己的变量,是自己独有,类变量是类的变量,是类的所有实例共享的属性和方法
  8、
  特殊含义
  含义
  __name__
  对象名
  __class__
  对象的类型
  __dict__
  对象的属性字典
  __qualname__
  类的限定名
  举例:
  class Person:
  age = 3
  def __init__(self,name):
  self.name = name
  print(Person.__class__)
  print(sorted(Person.__dict__.items()),end='\n\n')
  tom = Person('Tom')
  print(tom.__class__)
  print(tom.__dict__,end='\n')
  print(tom.__class__.__name__)
  print(tom.__class__.__dict__)
  是类的,就是这个类所有实例的,其实例都可以访问,是实例的,就是这个实例自己的,通过类访问不到。
  类变量是属于类的变量,这个类的实例可以共享
  实例可以动态给自己增加一个属性。实例的.__dict__[变量名]和实例.变量名都可以访问到
  实例的同名变量,就是实例自己的,会覆盖类的同名变量,但类的变量不变
  class Person:
  age = 3
  height = 170
  def __init__(self,name,age=18):
  self.name = name
  self.age = age
  tom = Person('Tom')
  jerry = Person('Jerry',20)
  Person.age = 30
  print(Person.age,tom.age,jerry.age)
  print(Person.height,tom.height,jerry.height)
  tom.height += 10
  print(Person.height,tom.height,jerry.height)
  Person.height += 15
  print(Person.height,tom.height,jerry.height)
  Person.weight = 70
  print(Person.weight,tom.weight,jerry.weight)
  print(tom.__dict__['height'])
  print(tom.__dict__['weight'])
  9、实例属性的查找顺序
  tom.__dict__---->tom.__class__---->Person.__dict__
  类变量使用全大写来命名
  10、装饰一个类
  def add_name(name):
  def wrapper(clz):
  clz.NAME = name
  return clz
  return wrapper
  @add_name('Tom')   # add_name = add_name('Tom')(Person)
  class Person:
  AGE = 3
  print(Person.NAME)
  11、类方法
  class Person:
  @classmethod   ----->装饰器,自带的,写法如下
  def class_method(cls):---->必须至少有一个参数,第一个默认cls,即类对象自身
  cls.HEIGHT = 170
  Person.class_method()----->需要运行一下,才能写进去
  print(Person.__dict__['HEIGHT'])
  cls不能调用类的实例,因为cls是class_method的
  12、静态方法:
  class Person:
  @classmethod
  def class_method(cls):
  cls.HEIGHT = 170
  @staticmethod
  def static_method():------>静态方法
  print(Person.HEIGHT)
  Person.class_method()
  Person.static_method()
  print(Person.__dict__)
  13、方法的调用
  class Person:
  def normal_method():
  print('normal')
  def method(self):
  print("{}'s method".format(self))
  @classmethod
  def class_method(cls):
  print('class = {0.__name__}.({0})'.format(cls))
  cls.HEIGHT = 170
  @staticmethod
  def static_method():
  print(Person.HEIGHT)
  print(1,Person.normal_method())
  # print(2,Person.method()) 这个不行
  print(3,Person.class_method())
  print(4,Person.static_method())
  print(Person.__dict__)
  tom = Person()
  # print(1,tom.normal_method()) 这个不行,不能给参数
  print(2,tom.method())
  print(3,tom.class_method()) # 可以,但是还是Person
  print(4,tom.static_method())
  类几乎可以调用所有内部定义的方法,但是调用普通方法会报错,因为第一个参数必须是类的实例
  实例也几乎可以调用所有的方法,普通函数的调用一般不会出现,不允许这么定义
  总结:
  类除了普通方法,都可以调用,普通方法需要对象的实例作为第一参数
  实例可以调用所有类中定义的方法(包括类方法,静态方法),普通方法传入实例自身,静态和类方法,需要找到实例的类
  四、访问控制
  1、私有属性Private
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.age = age
  def growup(self,i=1):
  if i > 0 and i < 150:
  self.age += i
  p1 = Person('Tom')
  p1.growup(20) # 正常范围
  print(p1.age)
  p1.age = 160 # 超过范围,还突破了if逻辑
  print(p1.age)
  私有属性方法:使用双下划线开头的属性名,就是私有属性
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age
  def growup(self,i=1):
  if 0 < i < 150:
  self.__age += i
  p1 = Person('Tom')
  p1.growup(20)
  print(p1.__age) # 这句不能访问,因为__把它隐藏了
  print(p1._Person__age) # 不过依然可以访问,只是约定不访问
  访问方式:新建一个函数,直接内部返回定义的__age,外部实例调用这个函数即可
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age
  def growup(self,i=1):
  if 0 < i < 150:
  self.__age += i
  def getage(self):
  return self.__age
  p1 = Person('tom')
  print(p1.getage())
  p1.growup(20)
  print(p1.getage())
  2、保护变量
  在变量名前使用一个下划线,成为保护变量,就是个约定
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self._age = age
  tom = Person('Tom')
  print(tom._age)
  print(tom.__dict__)
  3、私有方法
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self._age = age
  def _getname(self): # 保护变量
  return self.name
  def __getage(self): # 私有变量
  return self._age
  tom = Person('Tom')
  print(tom._getname()) # 下划线只是约定保护,没什么卵用
  # print(tom.__getage()) # 无此属性
  print(tom.__dict__)
  print(tom.__class__.__dict__)
  print(tom._Person__getage())
  五、补丁:可以通过修改或者替换类的成员。使用者调用的方式没有改变,但是类提供的功能可能已经变了
  猴子补丁,在运行时,动态替换属性,慎用
  test代码:
  class Person:
  def get_score(self):
  ret = {'English':80,'Chinese':99,'History':90}
  return ret
  test1代码:
  def get_score(self):
  return dict(name=self.__class__.__name__,English=10,Chinese=20,History=30)
  test2代码:
  from test import Person   ---->导入Person
  from test1 import get_score---->导入修改模块
  def monkeypatch4Person():    ---->定义补丁函数
  Person.get_score = get_score---->将原需要修改的地方替换成现在的函数
  monkeypatch4Person()      ---->运行一下
  if __name__=="__main__":
  print(Person().get_score())   ---->测试结果
  六:属性装饰器
  一般设计是:将实例的属性保护起来,不让外部访问,外部使用getter读取和setter设置信息
  原理:
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age   ---->私有起来
  def age(self):
  return self.__age---->外部读取实例属性信息
  def set_age(self,age):
  self.__age = age   ---->外部修改实例属性
  tom = Person('Tom')
  print(tom.age())
  tom.set_age(20)
  print(tom.age())
  实际应用方法;
  property装饰器:后面跟的函数名就是以后的属性名,它就是getter,这个必须有,有了就是只读
  setter装饰器:与函数名同名,且接受两个参数,第一个self,第二个要修改的值,有了它,可写
  deleter装饰器:可以删除属性,很少用
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age ---->定义一个私有属性
  @property   ---->装饰器私有属性
  def age(self): ---->定义函数读取属性
  return self.__age
  @age.setter
  def age(self,age): ---->定义函数修改属性
  self.__age = age
  @age.deleter
  def age(self):   ---->定义函数删除属性
  del self.__age
  tom = Person('Tom')
  print(tom.age)
  tom.age = 20
  print(tom.age)
  # del tom.age
  # print(tom.age)
  其他写法:
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age
  def getage(self):
  return self.__age
  def setage(self,age):
  self.__age = age
  def delage(self):
  del self.__age
  age = property(getage,setage,delage,'age property')--->这句写上后面可以直接.age
  tom = Person('Tom')
  print(tom.age)
  tom.age = 20
  print(tom.age)
  del tom.age
  或者;
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age
  age = property(lambda self:self.__age)
  tom = Person('Tom')
  print(tom.age)
  七、对象的销毁:
  类中可以定义__del__方法,成为析构函数(方法)
  作用:销毁类的实例的时候调用,以释放占用的资源
  由于python实现了垃圾回收机制,但不能确定何时执行,有必要时,使用del语句删除实例,手动调用
  class Person:
  def __init__(self,name,age=18):
  self.name = name
  self.__age = age
  def __del__(self):
  print('del')
  tom = Person('Tom')
  del tom
  print(tom.__dict__)
  八、类的继承
  1、通过继承,不需要写代码就可以继承父类的属性和方法
  class Animal:
  def __init__(self,name):
  self._name = name
  def shout(self):
  print('{} shout'.format(self.__class__.__name__))
  @property
  def name(self):
  return self._name
  a = Animal('monster')
  a.shout()
  class Cat(Animal):
  pass
  cat = Cat('garfield')
  cat.shout()
  print(cat.name)
  class Dog(Animal):
  pass
  dog = Dog('ahuang')
  dog.shout()
  print(dog.name)
  2、特殊属性和方法
  特殊属性和方法
  含义
  示例
  __base__
  类的基类
  __bases__
  类的基类元组
  __mro__
  显示方法查找顺序,基类的元组
  mro()
  同上
  int.mro()
  __subclasses__()
  类的子类列表
  int.subclasses__()
  3、继承中的访问控制
  class Animal:
  __COUNT = 0
  HEIGHT = 0
  def __init__(self,age,weight,height):
  self.__COUNT += 1
  self.age = age
  self.__weight = weight
  self.HEIGHT = height
  def eat(self):
  print('{} eat'.format(self.__class__.__name__))
  def __getweight(self):
  print(self.__weight)
  @classmethod
  def showcount1(cls):
  print(cls.__COUNT)
  @classmethod
  def __showcount2(cls):
  print(cls.__COUNT)
  class Cat(Animal):
  NAME = 'CAT'
  c = Cat(3,5,15)
  c.eat()
  print(c.HEIGHT)
  c.showcount1() # 类方法,实例无法调用,相当于类调用
  print(c.NAME)
  print('{}'.format(Animal.__dict__))
  print('{}'.format(Cat.__dict__))
  print(c.__dict__)
  print(c.__class__.mro())
  从父类继承,自己没有的,就可以到父类中找
  私有的都是不可以访问的,本质上是改了名
  4、方法的重写、覆盖override
  class Animal:
  def shout(self):
  print('Animal shout')
  class Cat(Animal):
  def shout(self):
  print('miao')
  def shout(self):
  print(super())
  print(super(Cat,self))
  super().shout()
  a = Animal()
  a.shout()
  c = Cat()
  c.shout()
  print(a.__dict__)
  print(c.__dict__)
  print(Animal.__dict__)
  print(Cat.__dict__)
  覆盖自身也是可以的
  5、继承中的初始化
  class Animal:
  def __init__(self,age):
  print('Animal init')
  self.age = age
  def show(self):
  print(self.age)
  class Cat(Animal):
  def __init__(self,age,weight):
  super().__init__(age)
  print('Cat init')
  self.age = age + 1
  self.weight = weight
  c = Cat(10,5)
  c.show()
  九、多继承
  1、python3都是新式类,继承子object,新式类可以使用super
  2、多继承:OCP原则,多继承,少修改,增强基类,实现多态
  3、多态:在面向对象中,父类、子类通过继承练习在一起,如果一套方法,可以实现不同表现,就是多态
  4、一个类继承自多个类就是多继承,它将具有多个类的特征
  5、python使用MRO(method,resolution)
页: [1]
查看完整版本: Python第八课----面向对象