Python3 面向对象

1.面向对象

  把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。

  面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。

class Student(object):

    def __init__(self, name, score):
        self.name = name
        self.score = score

    def print_score(self):
        print('%s: %s' % (self.name, self.score))

  Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只作用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:创建一个类的实例,类的具体对象。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

2.类和实例

  必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。

class Student(object):
    def __init__(self, name, score):  #构造方法
        self.name = name
        self.score = score

    def get_grade(self):
        if self.score >= 90:
            return 'A'
        elif self.score >= 60:
            return 'B'
        else:
            return 'C'

bart = Student('Bart Simpson', 59)
print(bart.get_grade())

  class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。

  注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。

  创建实例的时候,必须传入与__init__方法匹配的参数。

  要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:

class Student(object):
    def __init__(self, name, score):  #构造方法
        self.__name = name
        self.__score = score

    def get_name(self):
        return self.__name

    def get_score(self):
        return self.__score

    def set_score(self, score):
        if 0 <= score <= 100:
            self.__score = score
        else:
            raise ValueError('bad score')

bart = Student('Bart Simpson', 59)

bart.set_score(100)

print(bart.get_score(),bart.get_name())

bart._Student__name  ###这样可以从外部访问了,但是不建议。

  内部属性不被外部访问,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。

  这样代码更健壮,可以对参数做检查,避免传入无效的参数

  在Python中,变量名类似__xxx__的,就是以双下划线开头,并且以双下划线结尾,是特殊变量,特殊变量可以直接访问,不是private变量,不能用__name____score__这样的变量名。  

  以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,把它当成私有变量。

  __private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。

类的专有方法:可以对类的专有方法进行重载(用到具体的搜索吧)

  • __init__ : 构造函数,在生成对象时调用
  • __del__ : 析构函数,释放对象时使用
  • __repr__ : 打印,转换
  • __setitem__ : 按照索引赋值
  • __getitem__: 按照索引获取值
  • __len__: 获得长度
  • __cmp__: 比较运算
  • __call__: 函数调用
  • __add__: 加运算
  • __sub__: 减运算
  • __mul__: 乘运算
  • __truediv__: 除运算
  • __mod__: 求余运算
  • __pow__: 乘方

3.继承和多态

  OOP程序设计中,我们定义class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。

  子类获得了父类的全部功能,但当子类和父类有相同的方法时,子类覆盖了父类的该方法,先调用子类的相同方法。

  super() 函数是用于调用父类(超类)的一个方法super(dog, self).__init()__(name)

  基类可以定义在别的模块中,class DerivedClassName(modname.BaseClassName):         但是要导入该模块import。

  Python同样有限的支持多继承形式。需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,方法在子类中未找到时,从左到右查找父类中是否包含方法。

class DerivedClassName(Base1, Base2, Base3):
    <statement-1>
    .
    .
    .
    <statement-N>

 继承示例代码:

class Animal(object):
    def __init__(self):
        a = "animal"

    def run(self):
        print('Animal is running...')

class Dog(Animal):
    def run(self):
        print('Dog is running...')

    def eat(self):
        print('Eating meat...')

dog = Dog()
print(isinstance(dog, Dog))

  Python中多态是指一类事物有多种形态。比如动物有多种形态,人,狗,猫,等等。文件有多种形态:文本文件,可执行文件。

  多态性:

  为什么要用多态性?

  ①增加了程序的灵活性

  以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

  ②增加了程序额可扩展性

  通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用

import abc


class Animals(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def talk(self):
        pass


class People(Animals):
    def talk(self):
        print('People is talking')


class Cat(Animals):
    def talk(self):
        print('Cat is miaomiao')


class Dog(Animals):
    def talk(self):
        print('Dog is wangwang')


cat1 = Cat()
dog1 = Dog()
peo1 = People()
# peo、dog、pig都是动物,只要是动物肯定有talk方法
# 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo1.talk()
dog1.talk()
peo1.talk()


# 定义一个统一的接口来访问
def func(obj):
    obj.talk()


func(cat1)

   动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。

 4.获取对象信息

  判断对象类型,使用type()函数。如果要判断一个对象是否是函数等,可以使用types模块中定义的常量。

    isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。

  获得一个对象的所有属性和方法,可以使用dir()函数。

  通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。

  配合getattr()setattr()以及hasattr(),我们可以直接操作一个对象的状态。参考菜鸟python3 内置函数。

 5. 实例属性和类属性

  直接在class中定义属性,这种属性是类属性,归类所有。类的所有实例都可以访问到。相同名称的实例属性将屏蔽掉类属性。

  访问类的变量是通过“类名.变量名”进行访问,而不是“self.变量名”进行访问。“self.变量名”访问的是实例对象的自身变量。

  下面例子中实例的变量被重新绑定,

class ff:
    a = 5

    def aaa(self):
        print(ff.a)   #如果写成self.a,a1.a变量被重新绑定,a1.aaa()的值就是10. 就取不到类的变量。

a1 = ff()
a1.aaa()
a2 = ff()
a2.aaa()
a1.a = 10
print(a1.a)
print(a2.a)
ff.a = 100
print(a1.a)
print(a2.a)
a1.aaa()
a2.aaa()


result:
5
5
10
5
10
100
100
100

6.使用__slots__

   可以给一个实例绑定方法和属性,但对别的实例是不起作用的。

   只允许对Student实例添加nameage属性。

class Student(object):
    __slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称

s = Student()
s.name = "sss"
s.score = 99

  使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

  在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

7.使用@property

读,写,删除的例子。三种操作对应了一个名字。

class People(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        # 私有属性
        self.__number = 0
    # 获取私有属性值  number = p1.number 会执行这个函数
    @property
    def number(self):
        # 返回私有属性值
        return self.__number
    # 设置私有属性值  p1.number = 666
    @number.setter
    def number(self, value):
        # 设置__number的值
        self.__number = value
 
    # 删除私有属性  del p1.number 会执行这个函数
    @number.deleter
    def number(self):
        # 删除属性
        del self.__number
p1 = People('张三', 22)
# 正常的对象属性赋值
# 对象.属性名 = 属性值
p1.name = '李四'
# 获取对象的属性值
name = p1.name
# 删除对象的属性
del p1.name
# 私有属性升级版
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
num = p1.number
print(num)
# 会去执行@number.setter装饰的number函数,在函数中设置__number属性的值
p1.number = 666
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
print(p1.number)
# 会去执行@number.deleter装饰的number函数,在函数中会将__number属性删除
del p1.number
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
print(p1.number)

  birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。

class Student(object):

    @property
    def birth(self):
        return self._birth

    @birth.setter
    def birth(self, value):
        self._birth = value

    @property
    def age(self):
        return 2015 - self._birth

s = Student()
s.birth = 5
print(s.birth)

8.多重继承

  在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。 

class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
    pass

9.检查对象的特性

  hasattr() 函数用于判断对象是否包含对应的属性。语法:hasattr(object, name)

  getattr() 函数用于返回一个对象属性值。语法:getattr(object, name[, default])  default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。

c = ff()
print(hasattr(c, 'age')) #检查实例属性是否拥有
print(hasattr(c, 'study')) #检查实例方法是否拥有
print(callable(getattr(c, 'study',None))) #检查实例方法study能否被调用
是否拥有
原文地址:https://www.cnblogs.com/yunlong-study/p/12613627.html