【Python学习手册】类与对象详解(值得收藏的学习手册)

python专栏:【全网最强】Python系统学习手册

目录

python专栏:【全网最强】Python系统学习手册

一、类与对象

1.面向对象

2.动态类型语句

3.类的定义

4.类的成员

成员变量

成员方法

成员的动态性

5.构造方法

6.实例方法

7.动态增删改

8.类的继承

二、方法

1.类方法与静态方法

2.函数装饰器

3.一般的函数装饰器

三、成员变量

四、隐藏和封装

封装的目的

良好的封装需要从两个方面考虑:

使用property定义属性

五、类的继承

重写父类方法

调用被重写的方法

使用super函数

六、多态

类型检查函数

七、枚举类

枚举类的派生类


一、类与对象

用于描述复杂的对象,包含很多属性和方法。

Class:某一些有共同特征的对象的抽象,是某种概念。

对象(Object:也称为实例(instance),是具体存在的实体,每个实体具备一定的特征。对象之间有相同点也有不同点。

1.面向对象

  • 面向对象(Object-Oriented Programming)是一种编程范式,是模块化设计的重要方法。
  • 世界由各种对象组成,不同对象之间可以相互作用和通讯。
  • 描述对象特征的信息称为属性(Attribute
  • 存取属性的函数称为方法(Method
  • 具有相同属性与方法的对象(Object),属于同一个类别,称之为一个类(Class,其中的一个对象为该类的实例(Instance

2.动态类型语句

  • python是动态类型语言,不止属性值可以变化,对象的所属类别、方法都可以变化。
  • 一个对象可以动态转换为不同的类,具有不同的属性和方法。属性和方法可以动态的添加和删除,具备高度的灵活性

3.类的定义

  •   class 类名(基类):

              零到多个成员变量...

              零到多个执行语句...

              零到多个成员方法...

  • 类名只要是合法的标识符即可,合法的变量名可以作为类名。推荐使用大写字母开头,下划线分隔的一系列有意义的单词作为类名。
  • 注意冒号和缩进的规范
  • 类定义用class关键字,函数定义用def关键字,类中的方法(成员函数)也用def定义。
  • 类中的成员变量和方法的顺序没有影响,各个成员之间可以相互调用。

4.类的成员

成员变量

  • 类变量:属于类本身,用于定义该类整体的状态数据。
  • 实例变量:属于该类的某一个对象,用于定义某个对象所包含的状态数据。

成员方法

  • 类方法:用于定义一个类的整体行为,不随对象变化,不绑定具体对象。
  • 实例方法:用于定义该类的某个对象的行为或功能,只对具体对象。在类中定义的方法默认为实例方法。

成员的动态性

  • 类变量可以在任何地方增、删、改:在类中为新变量赋值,可以自动增加类变量。用del删除类变量。
  • 对实例变量也类似,也可以在任何地方动态增、删、改。对不存在的赋值就是动态增加,对已有的变量del就是动态删除。

5.构造方法

  • 定义了一个类,构造方法就是从类定义出发,生成一个实例。构造方法返回该类的对象。
  • python的构造方法有特殊的名字:__init__,必须用这个名字不能随便换!注意init前后都是连续的双下划线。
  • 构造方法的第一的参数是self,表示被构造的实例对象。一般会在构造方法中为self.varname赋值,将对象装配好。
  • 构造方法结束时不需要使用return,它会自动将装配好的对象也就是self当作返回值。
  • python规定,每一个类,必须有一个构造方法。如果你没有定义,python会自动生成一个只有参数self的空的构造方法。

6.实例方法

  • 在类中定义的方法,python会自动为它们绑定第一个参数,一般这个参数约定俗成的命名为self。这个参数总是指向调用该方法的对象。
  • 由于实例方法的第一个参数self自动绑定,传参的时候不需要传它。self指向的对象是不确定的,但对象的类型是确定的。
  • python的类和对象,类似于c++的命名空间,因此在调用类和对象的方法时,一定要使用类.和对象.的形式。
  • 对象.方法(参数)调用实例方法,用类.方法(参数)的方式调用类方法。
  • 也可以用类.方法(对象,参数)的方式对某一个实例调用方法。这种方式称为未绑定方法,用户需要指定一个实例对象。
# 第一个面向对象程序,定义人类:一个关于人的类
class Person:
    ''' 定义一个人 '''
    def __init__(self,name,age=0):
        ''' 构造方法,定义与生俱来的两个属性,姓名和年龄 '''
        self.name = name
        self.age = age
    def birthday(self):
        ''' 定义实例方法,过生日 ''' # 定义一个实例方法
        self.age += 1
        print('%s%d岁啦,生日快乐!!!' % (self.name, self.age))
    def open_mouth(self):
        ''' 张嘴 '''
        print('%s张嘴。' % self.name)
    def chew(self):
        ''' 咀嚼 '''
        print('%s嚼一嚼。' % self.name)
    def eat(self):
        ''' 吃饭 ''' # 定义一个实例方法,依赖其他方法
        self.open_mouth() # 在类定义中调用其它的方法,使用self.xxx的方式
        self.chew()
        
        
a = Person('张三') # 使用构造方法,由于第一个self参数自动绑定,只需传入后面的参数

a.name
a.age
a.birthday() # 调用过生日方法,第一个参数自动绑定,不需要传参了
a.birthday()
a.age
a.eat()
# python中,也可以用 类.方法(对象) 的方式来调用方法,就是看着啰嗦
Person.chew(a)

7.动态增删改

# 实例变量的动态增删改
# 增
a.nickname = '小明'
print(a.nickname)
# 改
a.nickname = '小麻'
print(a.nickname)
# 删
# del a.nickname
print(a.nickname) # 删除之后,这个成员变量不存在了,会报错

# 类变量的动态增删改
# 增
Person.charactor = '勇敢'
print(Person.charactor)
print(a.charactor) # 每个实例都能够调用类变量
# 改
Person.charactor = '智慧'
print(Person.charactor)
print(a.charactor) 
# 删
# del Person.charactor
print(Person.charactor)

8.类的继承

  • 和其它面向对象语言一样,python也支持类的继承。
  • 继承就是:从另一个类中全盘拷贝变量和方法,实现代码复用。被继承的类称为基类,继承者叫派生类。
  • 派生类可以在基类的基础上增加自己的变量和方法,基类已经有的不需要再写一遍。对派生类的操作不会影响到基类。
  • 继承操作只需要在class 类名后面添加(基类)即可。
class Student(Person):
    ''' 定义类:学生,继承 “人”这个类别 '''
    def __init__(self,name,age=0,school='北师大'):
        ''' 初始化一个“学生” '''
        Person.__init__(self,name,age) # 先使用基类的初始化方法
        self.school = school   # 在此基础上添加
    def gotoschool(self): # 新增一个成员方法
        ''' 上学函数 '''
        print('%s去%s上学啦!' % (self.name, self.school))
b = Student('韩梅梅')
b.gotoschool()

二、方法

1.类方法与静态方法

  • python支持定义类方法和静态方法,定义的方式就是使用函数装饰器。
  • 使用@classmethod修饰的是类方法自动绑定类方法的第一个参数cls
  • 使用@staticmethod修饰的是静态方法。静态方法不会自动绑定参数
  • 类方法可以访问类变量,一般用它来对类变量进行增删改。由于python的动态性,这些事情在哪儿都能做,但集中到类方法里面做更方便管理。
  • 静态方法其实单独定义的函数没有区别。只有名字和当前类有关。

2.函数装饰器

  • python的语法中,@符号作为函数装饰器使用,它的作用是引用已有的函数,修饰其它的函数。
  • 所谓函数装饰器,相当于给函数“穿马甲”,添加或者改变原有函数的功能。
  • python的函数装饰器语法使它能简便优美的实现很多功能,比如类方法,静态方法,以及即时编译(jit)
class Mosquito:
    '''
    蚊子类。目前我们只关心蚊子的行为,不关心具体的蚊子,所以没有构造方法。这个类不会产生实例对象。
    '''
    # 使用@classmethod修饰类方法,自动绑定第一个参数,也就是当前类cls
    @classmethod
    def fly(cls):
        '''
        飞行方法,蚊子都会飞。
        '''
        print('这个类是会飞的: ', cls)

    # 使用@staticmethod修饰静态方法
    @staticmethod
    def sting(p):
        '''
        叮咬方法,我们关心谁被蚊子叮了,并不关心叮人的具体是哪只蚊子。这个方法的参数是人类对象。
        '''
        print(p.name + '被蚊子叮了。')
Mosquito.sting(a)
Mosquito.fly()

3.一般的函数装饰器

  • 一般的函数装饰器,可以理解为函数套函数。在函数func()的前面加上@gfunc,则产生的函数实际上是gfunc(func())
  • gfunc()必须是一个以函数为参数的函数。
  • func()是被装饰得函数,装饰前后,函数的参数不发生变化,返回值可能发生变化,也可能不变。
  • 装饰后函数的返回值,事实上就是gfunc()的返回值。
  • 函数装饰器作用:用来对一个函数进行包装,在其前后加入通用的辅助功能:

           1)在前面,加上权限检查,数据合理性与一致性检查,等必要的前处理。

           2)在后面,加上记录日志,保存结果,统计绘图,等必要的后处理。

           3)适用于前后处理可以通用,中间的函数算法可以灵活替换的场景。

           4)可以使用*args代替不定个数的参数,增加装饰器的通用性。

def pre_post(func):
    '''
    用装饰器实现通用的前后处理    '''
    def pre_post_f(*args):
        '''
        实际进行前后处理操作的函数        '''
        # 用一句话代替前后处理过程
        print('前处理......')
        f = func(*args)
        print('后处理......')
        # 内层函数的返回值为func的返回值
        return f
    # 外层函数,把包装好的内层函数作为返回值
    return pre_post_f 

# 用通用前后处理函数来包装一个求平均值的函数
@pre_post
def mymean(x):
    return sum(x)/len(x)
# 运行mymean函数,实际上运行的是含有前后处理的,用 pre_post包装好了的函数
x = list(range(10))
print(mymean(x))

三、成员变量

  • python类的成员变量分为类变量实例变量,可以动态增删改。
  • 变量和实例变量有不同的用途、定义方式、使用方式。
  • 类变量在类的命名空间内定义
  • 实例变量在构造方法内定义
  • 类变量可以通过类名.变量实例名.变量两种方式访问
  • 实例变量只能通过实例名.变量访问和修改
# 中国城市信息列表
class City:
    # 定义类变量
    country = 'China' # 中国城市
    num_of_cities = 0  # 城市总数
    def __init__(self, name, lon, lat, postcode):
        self.name = name
        self.lon = lon
        self.lat = lat
        self.postcode = postcode
        City.num_of_cities += 1
    def print_city(self):
        # 使用类变量一定要带上类名,下面这句话会报错
        # print('Country: %s' % contry)
        # 下面这些是正确的
        print('Country: %s' % City.country)
        print('Total number of cities: %d' % City.num_of_cities)
        print('City name: %s' % self.name)
        print('Longitude: %7.3f' % self.lon)
        print('Latitude: %7.3f' % self.lat)
        print('Post code: %d' % self.postcode)
  • 通过实例BJ修改类变量country,然后再从类中访问,发现变量并没有被修改。
  • 由于python语言的动态性,用赋值=修改变量的时候,事实上并没有修改类变量country,而是在实例BJ里面新建了一个实例变量,也叫country
  • 因此,修改类变量最好是通过类来修改。通过实例只能读不要增删改!
BJ = City('北京',116.408,39.904,100000)
BJ.print_city()
SH = City('上海',121.445,31.213,200000)
SH.print_city()
GZ = City('广州',113.265,23.108,510000)
GZ.print_city()
# 访问类变量
# 通过类访问
print(City.country)
# 通过类修改
City.country = '中国'
print(City.country)
# 通过实例访问
print(BJ.country)
# 通过实例修改
BJ.country = 'BJ中国' # 通过实例BJ修改
# 从类中访问,发现类变量没有被改过!
print(City.country)
# 从实例BJ中访问,发现被改了
print(BJ.country)
# 从其它实例中访问,发现还是没有被修改
print(SH.country)
# 通过dir发现BJ中新建了一个实例变量,也叫country!
dir(BJ)

四、隐藏和封装

面向对象的三大特征封装Encapsulation)、继承和多态

封装指的是将对象的状态信息隐藏在内部,不允许外部直接访问。通过该类提供的方法,完成数据完整性、一致性、权限检查等操作后才允许访问和修改。

双下划线__开头的是隐藏变量和方法。

类变量、类方法、实例变量、实例方法,都是可以隐藏的。也可以通过“作弊”的方式访问到隐藏变量和方法。但是非常不推荐这样做!

封装的目的

  • 隐藏类的实现细节。限制不合理的访问和修改。
  • 通过数据检查保证对象信息的完整性。
  • 便于集中修改,提高代码的可维护性。

良好的封装需要从两个方面考虑:

  • 该藏的藏起来:隐藏对象的属性和实现细节,不允许外部直接访问
  • 该露的露出来:编写相应的方法操作这些隐藏属性,通过在方法中的各种检查来保证访问和操作的安全
# 中国城市信息列表,使用封装来增加安全性
class City:
    # 定义类变量,所有的类变量都是隐藏变量
    # 中国城市
    __country = 'China'
    # 城市总数
    __num_of_cities = 0    
    def __num_plusone():
        '''   隐藏方法,让城市的总数加一。  '''
        City.__num_of_cities += 1    
    def __init__(self, name, lon, lat, postcode):
        ''' 构造方法,所有的实例变量都是隐藏变量。 '''
        self.__name = name
        self.__lon = lon
        self.__lat = lat
        self.__postcode = postcode
        City.__num_plusone()        

    def print_city(self):
        '''  把实例对象和类的信息打印出来。 '''
        print('Country: %s' % City.__country)
        print('Total number of cities: %d' % City.__num_of_cities)
        print('City name: %s' % self.__name)
        print('Longitude: %7.3f' % self.__lon)
        print('Latitude: %7.3f' % self.__lat)
        print('Post code: %d' % self.__postcode)    
    # 读取类和对象的属性
    def get_name(self):
        return self.__name
    def get_lat(self):
        return self.__lat
    def get_lon(self):
        return self.__lon
    def get_coordinate(self):
        return self.__lat, self.__lon
    def get_postcode(self):
        return self.__postcode
    def get_country():
        return City.__country
    def get_num_of_cities():
        return City.num_of_cities
    # 没有写入方法,对象一旦创建就不能修改,类的属性只能通过内部的方法修改

看起来python的隐藏方法是有效的。然而,事实上python并没有真正的隐藏机制,它只是把被隐藏的变量给改了名字。

_类名__变量或方法名的方式,可以访问到被隐藏的东西。但是平时不建议这样做。

# 创建一些对象
BJ = City('北京',116.408,39.904,100000)
BJ.print_city()

SH = City('上海',121.445,31.213,200000)
SH.print_city()

GZ = City('广州',113.265,23.108,510000)
GZ.print_city()
# 直接访问实例变量和类变量,会报错,隐藏变量从类定义的外部,既不能读也不能写
#print(City.country)
print(BJ.__name)
# 通过get方法间接访问类变量和实例变量
print(City.get_country())
print(BJ.get_name())
# 作弊式访问隐藏变量
print(BJ._City__name)
# 作弊式修改隐藏变量
BJ._City__name = 'Beijing'
print(BJ._City__name)

使用property定义属性

  • 使用双下划线隐藏变量和方法,实现封装,然后通过一系列getset方法实现。
  • 可以通过property()函数,把几个变量攒起来,变成虚拟属性。

property()函数的语法格式如下:

        property(fget = None, fset = None, fdel = None, doc = None)

  • property()函数可以传入四个参数,分别代表读方法(fget)、写方法(fset)、删除方法(fdel)和文档字符串(doc
  • 传入1个参数,表示只读(只有fget
  • 传入2个参数,表示读写(有fgetfset
  • 传入3个参数,表示读写删
  • 传入4个参数,表示读、写、删、文档齐全
# 中国城市信息列表,使用property定义属性
class City:
    # 定义类变量,所有的类变量都是隐藏变量
    # 中国城市
    __country = 'China'
    # 城市总数
    __num_of_cities = 0    
    def __num_plusone():
        '''   隐藏方法,让城市的总数加一。    '''
        City.__num_of_cities += 1    
    def __init__(self, name, lon, lat, postcode):
        '''  构造方法,所有的实例变量都是隐藏变量。     '''
        self.__name = name
        self.__lon = lon
        self.__lat = lat
        self.__postcode = postcode
        City.__num_plusone()

       def print_city(self):
        '''    把实例对象和类的信息打印出来。   '''
        print('Country: %s' % City.__country)
        print('Total number of cities: %d' % City.__num_of_cities)
        print('City name: %s' % self.__name)
        print('Longitude: %7.3f' % self.__lon)
        print('Latitude: %7.3f' % self.__lat)
        print('Post code: %d' % self.__postcode)    
    # 读取类和对象的属性
    def get_name(self):
        return self.__name
    def get_lat(self):
        return self.__lat
    def get_lon(self):
        return self.__lon
    def get_coordinate(self):
        return self.__lat, self.__lon
    def get_postcode(self):
        return self.__postcode
    def get_country():
        return City.__country
    def get_num_of_cities():
        return City.num_of_cities    


     # 写入对象的属性(类的属性不能直接写)
    def set_name(self, name):
        self.__name = name
    def set_lat(self, lat):
        self.__lat = lat
    def set_lon(self, lon):
        self.__lon = lon
    def set_coordinate(self, coordinate):
        self.__lat, self.__lon = coordinate
    def set_postcode(self, postcode):
        self.__postcode = postcode
    
    # 定义coordinate属性的删除操作
    def del_coordinate(self):
        self.__lat, self.__lon = 0, 0
        
    # 用property定义属性
    coordinate = property(get_coordinate, set_coordinate, del_coordinate, \
                         '城市的经纬度坐标,北纬在前,东经在后,南和西方向为负值')

  • property所定义的属性,并不是类定义中真实存在的类或实例变量,而是用已有变量合成出来的。
  • 这种属性被称为计算属性,它并不真正的存储什么东西,而是通过类和对象的状态计算出来的。
  • 对计算属性赋值,python会自动使用set方法更新相应的类或对象内部变量。
# 创建一些对象
BJ = City('北京',116.408,39.904,100000)
BJ.print_city()

SH = City('上海',121.445,31.213,200000)
SH.print_city()

GZ = City('广州',113.265,23.108,510000)
GZ.print_city()
# 访问coordinate的说明文档
help(City.coordinate)
# 访问coordinate的说明文档,也可以直接取得成员的__doc__字符串
print(City.coordinate.__doc__)
# 访问coordinate属性
print(BJ.coordinate)
# 事实上是通过get方法访问的
# 直接对coordinate属性赋值
BJ.coordinate = 39, 116
print(BJ.coordinate)
# 事实上是通过set方法修改的,是安全的
# 直接访问隐藏的属性,例如lat,还是不行的
print(BJ.__lat)
# 通过get方法访问lat,确认lat也被修改了
print(BJ.get_lat())

五、类的继承

  • 继承就是子类全盘拷贝父类的成员(变量和方法),并在此基础上定义自己的成员。
  • python支持多继承。但多重继承会令编程复杂度极大增加最好还是用单继承,然后添加需要的变量和方法。
  • 多重继承,指一个子类有多个直接的父类。该子类会得到所有父类的所有方法。
  • 如果父类中有同名方法,则前面的父类中的方法会“遮蔽”后面父类的同名方法
  • 看来flyfire两个函数都在。Plane的构造函数优先,Weapon的构造函数被覆盖了。
# 多重继承例子
# 定义飞机类
class Plane:
    def __init__(self, name, speed = 2000):
        self.name = name
        self.speed = speed # 飞行速度
    def fly(self):
        print('%s是飞机,可以飞!' % self.name)
# 定义武器类
class Weapon:
    def __init__(self, name, attack_p = 500):
        self.name = name
        self.attack_p = attack_p # 攻击力点数
    def fire(self):
        print('%s是武器,开火!!!' % self.name)
# 定义战斗机类,继承飞机和武器
class Fighter(Plane, Weapon):
    pass # 什么都不做,先看看里面有什么
# 定义战斗机类Fighter的实例
f = Fighter('歼20')
# 看看里面有什么
print(f.name)
print(f.speed)
#print(f.attack_p) # 攻击力属性丢了!
f.fly()
f.fire()

重写父类方法

  • 有时候子类不仅仅是需要在父类的基础上增加新的方法,还需要改写父类已有的方法。
  • 例如客机、直升机、战斗机都是飞机,但它们的飞行方式不同。直升机能垂直起降,客机都是固定翼飞机不能垂直起降。战斗机一般不能垂直起降,但有一类特殊的飞机(F35B,海鹞,雅克38,雅克141)虽然是固定翼的但也能垂直起降。现代战斗机一般都能超音速飞行。
  • 如果子类的同名方法和父类不一样,就需要重写(override)该方法
# 重写父类方法例子
class Aircraft():
    '''    飞行器,包括热气球、飞艇、各种固定翼和旋翼飞机。在大气层内飞行。    '''
    def __init__(self, name, maxspeed = 100):
        self.name = name
        self.maxspeed = maxspeed # 飞行速度
    def fly(self):
        print('%s是飞行器(aircraft),可以在大气层内飞行。' % self.name)        
class Plane(Aircraft):
    '''    固定翼飞行器(Fixed-wing aeroplane),一般简称为飞机(plane),利用固定的机翼产生的升力在大气层内飞行。    '''
    def fly(self): # 重写父类的方法
        print('%s是固定翼飞行器(Fixed-wing aeroplane),利用固定的机翼产生的升力在大气层内飞行。' % self.name)
class Helicopter(Aircraft):
    '''    直升飞机(Helicopter),利用旋转的机翼产生的升力在大气层内飞行。    '''
    def fly(self): # 重写父类的方法
        print('%s直升飞机(Helicopter),利用旋转的机翼产生的升力在大气层内飞行。' % self.name)
# 定义固定翼飞机和直升飞机的实例
a = Plane('C919')
a.fly()
b = Helicopter('直20')
b.fly()

调用被重写的方法

有时候我们需要在子类中调用被重写的方法,只需要指定父类的名字就可以了。这个时候需要显示的给它传入self参数。

# 定义战斗机类,与之前不同的是,这次不使用多重继承,同时测试调用被重写的父类方法
class Fighter(Plane):
    def __init__(self, name, maxspeed = 2000, attack_p = 500):
        self.name = name
        self.maxspeed = maxspeed # 飞行速度
        self.attack_p = attack_p # 攻击力点数
    # 添加新的方法:开火
    def fire(self):
        print('%s是武器,开火!!!' % self.name)
    # 重写父类方法
    def fly(self):
        # 首先调用父类的同名方法,注意要给这个方法传入self参数
        Plane.fly(self)
        # 后面是新添加的内容
        print('%s是战斗机,可以高速飞行。' % self.name)
# 定义一个实例,看看fly方法执行的结果如何
c = Fighter('歼20')
c.fly()

使用super函数

  • python还支持使用super函数直接调用父类中的方法。我们可以用super函数重写Figher类。
  • super函数其实是super类的构造函数,它能自动绑定self,因此不需要传入self参数了。
# 定义战斗机类,使用super函数
class Fighter(Plane):
    def __init__(self, name, maxspeed = 2000, attack_p = 500):
        # 使用super函数调用父类的构造方法
        super().__init__(name, maxspeed)
        self.attack_p = attack_p # 攻击力点数
    # 添加新的方法:开火
    def fire(self):
        print('%s是武器,开火!!!' % self.name)
    # 重写父类方法
    def fly(self):
        # 使用super函数调用父类的方法
        super().fly()
        # 后面是新添加的内容
        print('%s是战斗机,可以高速飞行。' % self.name)

# 定义一个实例,看看fly方法执行的结果如何,和上面是一样的
c = Fighter('歼20')
c.fly()

# 看看super函数的帮助,发现它其实是super类的构造方法
help(super)

六、多态

  • python属于弱类型、动态类型语言,python的变量本身没有声明类型。变量指向什么类型,它就是什么类型。
  • 事实上,多态是一种灵活的编程机制,会根据传入的对象自动执行不同的行为。以飞行器类为例,会根据不同的类型选择不同的方式执行fly方法。
  • 多态在编写大型程序的时候非常有用。用户只需给出方法的名称,如何执行完全取决于对象本身。因此能省略大量的if或者switch之类的流程控制。
# 定义实例
a = Plane('C919')
a.fly()
# 同一个变量,换一个类
a = Helicopter('直20')
a.fly()
# 再换一个类,同样是执行fly方法,执行方式不同
a = Fighter('歼20')
a.fly()

类型检查函数

  • 多态的使用非常方便,但也有可能引入bug,例如调用不存在的方法,或者方法的行为在意料之外。
  • 为了保证程序质量,有时候需要有必要的类型检查,然后再调用方法。
  • issubclass(cls,class_or_turple): 检测类的继承关系:检查cls是否为有一个类或者元组中所包含的多个类中任意类的子类。
  • isinstance(cls,class_or_turple): 检测类和对象的关系:检查cls是否为有一个类或者元组中所包含的多个类中任意类的子类。
# 用issubclass检测类的继承关系
# Fighter是Plane的子类
print(issubclass(Fighter,Plane))
# Fighter不是Helicopter的子类
print(issubclass(Fighter,Helicopter))
# 使用元组作为第二个参数,只要符合其中一个就是True
print(issubclass(Fighter,(Plane,Helicopter)))


# 用isinstance检测类和对象的关系
a = Fighter('歼20')
# 是Fighter对象吗?
print(isinstance(a,Fighter))
# 是Plane对象吗?
print(isinstance(a,Plane))
# 是Helicopter对象吗?
print(isinstance(a,Helicopter))
# 使用元组作为第二个参数,只要符合其中一个就是True
print(isinstance(a,(Plane,Helicopter)))

七、枚举类

  • 枚举类型是一种特殊的数据类型,其中的对象数量是有限个。
  • python一般是通过Enum类的构造函数来定义枚举类enumeration [ɪˌnuːməˈreɪʃn]
  • 构造函数Enum()的第一个参数是类名,第二个参数是一个元组,列出所有枚举值。
  • 枚举类的每个成员有namevalue两个属性。name是成员的名称,value是成员的枚举值(顺序编号,从1开始,记住是从1开始!)
# 定义枚举类,一年四季
import enum
S = enum.Enum('Season',('spring','summer','fall','winter'))
# 访问枚举类
# 打印成员
print(S.spring)
# 打印成员的name属性
print(S.spring.name)
# 打印成员的value属性
print(S.spring.value)
# 通过变量名来访问成员(注意是用方括号,类似于访问字典类型)
print(S['spring'])
# 通过枚举值来访问成员(注意是用圆括号,编号从1开始,不是从0开始!)
print(S(1))
# 枚举类自带的__members__属性,将枚举类转换为字典(有序字典)
print(S.__members__)

枚举类的派生类

  • 有时候单纯的枚举类功能太单一了,和只读的有序字典差不多。
  • 可以从Enum类派生出我们自己的类,添加我们自己需要的方法。
class Season(enum.Enum):
    # 为序列指定value值
    spring = '春'
    summer = '夏'
    fall = '秋'
    winter = '冬'
    def info(self):
        print('这是一个代表季节%s的枚举' % self.value)
# 通过成员名访问
print(Season['spring'])
# 通过枚举值来访问
print(Season('春'))
# 使用info方法
Season['summer'].info()
# 使用__members__遍历有序字典
for name, member in Season.__members__.items():
    print(name, ':', member, ',', member.value)

  • 6
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值