yunde110 发表于 2018-8-13 11:37:55

Python3.5修炼手册13-duyuheng

  面向对象编程
  python是一门面向对象编程语言,对面向对象语言编程的过程叫做面向对象.
  面向对象程序设计把计算机程序视为一组对象的集合,每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序执行的就是一系列消息在各个对象之间传递.
  在python中,所有数据类型都被视为对象,也可以自定义对象.自定义对象数据类型就是面对对象中的类(Class)的概念.
  面向对象术语简介:
  类: 用来描述具有相同属性和方法的对象集合.类定义了集合中每个对象共有的属性和方法.对象式类的实例.
  类变量(属性): 类变量在整个实例化的对象中是公用的.类变量定义在类中,且在方法之外.类变量通常不作为实例变量使用.类变量也称作属性.
  数据成员: 类变量或实例变量用于处理类及其实例对象的相关数据.
  方法重写: 如果从父继承的方法不能满足子类的需求,就可以对其内容进行改写,这个过程称为方法的覆盖(Override),也称为方法的重写.
  实例变量: 定义在方法中的变量只能作用于当前实例的类.
  多态(Polymorphism): 对不同类的对象使用同样的操作.
  封装(Encapsulation): 对外部世界隐藏对象的工作细节.

  继承(Inheritance): 即一个派生类(derived>  实例化(Instance): 创建一个类的实例,类的具体对象.
  方法:类中定义的函数.
  对象: 通过类定义的数据jiegou实例.对象包括两个数据成员(类变量和实例变量)和方法.
  python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类、派生类可以覆盖基类中的任何方法、方法中可以调用基类中同名方法.
  对象可以包含任意数量和类型的数据.
  类的定义与使用
  类的定义
  类的语法格式如下:

  >  <statement-1>
  .
  .
  .
  <statement-N>
  由代码段和类的定义我们看到,python中定义类使用class关键字,class后面紧接着类名,类名通常是大写开头的字母;紧接着是(object),表示该类从哪个类继承下来的.通常,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类.类包含属性和方法(相当于函数中的语句和方法).
  注意:在类中定义方法的形式和函数差不多,但是不称为函数,而称为方法.方法的调用需要绑定到特定对象上,而函数不需要.
  类的使用
  例如:
class MyClass(object):  
    i = 123
  
    def f(self):
  
          return 'helloworkd'
  
user_class = MyClass()
  
print('调用类的属性:',user_class.i)
  
print('调用类的方法:',user_class.f())
  C:\python\python.exe C:/python.py/lei.py
  调用类的属性: 123
  调用类的方法: helloworkd
  由上例的调用方式可知,类的用比函数多了几个操作,调用类时需要执行如下操作:
  user_class = MyClass()
  这步叫做实例化,即创建一个类的实例.此处得到的use_class变量称为类的具体对象.
  user_class.i用于调用类的属性,也就是所谓的类变量.
  user_class.f()用于调用类的方法.
  对于类中定义方法的要求:在类中定义方法时,第一个参数必须式self.除第一个参数外,类的方法和普通函数没什么区别,如可以使用默认参数、可变参数、和命名关键字参数等.
  对于在类中调用方法的要求:要调用一个方法,在实例变量上直接调用即可.除了self不用传递,其他参数正常传入.
  类对象支持两种操作,即属性引用和实例化.属性引用的标准语法如下:
  obj.name
  语法中obj.代表类对象,name代表属性.
  深入类
  类的构造方法
  例如:
class MyClass(object):  
    i = 123
  
    def __init__(self,name):
  
      self.name = name
  
    def f(self):
  
         return'hello,'+self.name
  
user_class = MyClass('duyuheng')
  
print('调用类的属性:',user_class.i)
  
print('调用类的方法:',user_class.f())
  C:\python\python.exe C:/python.py/lei.py
  调用类的属性: 123
  调用类的方法: hello,duyuheng
  从上例输出结果可以看到,实例化MyClass类时调用了__init__()方法.
  在python中,__init__()方法是一个特殊方法,在对象爱实例化时会被调用__init__()的意思式初始化,式initialization的简写.这个方法的书写方式是:先输入两个下划线,后接着init在接着两个下划线,这个方法也叫构造方法.
  在定义类时,若不显示到定义一个__init__()方法,则程序默认调用一个无参的__init__()方法.
  代码对比:
  代码一:使用__init__()方法
class DefaultInit(object):  
    def __init__(self):
  
      print('类实例化时执行我,我是__init__方法.')
  
    def show(self):
  
      print('我是类中定义的方法,需要通过实例化对象调用.')
  
test =DefaultInit()
  
print('类实例化结束.')
  
test.show()
  C:\python\python.exe C:/python.py/lei.py
  类实例化时执行我,我是__init__方法.
  类实例化结束.
  我是类中定义的方法,需要通过实例化对象调用.
  代码二:不使用__init__方法
class DefaultInit(object):  
    def show(self):
  
      print('我是类中定义的方法,需要通过实例化对象调用.')
  
test =DefaultInit()
  
print('类实例化结束.')
  
test.show()
  C:\python\python.exe C:/python.py/lei.py
  类实例化结束.
  我是类中定义的方法,需要通过实例化对象调用.
  从上面两段代码可以看出,当代码中定义了__init__()方法时,实例化类时会调用该方法;若没有定义__init__()方法,也不会报错,此时调用默认的__init__()方法.
  在python中定义类时若没有定义构造方法(__init__()方法),则在类的实例化时系统调用默认的构造方法.另外,__init__()方法可以有参数,参数通过_=__init__()传递到类的实例化操作上.
  __init__()方法是python中构造方法,那么是否可以在一个类中定义多个构造方法呢?
  例一:只有一个不带参数的__init__()方法
class DefaultInit(object):  
    def __init__(self):
  
      print('我是不带参数的__init__()方法.')
  
DefaultInit()
  
print('类实例化结束.')
  C:\python\python.exe C:/python.py/lei.py
  我是不带参数的__init__()方法.
  类实例化结束.
  只有一个__init__()方法时,实例化类时没有什么顾虑.
  例二:第一个为不带参数的,第二个为带参数的__init__()方法
class DefaultInit(object):  
    def __init__(self):
  
      print('我是不带参数的__init__()方法.')
  
    def __init__(self,param):
  
      print('我是带参数的__init__()方法,参数值为:',param)
  
DefaultInit('hello')
  
print('类实例化结束.')
  C:\python\python.exe C:/python.py/lei.py
  我是带参数的__init__()方法,参数值为: hello
  类实例化结束.
  由执行结果可以看到,调用的是一个带pram参数的构造方法.
  注意:此例实例化类时只能调用带两个占位参数的构造方法,调用其他的方法都会报错.
  例三:第一个为带参数的,第二个为不带参数的__init__()方法
class DefaultInit(object):  
    def __init__(self, param):
  
      print('我是带参数的__init__()方法,参数值为:', param)
  
    def __init__(self):
  
      print('我是不带参数的__init__()方法.')
  
DefaultInit()
  
print('类实例化结束.')
  C:\python\python.exe C:/python.py/lei.py
  我是不带参数的__init__()方法.
  类实例化结束.
  由执行结果可以看到,调用的构造方法除了self外,没有其他参数.
  注意:此例实例化类时只能调用一个带占位参数的构造方法,调用其他构造方法都会报错.
  结论:一个类中可以定义多个构造方法,但是实例化类时只能实例化到最后的构造方法,即后面的构造方法会覆盖前面的构造方法,并且需要根据最后一个构造方法的形式进行实例化.建议一个类中只定义一个构造函数.\
  类的访问权限
  在类内部有属性和方法,外部代码可以通过直接调用实例变量的方法操作数据,这样就隐藏了内部的复杂逻辑.
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.name = name
  
      self.score = score
  
    def info(self):
  
      print('学生:%s; 分数:%s '%(self.name,self.score))
  
stu = Student('duyuheng',95)
  
print('修改前分数:',stu.score)
  
stu.info()
  
stu.score=0
  
print('修改后分数:',stu.score)
  
stu.info()
  C:\python\python.exe C:/python.py/lei.py
  修改前分数: 95
  学生:duyuheng; 分数:95
  修改后分数: 0
  学生:duyuheng; 分数:0
  由输出结果可以看出,在类中定义非构造方法可以调用类中的构造方法实现变量的属性,调用的方式为self.实例变量属性名,如上例中的self.name和self.score.可以在类的外部修改类的内部数属性.
  要是让内部属性不被外部访问,可以在属性名前面加两个下划线__.在python中,实例的变量名如果以__开头,就会变成私有变量(private),只有内部可以访问,外部不能访问.
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.__name = name
  
      self.__score = score
  
    def info(self):
  
      print('学生:%s; 分数:%s '%(self.__name,self.__score))
  
stu = Student('duyuheng',95)
  
print('修改前分数:',stu.__score)
  
stu.info()
  
stu.score=0
  
print('修改后分数:',__stu.score)
  
stu.info()
  C:\python\python.exe C:/python.py/lei.py
  Traceback (most recent call last):
  File "C:/python.py/lei.py", line 14, in <module>
  print('修改前分数:',stu.__score)
  AttributeError: 'Student' object has no attribute '__score'
  从输出结果可以看出,已经无法从外部访问实例变量的属性_score了,作用就是确保外部代码不能随意修改对象内部的状态,通过访问限制的保护,代码更加安全.
  在python中,可以为类增加get_attrs方法,获取类中的私有变量,
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.__name = name
  
      self.__score = score
  
    def info(self):
  
      print('学生:%s; 分数:%s '%(self.__name,self.__score))
  
    def get_score(self):
  
      returnself.__score
  
stu = Student('duyuheng',95)
  
print('修改前分数:',stu.get_score())
  
stu.info()
  
print('修改后分数:',stu.get_score())
  
stu.info()
  C:\python\python.exe C:/python.py/lei.py
  修改前分数: 95
  学生:duyuheng; 分数:95
  修改后分数: 95
  学生:duyuheng; 分数:95
  由执行结果可以看到,通过get_score方法已经可以正确得到类内部的属性值.
  在python中,可可以为类增加set_attrs方法,修改类中的私有变量.
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.__name = name
  
      self.__score = score
  
    def info(self):
  
      print('学生:%s; 分数:%s '%(self.__name,self.__score))
  
    def get_score(self):
  
      returnself.__score
  
    def set_score(self,score):
  
      self.__score=score
  
stu = Student('duyuheng',95)
  
print('修改前分数:',stu.get_score())
  
stu.info()
  
stu.set_score(0)
  
print('修改后分数:',stu.get_score())
  
stu.info()
  C:\python\python.exe C:/python.py/lei.py
  修改前分数: 95
  学生:duyuheng; 分数:95
  修改后分数: 0
  学生:duyuheng; 分数:0
  由执行结果看到,通过set_score方法正确更改了私有变量score的值.
  在python中,通过自定义私有变量可对应的set方法可以做参数检查,避免传入无效的参数.
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.__name=name
  
      self.__score=score
  
    def info(self):
  
      print('学生:%s; 分数:%s '%(self.__name,self.__score))
  
    defget_score(self):
  
      return self.__score
  
    def set_score(self,score):
  
      if 0<=score<=100:
  
            self.__score=score
  
      else:
  
             print('请输入0到100的数字.')
  
stu =Student('duyuheng',95)
  
print('修改前的分数',stu.get_score())
  
stu.info()
  
stu.set_score(-10)
  
print('修改后的分数',stu.get_score())
  
stu.info()
  C:\python\python.exe C:/python.py/lei.py
  修改前的分数 95
  学生:duyuheng; 分数:95
  请输入0到100的数字.
  修改后的分数 95
  学生:duyuheng; 分数:95
  上例输出结果可以看到,调用set_score方法时,如果传入的参数不满足条件,就按照不满足条件的程序逻辑执行.
  类的私有方法也是由两个下划线开头,声明该方法为私有方法,且不能在类外使用.
  私有方法的调用方式如下:
  self.__private_methods
  私有方法的使用:
  例如:
class PrivatePublicMethod(object):  
    def __init__(self):
  
      pass
  
    def __foo(self):
  
      print('这是私有方法')
  
    def foo(self):
  
      print('这是公共方法')
  
      print('公共方法中调用私有方法')
  
      self.__foo()
  
      print('公共方法调用私有方法结束')
  
pri_pub = PrivatePublicMethod()
  
print('开始调用公共方法:')
  
pri_pub.foo()
  
print('开始调用私有方法:')
  
pri_pub.__foo()
  C:\python\python.exe C:/python.py/lei.py
  Traceback (most recent call last):
  File "C:/python.py/lei.py", line 21, in <module>
  pri_pub.__foo()
  AttributeError: 'PrivatePublicMethod' object has no attribute '__foo'
  开始调用公共方法:
  这是公共方法
  公共方法中调用私有方法
  这是私有方法
  公共方法调用私有方法结束
  开始调用私有方法:
  由输出结果可以看出,私有方法和私有变量类似,不能通过外部调用.
  继承
  面对对象编程带来的好处之一是代码重用,实现重用的方法之一是通过继承机制.继承完全可以理解成类之间类型和子类型的关系.

  在面向对象程序设计中,当我们定义一个class时,可以从某个现有的class继承,定义的新class称为子类(Subclass),而被继承的class称为基类,父类或超类(Base>  继承定义如下:
  clss DerivedClassName(BaseClassName):
  <statement-1>
  .
  .
  <statement-N>
  需要注意:继承语法class子类名(基类名)时,//基类名写在括号里,基本类是在定义类时,在元组中指明的.
  在python中,继承有以下特点:
  (1)在继承中,类级泵的构造方法(__init__()方法)不会被自动调用,需要在子类的构造方法中专门调用.
  (2)在调用基类的方法时需要加上基类的类名前缀,并带上self参数变量.区别于在类中调用普通函数时不需要带self参数.
  (3)在python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找
  例如:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
#上面定义了一个名为Animal的类,类中定义了一个run()方法直接输出(默认调用__init__()方法)
  
class Dog(Animal):
  
      pass
  
class Cat(Animal):
  
      pass
  
#上面代码对于Dog和Cat来说Animal就是它的父类;对于Animal来说Dog和Cat来说Animal就是它的子类.
  
dog = Dog()
  
dog.run()
  
cat = Cat()
  
cat.run()
  C:\python\python.exe C:/python.py/lei.py
  Animal is runing...
  Animal is runing...
  由输出结果看到,子类中没有定义任何方法,但是都执行了run()方法.
  继承的优点;
  继承最大的好处时子类获得了父类全部非私有的功能.
  子类也可以拥有自己的方法.
  例如:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
class Dog(Animal):
  
      def eat(self):
  
            print('Eating...')
  
dog = Dog()
  
dog.run()
  
dog.eat()
  C:\python\python.exe C:/python.py/lei.py
  Animal is runing...
  Eating...
  由上例可以看出,唉Dog中增加了eat方法,从输出结果可以看书既执行了父类的方法,又执行了自己定义的方法.
  若不想让子类继承父类中的私有方法,也不能调用父类的私有方法.父类定义如下.
  例如:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
    def __run(self):
  
      print('I am private method.')
  
class Dog(Animal):
  
      pass
  
dog=Dog()
  
dog.__run()
  C:\python\python.exe C:/python.py/lei.py
  Traceback (most recent call last):
  File "C:/python.py/lei.py", line 15, in <module>
  dog.__run()
  AttributeError: 'Dog' object has no attribute '__run'
  由执行结果可以看到,子类不能调用父类的私有方法,子类虽然继承了父类,但是调用父类的私有方法相当于从外部调用类中的方法,因而调用不成功.
  对于类中扩展的非私有方法,子类可以拿来即用,如在父类Animal中增加一个jump方法:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
    def jump(self):
  
      print('Animal is jumpping...')
  
    def __run(self):
  
      print('I am a private method.')
  
class Dog(Animal):
  
      pass
  
class Cat(Animal):
  
    pass
  
dog = Dog()
  
dog.run()
  
dog.jump()
  
cat =Cat()
  
cat.run()
  
cat.jump()
  C:\python\python.exe C:/python.py/lei.py
  Animal is runing...
  Animal is jumpping...
  Animal is runing...
  Animal is jumpping...
  由上例结果可以看出,子例可以立即获取父类增加的非私有方法.
  多态
  多台来自于希腊语,意思时有多种形式.多态意味着即使不知道变量所引用的对象类型是什么,也能对对象进行操作,多态会根据对象(或类)的不同而表现出不同的行为.
  例如:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
class Dog(Animal):
  
    def run(self):
  
      print('Dog is running...')
  
class Cat(Animal):
  
    def run(self):
  
      print('Cat in runing...')
  
dog = Dog()
  
print('实例化Dog类')
  
dog.run()
  
cat = Cat()
  
print('实例化Cat类')
  
cat.run()
  C:\python\python.exe C:/python.py/lei.py
  实例化Dog类
  Dog is running...
  实例化Cat类
  Cat in runing...
  在上例中我们在Animal类中定义了run方法,Dog和Cat类分别继承Animal类,并且分别定义了自己的run方法,最后Dog和Cat调用的是自己定义的run方法.
  当我们定义类时实际上就定义了一中数据类型.定意义数据类型和python自带的数据类型(如str、list、dict)没什么两样.
  例如:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
class Dog(Animal):
  
    def run(self):
  
      print('Dog is running...')
  
class Cat(Animal):
  
    def run(self):
  
      print('Cat in runing...')
  
a=list()
  
b=Animal()
  
c=Dog()
  
print('a是否为list类型:',isinstance(a,list))
  
print('b是否为Animal类型:',isinstance(b,Animal))
  
print('c是否为Animal类型:',isinstance(c,Dog))
  C:\python\python.exe C:/python.py/lei.py
  a是否为list类型: True
  b是否为Animal类型: True
  c是否为Animal类型: True
  输出结果可以看出:a,b,c确实分别为list,Animal,Dog三种类型
  在执行下列语句:
print('c是否为Dog类型:',isinstance(c,Dog))  
print('c是否为Animal类型:',isinstance(c,Dog))
  C:\python\python.exe C:/python.py/lei.py
  c是否为Dog类型: True
  c是否为Animal类型: True
  由执行结果可以看出,c既是Dog类型又是Animal类型,应为Dog是从Animal继承下来的,当我们创建Dog实例时,我们认为c的数据类型是Dog,但是c同时也是Animal,Dog本来就是Animal的一种.
  在继承关系中,如果一个实例的数据类型是某个子类,那么他的数据类型也可以看作时父类.但是反过来就不行了:
  在执行下列语句:
print('b是否为Dog类型:',isinstance(b,Dog))  C:\python\python.exe C:/python.py/lei.py
  b是否为Dog类型: False
  我们在看一个实例.编写一个函数,这个函数接受一个Animal类型的变量,定义并执行如下函数,执行时传入Animal的实例:
class Animal(object):  
    def run(self):
  
      print('Animal is runing...')
  
class Dog(Animal):
  
    def run(self):
  
      print('Dog is running...')
  
class Cat(Animal):
  
    def run(self):
  
      print('Cat in runing...')
  
def run_two_times(animal):
  
    animal.run()
  
    animal.run()
  
run_two_times(Animal())
  C:\python\python.exe C:/python.py/lei.py
  Animal is runing...
  Animal is runing...
  若执行函数时传入Dog的实例,如下:
run_two_times(Dog())  C:\python\python.exe C:/python.py/lei.py
  Dog is running...
  Dog is running...
  若执行函数时传入Cat的实例,如下:
run_two_times(Cat())  C:\python\python.exe C:/python.py/lei.py
  Cat in runing...
  Cat in runing...
  如果在定义一个Bird类型,也继承Animal类,定义如下:
class Bird(Animal):  
    def run(self):
  
      print('Bird is flying the sky ...')
  
run_two_times(Bird())
  C:\python\python.exe C:/python.py/lei.py
  Bird is flying the sky ...
  Bird is flying the sky
  由执行结果可以看出,新增的Animal子类不必对run_two_times()方法做任何修改.实际上,任何依赖Animal作为参数的函数或方法都可以不加修改地正常运行,原因就在于多态.
  多态的好处是:我们需要传入子类时,只需要接受父类型就可以了,因为子类都是父类型,按照父类型操作即可.由于父类型有run()方法,因此传入类型只要是父类或者是继承父类,都会自动调用实际类型的run()方法.
  多态的意思:对于一个变量,我们只需要知道它是父类型,无需确切的知道它的子类型,就可以放心调用run()方法,.具体调用的run()方法作用于父类或者子类,由运行时该对象的确切类型决定.
  多态真正的威力在于:调用方只管调用,不管细节.当我们新增一种Animal的子类时,只要确保run()方法编写正确即可,不用管原来的代码是如何调用的.这就是"开闭"原则:对于扩展开放,允许新增Animal子类;对于封闭,不需要修改依赖Animal类型的run_two_times()等函数.
  很多函数和运算符都是多态的,只要使用多态函数和运算符,多态就会消除.唯一能毁掉多态的是使用函数显示地检查类型,如type、isinstance函数等.如果有可能,就尽量避免使用这些毁掉多态的方式,重要的是如何让对象按照我们希望的方式工作,无论它是否是正确类型或类.
  封装
  封装是全局作用域中其他区域隐藏多余信息的原则.听起来像多态,使用对象而不用知道其他内部的细节.
  封装并不等同于多态.多态可以让用户不知道类(或对象类型)的对象进行方法调用,而封装可以不用关心对象是如何构建的,直接使用即可.
  例如:
class Student(object):  
    def __init__(self,name,score):
  
      self.name = name
  
      self.score = score
  
std = Student('duyuheng',90)
  
def info(std):
  
    print('学生:%s; 分数:%s;'%(std.name,std.score))
  
info(std)
  C:\python\python.exe C:/python.py/lei.py
  学生:duyuheng; 分数:90;
  上例是通过函数调用并得到结果.
  可以直接在Studnet类内部定义访问数据的函数,这样就把"数据"封装起来了.这些封装数据的函数数据和Student类本身是相关联的,我称之为方法.
  要定义一个方法,除了第一参数时self外,其他参数和普通函数一样.要调用一个方法,在实例变量上直接调用即可.除了self不用传递,其他参数正常传入.
class Student0(object):  
    def __init__(self,name,score):
  
      self.name = name
  
      self.score = score
  
stu = Student0('xuwei',99)
  
def info(self):
  
    print('学生:%s分数:%s'%(self.name,self.score))
  
info(stu)
  C:\python\python.exe C:/python.py/lei.py
  学生:xuwei分数:99
  由上例我们从外部看出Studnt类,只需要知道创建实例需要给出的name和score,如何输出是在Student类的内部定义的,这些数据和逻辑被"封装"起来,调用很容易,但却不知道内部实现的细节.
  封装的另一个好处时可以给student类增加新方法,比如访问权限中的get_score()方法和set_score()方法,使用这些方法时,无需知道内部的实现细节,直接调用即可.
  多重继承
  多重继承的定义如下:
  class DerivedclassName(Base1,Base2,Base3)
  <statement-1>
  .
  .
  <statement-N>
  多重继承就是使有多个基类(父类或超类).
  需要注意圆括号中父类的顺序,若父类中有相同的方法名,在子类使用时未指定,python会从左到右搜索.若方法在子类中未找到,则从左到右查找父类中是否包含方法.
  例如:
classA(object):  
    def __init__(self,a):
  
      print('init A...')
  
      self.a = a
  
class B(A):
  
    def __init__(self,a):
  
      super(B,self).__init__(a)
  
      print('init B...')
  
class C(A):
  
    def __init__(self,a):
  
      super(C,self).__init__(a)
  
      print('init C...')
  
class D(B,C):
  
    def __init__(self,a):
  
      super(D,self).__init__(a)
  
      print('init D...')
  
d =D('d')
  C:\python\python.exe C:/python.py/lei.py
  init A...
  init C...
  init B...
  init D...
  由上列可以看出,D同时继承自B和C,也就是D拥有了A、B、C的全部功能.多重继承通过super()调用__init__()方法时,A虽然被继承了两次但是__init__()只调用一次.
  多重继承的目的时从两种继承树中分别选择并继承出子类,以便组合功能使用.
  多重继承一个子类可以继承多个父类,同时获得多个父类所有非私有功能
  获取对象信息
  python提供了3种获取对象类型的方法.
  第1种使用type()函数
  将一个变量实现哦昂函数或类
print(type(abs))#函数  C:\python\python.exe C:/python.py/lei.py
  <class 'builtin_function_or_method'>
classA(object):#类  
    def __init__(self,a):
  
      pass
  
print(type( A(object)))
  C:\python\python.exe C:/python.py/lei.py
  <class '__main__.A'>
  由上面两例子可以看出,返回值对应的Class类型.
  如果要在if语句中判断并比较两个变量的type类型是否同,如下:
print(type(123)==type(456))  
print(type(123)==int)
  
print(type('abc')==type('123'))
  
print(type('abc')==str)
  
print(type('abc')==type(123))
  C:\python\python.exe C:/python.py/lei.py
  True
  True
  True
  True
  False
  由上例可以看出,判断基本数据类型可以直接写int、str.
  可以使用tyoes模块中定义的常量.
  例如:
importtypes  
def func():
  
    pass
  
print(type(abs)==types.BuiltinFunctionType)
  
print(type(lambda x:x)==types.LambdaType)
  
print(type((x for x in range(10)))==types.GeneratorType)
  C:\python\python.exe C:/python.py/lei.py
  True
  True
  True
  由上例可以看出,函数的判断方式需要借助types模块的帮助.
  第二种使用isinstance()函数
  要明确class的继承关系,使用type()很不方便,通过判断class的数据类型确定class的继承关系要方便的多,这个时候要使用isinstance()函数.
  例如:
class Animal(object):  
    def run(self):
  
      pass
  
class Dog(Animal):
  
    def run(self):
  
      pass
  
animal = Animal()
  
dog =Dog()
  
print(isinstance(dog,Dog))
  
print(isinstance(dog,Animal))
  
C:\python\python.exe C:/python.py/lei.py
  
True
  
True
  由上例可以得知:尽管dog式Dog类型,不过由于Dog是从Animal继承下来的,因此dog也是Animal类型.isinstance()判断的是一个对象是否为该类型的本身,或者是否为该类型继承的类型.
  不过animal不是Dog类型
print(isinstance(animal,Dog))  C:\python\python.exe C:/python.py/lei.py
  False
  需要知道的是:能用type()判断的基本类型也可以用isinstance()判断.
isinstance()可以判断一个变量是否为某些类型中的一种,判断变量是否为list或tuple的方式.  
print(isinstance(,(list,tuple)))
  
print(isinstance((1,2,3),(list,tuple)))
  C:\python\python.exe C:/python.py/lei.py
  True
  True
  第三种使用dir()
  如果要获得一个对象的所有属性和方法,就可以使用dir()函数.dir()函数返回一个字符串的list.
  例如:
print(dir('abc'))  C:\python\python.exe C:/python.py/lei.py
  ['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
  类的专有方法
  python类可以定义专有方法.专门方法是在特殊情况下或使用特别语法时由python调用的,而不像普通方法一样在代码中直接调用.
  看到型如__xxx__的变量或函数名就要注意,这在python中是有特殊用途的.
  这种特殊类型的函数定制类的方法由有以下几种.
  第一种__str__ 用法如下:
class Studnet(object):  
    def __init__(self,name):
  
      self.name= name
  
    def __str__(self):
  
      return '学生名称:%s'%self.name
  
print(Studnet('duyuheng'))
  C:\python\python.exe C:/python.py/lei.py
  学生名称:duyuheng
  这样的输出不但好看而且,还是我们想要的
  在看一下直接显示变量的内容:
class Studnet(object):  
    def __init__(self,name):
  
      self.name= name
  
s=Studnet('duyuheng')
  
print(s)
  C:\python\python.exe C:/python.py/lei.py
  <__main__.Studnet object at 0x00000000010CB4E0>
  上例输出结果为一堆字符串,这是因为直接显示变量调用的不是__str__(),而是__repr__(),两者的区别在于__str__()返回用户看到的字符串,而__repr__()返回程序开发者看到的字符.也就是说,__repr__()是说,__repr__()是为调试服务的.
  解决这个办法是在定义一个__repr__().通常,__str__()和__repr__()代码是一样的,所以有一个简单的写法如下:
class Student(object):  
    def __init__(self,name):
  
      self.name = name
  
    def __str__(self):
  
      return '学生名称:%s' % self.name
  
    __repr__=__str__
  
s = Student('duyuheng')
  
print(s)
  C:\python\python.exe C:/python.py/lei.py
  学生名称:duyuheng
  上例已经得到满意的结果
  第二种__iter__
  如果想将一个类用于for...in循环,类似list或tuple一样,就必须实现一个__iter__()方法.该方法返回一个迭代对象,python的for循环会不断调用该迭代对象的__next__()方法,获得循环的下一个值,直到遇到StopIteration错误时退出循环.
  以裴波那契(黄金分数列)为例,写一个可以作用于for循环的Fib类:
class Fib(object):  
    def __init__(self):
  
      #初始化两个计数器a、b
  
      self.a,self.b = 0,1
  
    def __iter__(self):
  
      #实例本身就是就是迭代对象,故返回自己
  
      return self
  
    def __next__(self):
  
      #计算下一个值
  
      self.a,self.b=self.b,self.a+self.b
  
      #退出循环条件
  
      if self.a > 100:
  
            raise StopAsyncIteration();
  
      #返回下一个值
  
      return self.a
  
for n in Fib():
  
    print(n)
  C:\python\python.exe C:/python.py/lei.py
  1
  1
  2
  3
  5
  8
  13
  21
  34
  55
  89
  第三种__getitem__
  要像list一样按照下标取出元素,需要实现__getitem__()方法.
  例如:
class Fib(object):  
    def __getitem__(self, n):
  
      a,b =1,1
  
      for x in range(n):
  
            a,b =b,a+b
  
      returna
  
fib = Fib()
  
print(fib)
  
print(fib)
  C:\python\python.exe C:/python.py/lei.py
  3
  89
  由执行结果看到,可以成功获取对应数列的值了.
  第四种__getattr__
  正常情况下,调用类的方法或属性时,如果类的方法或属性不存在就会报错,python提供了一种机制,就是写一个__getattr__()方法,动态返回一个属性.
class Student(object):  
    def __init__(self):
  
      self.name ='duyuheng'
  
    def __getattr__(self, attr):
  
      if attr=='score':
  
            return95
  
stu = Student()
  
print(stu.name)
  
print(stu.score)
  C:\python\python.exe C:/python.py/lei.py
  duyuheng
  95
  注意:只有在没有找到属性的情况下才会调用__getattr__,已有的属性(如name),不会在__getatter__中查找,此外,如果所有调用都会返回None(如stu.abc),就是定义的__getattr__默认返回None.
  第五种__call__
  一个对象实例可以有自己的属性和方法,调用实例的方法时使用instance.method()调用.
  任何类,只需要定义一个__call__()方法,就可以直接对实例进行调用.
  例如:
classStudent(object):  
    def __init__(self,name):
  
      self.name = name
  
    def __call__(self):
  
      print('名称:%s'%self.name)
  
stu=Student('duyuheng')
  
stu()
  C:\python\python.exe C:/python.py/lei.py
  名称:duyuheng
  由上例输出结果可以看到,直接对实例进行调用并得到结果.
  __call__()还可以定义参数.对实例进行直接调用就像对一个函数调用一样,完全可以把对象看成函数,把函数看成对象,因为这两者本身就有根本区别.
  如果把对象看成函数,函数本身就可以在运行期间动态创建出来,因为类的实例都是运行期间创建出来的,就模糊了对象和函数的界限.
  很时候判断一个对象是否能被调用,可以使用Callable()函数,比如函数上例定义的带有__call__()的类实例.
print(callable((Student('duyuheng'))))  
print(callable(max))
  
print(callable())
  
print(callable(None))
  
print(callable('a'))
  C:\python\python.exe C:/python.py/lei.py
  名称:duyuheng
  True
  True
  False
  False
  False
  由操作结果可以看到,通过callable()函数可以判断一个对象是否为"可调用"对象
页: [1]
查看完整版本: Python3.5修炼手册13-duyuheng