1. 类
和C++、java一样,python是一个面向对象语言。
类和对象的概念,如果你原本就是学编程的,那1.1章节就可以跳过,主要是介绍类和对象的相关的一些概念。
1.1 类的简介
类:一组具有相同属性和行为的对象的抽象一组具有相同属性和行为的对象的抽象。
对象 : 客观事件中,一切事物皆对象,对象是构成系统的基本单位,举一堆的例子: 一个学生、一头大象、一条鱼、一只蚂蚁,这些事实一个具体的对象,他们都属于动物这个类。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
局部变量:定义在方法中的变量,只作用于当前实例的类。
方法:类中定义的函数。
实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
1.2 类的定义
我们从简单到复杂的来定义一个类。
示例:
class Animal():
'''
定义一个动物类
'''
animal = Animal()
解释:
定义一个动物类,没有任何成员变量和成员方法。
class关键词用于定义类,后面接类的名字
备注 : 类的名字用单词定义,每个单词的首字母大写。
animal = Animal() :示例话一个具体的Animal对象(相当于一个活生生的动物,可以跑,可以跳)。
1.3 类的方法
方法即函数,在之前,我们的函数都是定义在外部的,可以直接被调用,而类的方法,则只能被类或者类的实例化对象调用。
类的方法和普通的函数定义是一样的,通过关键字def定义,但是函数第第一个参数一定self。
例如
class Animal():
'''
定义一个动物类
'''
def action(self):
'''
动作
:return:
'''
print('我是Aminal, 我会走路')
animal = Animal()
animal.action()
结果:
解释:
Animal类定义action方法,通过实例化animal可以调用action函数
类的方法属性:累的属性分为特殊方法、公共方法、保护方法、似有方法
特殊方法:__foo__,一般是系统定义名字 ,类似 __init__() 之类的。
保护方法:_foo,以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
私有法:__foo:,双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。
公共方法:如上面示例,知己def定义,没有上面的那些下划线,可以被对象直接调用。
1.3.1 私有方法
定义如上,这里主要给出示例来加深理解。
class Animal():
'''
定义一个动物类
'''
def action(self):
'''
动作
:return:
'''
print('我是Aminal, 我会走路')
def animal_func(self):
'''
animal 成员变量、成员方法调用测试
:return:
'''
self.__private_animal_func()
def __private_animal_func(self):
'''
私有化函数
:return:
'''
print('__private_animal_func 是一个私有化函数,只能在类内部调用')
animal = Animal()
animal.animal_func()
animal.__private_animal_func()
结果:
解释:
结果1是animal.animal_func()的执行结果,animal_func是animal类的成员方法,能够调用animal类的所有private函数。
结果2是animal.__private_animal_func()的执行结果,提示不能被调用,示例化对象没有不能直接调用private函数。
1.3.2 __init__函数
__init__函数为实例化对象的时候的初始化函数,无需要手动调用,在实例化对象的时候自动调用该函数。
另外,如果在实例化对象的时候,需要传递初始值,可是在__init__函数中定义。
例如:
class Animal():
'''
定义一个动物类
'''
def __init__(self, weight):
'''
Animal初始化函数
:param weight:
'''
self.weight = weight
print('我是一个Animal,我的体重是:{}'.format(self.weight))
animal = Animal(weight=10)
结果:
我是一个Animal,我的体重是:10
解释:
animal = Animal(weight=10)在实例化Animal对象的时候,Animal的__init__初始化函数就自动调用了(类似C++的构造函数)。
1.3.3 __del__函数
析构函数,在实例化对象被销毁的时候触发,无需手动调用,主要用于做变量的销毁等操作。
1.4 类的成员变量
和全局变量相似,成员函数在类或者类的实例化对象生存周期内有效。
成员变量和成员方法方法一样,区分公共变量、保护变量和似有变量,有效访问是一样的,这里就不做举例了,只给出一个简单的示例了。
如上__init__函数所示,成员变量一般都是定义在__init__函数中,并进行变量的初始化,每个变量通过self.var来定义,可以在成员函数中使用和被实例化对象使用。
例如:
animal = Animal(weight=10)
print('main函数中animal.weight = {}'.format(animal.weight))
结果:
main函数中animal.weight = 10
1.5 类继承
你所看到的那些蹦蹦跳跳的都可以统称为动物,但是,我们在日常的沟通中总不能每次都用动物这个统称来沟通吧,比如狗、猫、鸟、鱼,可以在动物下面更加细化(所谓细化的这个过程,即使继承)。
如上图,狗、猫、鸟、鱼都继承自Animal(动物),下面市县一个狗和鸟的类。
class Animal():
'''
定义一个动物类
'''
def __init__(self, weight):
'''
Animal初始化函数
:param weight:
'''
self.weight = weight
print('我是一个Animal,我的体重是:{}'.format(self.weight))
def action(self):
'''
动作
:return:
'''
print('我是Aminal, 我会走路')
class Dog(Animal):
'''
定义一个类(狗)(继承自动物类Animal)
'''
def __init__(self, weight):
'''
Dog类初始化函数
:param weight:
'''
Animal.__init__(self, weight)
animal = Animal(weight=10)
animal.action()
print('\n')
dog = Dog(weight=20)
dog.action()
结果:
我是一个Animal,我的体重是:10
我是Aminal, 我会走路
我是一个Animal,我的体重是:20
我是Aminal, 我会走路
解释:
class Dog(Animal): ()括号内填入父类的类名,表示继承自该类,例如Dog,则继承自Animal类,继承的内容包括Animal的所有成员变量和成员方法。
animal = Animal(weight=10)
animal.action()
这两行代码实例化一个Animal对象,并调用action函数,则输出
我是一个Animal,我的体重是:10
我是Aminal, 我会走路
dog = Dog(weight=20)
dog.action()
这两行代码,在Dog中并没有定义成员变量self.weight和action方法,但是依旧能够调动成功,就是因为继承了Animal类的self.weight变量和action方法(简单的理解就是,把Animal类中的self.weight变量和action方法的代码直接copy下来是一样的)。
1.5.1 方法重写
子类继承父类的同时,也继承了父类的所有方法,即使子类没有定义该方法,也能调用该方法,但是,执行的代码逻辑是父类实现的方法的逻辑。
如果子类对于这个方法的需求或者逻辑是不一样的,例如Animal中aciton方法表示的走路,但是对bird来说,他的action是飞,所有他们对action的方法是不一致的,这是就需要重新来实现bird的action方法的代码逻辑。
例如:
class Animal():
'''
定义一个动物类
'''
......
class Bird(Animal):
'''
定义一个类(鸟)(继承自动物类Animal)
'''
def __init__(self, weight):
'''
Bird类初始化函数
:param weight:
'''
Animal.__init__(self, weight)
def action(self):
'''
动作
:return:
'''
print('我是Bird, 我会飞')
animal = Animal(weight=10)
animal.action()
print('')
bird = Bird(weight=30)
bird.action()
结果:
我是一个Animal,我的体重是:10
我是Aminal, 我会走路
我是一个Animal,我的体重是:30
我是Bird, 我会飞
解释:
def action(self):
'''
动作
:return:
'''
print('我是Bird, 我会飞')
Bird类的aciton方法中,重新实现了对action方法的逻辑,因此,调用Bird类实例化对象的action方法时,就会执行这个实现的action方法,而不会去执行Animal类的action方法了。
备注:方法重写的时候,名字不可以修改,如果修改了,就是子类的自定义方法了,方法的参数可以根据需求修改或者不修改。
1.5.2 子类的自定义成员方法和变量
如上章节,子类可以重写action方法,当Bird中定义action1的时候,就变成了Bird类独有的函数的,Bird类的实例化对象能够调用action1方法,而Animal的实例化对象则没有action1方法,自定义独有变量亦是如此。
例如:
class Animal():
'''
定义一个动物类
'''
......
class Bird(Animal):
'''
定义一个类(鸟)(继承自动物类Animal)
'''
def __init__(self, weight):
'''
Bird类初始化函数
:param weight:
'''
Animal.__init__(self, weight)
self. flight_speed = 50
......
def action1(self):
'''
动作
:return:
'''
print('我是Bird, 我还有一个动作是俯冲,速度为每分钟{}'.format(self.flight_speed))
animal = Animal(weight=10)
animal.action()
print('')
bird = Bird(weight=30)
bird.action()
bird.action1()
结果:
我是一个Animal,我的体重是:10
我是Aminal, 我会走路
我是一个Animal,我的体重是:30
我是Bird, 我会飞
我是Bird, 我还有一个动作是俯冲,速度为每分钟
解释:
Bird类__init__初始化函数中的self. flight_speed = 50成员和action1方法则为Bird自定义的变量和方法,只能被Bird的实例化对象调用。
bird = Bird(weight=30)
bird.action()
bird.action1()
所有上面三行代码能够调用成功。
如果为下面的代码:
animal = Animal(weight=10)
animal.action1()
则会报错,提示没有Animal没有action1方法。
1.6 置类属性
__dict__ : 类的属性(包含一个字典,由类的数据属性组成)
__doc__ :类的文档字符串
__name__: 类名
__module__: 类定义所在的模块(类的全名是'__main__.className',如果类位于一个导入模块mymod中,那么className.__module__ 等于 mymod)
__bases__ : 类的所有父类构成元素(包含了一个由所有父类组成的元组)
参考代码 :
https://github.com/minlixia/python (advanced/03_class.py)