第11章 面向对象程序设计

51 阅读10分钟

面向对象的基本概念

image.png

面向对象技术简介

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

Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
对象可以包含任意数量和类型的数据。

类和实例

类的定义

  • class:表明这是一个类
  • ClassName:类的名字
  • ():父类集合的开始和结束
  • object:父类的名字,定义的类继承自父类,可以不写,默认是object。object是所有类的直接或间接父类

类的创建

class Player(object): # object 基类
    pass

tom = Player()  # 类的实例化(创建对象)
print(type(tom))
print(isinstance(tom,object))
print(isinstance(tom,Player))

类的实例化(创建对象)

实例名 = 类() 的方式实例化对象,为类创建一个实例

实例属性

class Player(object):
    def __init__(self,name,age,city):  # 初始化函数(构造函数)
        self.name = name
        self.age = age
        self.city = city

mia = Player('mia',24,'上海')
mia.city = '杭州'
tom = Player('tom',34,'重庆')
tom.height = 180
tom.age = 32
print(tom.__dict__) # 获取实例(对象)的所有属性

# 武器: 名字 攻击值 等级
class weapon(object):
    def __init__(self,name,damage,level):
        self.name = name
        self.damage = damage
        self.level = level

gun = weapon('magic',1000,3)
print(gun.__dict__)

类属性

class Player(object):
    numbers = 0   # 类属性
    def __init__(self,name,age,city):  # 初始化函数(构造函数)
        self.name = name  # 实例属性
        self.age = age
        self.city = city
        Player.numbers += 1

mia = Player('mia',24,'上海')
print(mia.__dict__)
print('欢迎荣耀王者的第 %d 个玩家注册!' % Player.numbers)
tom = Player('tom',32,'重庆')
print('欢迎荣耀王者的第 %d 个玩家注册!' % Player.numbers)

class weapon(object):
    numbers = 0
    max_damage = 10000
    levels = ['青铜','白银','黄金','钻石','王者']
    def __init__(self,name,damage,level):
        self.name = name
        self.damage = damage
        self.level = level
        weapon.numbers += 1
        if damage>weapon.max_damage:
            raise Exception('最大的伤害值是10000,请重试!')
        if level not in weapon.levels:
            raise Exception('段位设置错误!')
try:
    gun = weapon('magic',10000,'王者')
    print(weapon.numbers)
    arrow = weapon('arrow',450,'青铜')
    print(weapon.numbers)
except Exception as e:
    print(e)

构造方法

  • 类有一个名为 init() 的特殊方法(构造方法),该方法在类实例化时会自动调用,像下面这样:
def __init__(self):
    self.data = []

类定义了 init() 方法,类的实例化操作会自动调用 init() 方法。如下实例化类 MyClass,对应的 init() 方法就会被调用:

x = MyClass()
  • 当然, init() 方法可以有参数,参数通过 init() 传递到类的实例化操作上。例如:
#!/usr/bin/python3
 
class Complex:
    def __init__(self, realpart, imagpart):
        self.r = realpart
        self.i = imagpart
x = Complex(3.0, -4.5)
print(x.r, x.i)   # 输出结果:3.0 -4.5

self 代表类的实例,而非类

  • 类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
class Test:
    def prt(self):
        print(self)
        print(self.__class__)
 
t = Test()
t.prt()

以上实例执行结果为:

<__main__.Test instance at 0x100771878>
__main__.Test

从执行结果可以很明显的看出,self 代表的是类的实例,代表当前对象的地址,而 self.class 则指向类。 self 不是 python 关键字 在 Python中,self 是一个惯用的名称,用于表示类的实例(对象)自身。它是一个指向实例的引用,使得类的方法能够访问和操作实例的属性。

  • 当你定义一个类,并在类中定义方法时,第一个参数通常被命名为 self,尽管你可以使用其他名称,但强烈建议使用 self,以保持代码的一致性和可读性。

实例

class MyClass:
    def __init__(self, value):
        self.value = value

    def display_value(self):
        print(self.value)

# 创建一个类的实例
obj = MyClass(42) 

# 调用实例的方法
obj.display_value() # 输出 42

在上面的例子中,self 是一个指向类实例的引用,它在 init 构造函数中用于初始化实例的属性,也在 display_value 方法中用于访问实例的属性。通过使用 self,你可以在类的方法中访问和操作实例的属性,从而实现类的行为。

实例方法

class Player(object):
    numbers = 0   # 类属性
    levels = ['青铜', '白银', '黄金', '钻石', '王者']
    def __init__(self,name,age,city,level):  # 初始化函数(构造函数)
        self.name = name  # 实例属性
        self.age = age
        self.city = city
        if level not in Player.levels:
            raise Exception('段位设置错误!')
        else:
            self.level = level
        Player.numbers += 1

    def show(self):  # 实例的方法
        print('我是荣耀王者的第%d个玩家,我的名字是%s,我来自 %s,我的段位是%s' % (Player.numbers,self.name,self.city,self.level))

    def level_up(self):
        index1 = Player.levels.index(self.level)
        if index1<len(Player.levels)-1:
            self.level = Player.levels[index1+1]

    def get_weapon(self,weapon):
        self.weapon = weapon

    def show_weapon(self):
        return self.weapon.show_weapon()




class weapon(object):
    numbers = 0
    max_damage = 10000
    levels = ['青铜','白银','黄金','钻石','王者']
    def __init__(self,name,damage,level):
        self.name = name
        self.damage = damage
        self.level = level
        weapon.numbers += 1
        if damage>weapon.max_damage:
            raise Exception('最大的伤害值是10000,请重试!')
        if level not in weapon.levels:
            raise Exception('段位设置错误!')

    def show_weapon(self):
        for k,v in self.__dict__.items():
            print(k,v)



mia = Player('mia',24,'大连','青铜')
mia.show()
mia.level_up()
mia.show()
mia.level_up()
mia.show()
mia.level_up()
mia.show()
mia.level_up()
mia.show()
mia.level_up()
mia.show()
gun = weapon('magic_gun',1000,'青铜')
mia.get_weapon(gun)
mia.show_weapon()

类方法

class Player(object):
    numbers = 0   # 类属性
    levels = ['青铜', '白银', '黄金', '钻石', '王者']
    def __init__(self,name,age,city,level):  # 初始化函数(构造函数)
        self.name = name  # 实例属性
        self.age = age
        self.city = city
        if level not in Player.levels:
            raise Exception('段位设置错误!')
        else:
            self.level = level
        Player.numbers += 1

    def show(self):  # 实例的方法
        print('我是荣耀王者的第%d个玩家,我的名字是%s,我来自 %s,我的段位是%s' % (Player.numbers,self.name,self.city,self.level))

    def level_up(self):
        index1 = Player.levels.index(self.level)
        if index1<len(Player.levels)-1:
            self.level = Player.levels[index1+1]

    def get_weapon(self,weapon):
        self.weapon = weapon

    def show_weapon(self):
        return self.weapon.show_weapon()

    @classmethod
    def get_players(cls):  # 类方法
        print('荣耀王者的用户数量已经达到了%d人'%cls.numbers)

mia = Player('mia',24,'湖北','青铜')
mia.show()
Player.get_players()




class weapon(object):
    # 类属性
    numbers = 0
    max_damage = 10000
    levels = ['青铜','白银','黄金','钻石','王者']
    all_weapons = []

    # 构造方法
    def __init__(self,name,damage,level):
        self.name = name
        self.damage = damage
        self.level = level
        weapon.numbers += 1
        if damage>weapon.max_damage:
            raise Exception('最大的伤害值是10000,请重试!')
        if level not in weapon.levels:
            raise Exception('段位设置错误!')
        weapon.all_weapons.append(self)

    @classmethod
    def get_max_damage(cls):
        max_damage = 0
        for w in cls.all_weapons:
            if w.damage>max_damage:
                max_damage = w.damage
        return max_damage




    def show_weapon(self):
        for k,v in self.__dict__.items():
            print(k,v)

gun = weapon('magic',345,'青铜')
a = weapon('a',34,'白银')
b = weapon('b',123,'白银')
print(weapon.get_max_damage())

'''
类属性
类方法
实例属性
实例方法
'''

静态方法

class Player(object):
    numbers = 0   # 类属性
    levels = ['青铜', '白银', '黄金', '钻石', '王者']
    def __init__(self,name,age,city,level):  # 初始化函数(构造函数)
        self.name = name  # 实例属性
        self.age = age
        self.city = city
        if level not in Player.levels:
            raise Exception('段位设置错误!')
        else:
            self.level = level
        Player.numbers += 1

    def show(self):  # 实例的方法
        print('我是荣耀王者的第%d个玩家,我的名字是%s,我来自 %s,我的段位是%s' % (Player.numbers,self.name,self.city,self.level))

    def level_up(self):
        index1 = Player.levels.index(self.level)
        if index1<len(Player.levels)-1:
            self.level = Player.levels[index1+1]

    def get_weapon(self,weapon):
        self.weapon = weapon

    def show_weapon(self):
        return self.weapon.show_weapon()

    @classmethod
    def get_players(cls):  # 类方法
        print('荣耀王者的用户数量已经达到了%d人'%cls.numbers)

    @staticmethod
    def isvalid(**kwargs):
        if kwargs['age']>18:
            return True
        else:
            return False


infos = {'name':'mia','age':13,'city':'北京','level':'白银'}
if Player.isvalid(**infos):
    mia = Player('mia',24,'北京','白银')
else:
    print('请检查')

class weapon(object):
    # 类属性
    numbers = 0
    max_damage = 10000
    levels = ['青铜','白银','黄金','钻石','王者']
    all_weapons = []

    # 构造方法
    def __init__(self,name,damage,level):
        self.name = name
        self.damage = damage
        self.level = level
        weapon.numbers += 1
        if damage>weapon.max_damage:
            raise Exception('最大的伤害值是10000,请重试!')
        if level not in weapon.levels:
            raise Exception('段位设置错误!')
        weapon.all_weapons.append(self)

    @classmethod
    def get_max_damage(cls):
        max_damage = 0
        for w in cls.all_weapons:
            if w.damage>max_damage:
                max_damage = w.damage
        return max_damage




    def show_weapon(self):
        for k,v in self.__dict__.items():
            print(k,v)

魔法方法

  • Python中的魔法方法(也称为特殊方法或双下划线方法)是一种在类定义中使用的特殊命名约定的方法。
  • 当Python遇到某些内置操作时,它会尝试在对象上调用这些魔法方法。
  • 这些操作包括但不限于算术运算、属性访问、类型转换等。
class User(object):
    def __init__(self,name):  # 构造函数
        print('__init__被调用')
        self.name = name

    def __str__(self):
        return '我的名字是%s'%self.name

    def __add__(self, other):
        return self.name + other.name

    def __eq__(self, other):
        return self.name == other.name


mia = User('mia')
print(str(mia))
print(mia)
print(1+3)
print('hi '+'mia')
jack = User('mia')
print(mia+jack)
print(6==7)
print(mia==jack)

本章总结

image.png

image.png

习题

  1. 在Python中,哪个关键字用于定义一个类?A
    A. class
    B. function
    C. def
    D. type
  1. 下列关于Python类中的方法的描述,哪一个是错误的?D
    A. 实例方法是与类的实例绑定的方法,需要通过实例来调用。
    B. 类方法是与类本身绑定的方法,可以使用类名直接调用。
    C. 静态方法既不与实例绑定,也不与类绑定,它只是一个普通的函数。
    D. 所有类的方法都必须显式地定义self参数来代表类的实例。
  1. 在Python中,如果一个类没有显式地定义__init__方法,那么当创建该类的实例时,Python会做什么? B
    A. 抛出一个错误,因为必须定义__init__方法。
    B. 隐式地定义一个__init__方法,该方法什么都不做。
    C. 隐式地定义一个__init__方法,该方法将实例的所有属性初始化为None。
    D. 隐式地定义一个__init__方法,该方法将实例的所有属性初始化为空。
  1. 下列关于Python中的继承的描述,哪一个是正确的? B
    A. 在Python中,一个类只能继承自一个父类。
    B. Python支持多重继承,即一个类可以继承自多个父类。
    C. Python中的继承是按照深度优先的顺序进行的。
    D. 在Python中,子类的属性会覆盖父类的同名属性。
  1. 下列哪个选项不是Python中特殊方法(魔法方法)的例子?D
    A. init
    B. str
    C. add
    D. import
  1. 在Python中,self参数在类的方法中代表什么?A
    A. 类的实例
    B. 类本身
    C. 父类
    D. 方法的返回值
  1. Python中的super()函数用于什么目的?B
    A. 调用父类的构造函数
    B. 调用父类的任意方法
    C. 获取父类实例
    D. 访问父类的属性
  1. Python中的@property装饰器用于什么目的?C
    A. 定义一个类的实例方法
    B. 定义一个类的类方法
    C. 将一个方法转换为属性的getter方法
    D. 将一个方法转换为属性的setter方法
  1. Python中的@classmethod装饰器用于什么目的?C
    A. 将一个方法转换为属性的getter方法
    B. 将一个方法转换为属性的setter方法
    C. 定义一个类的类方法
    D. 定义一个类的静态方法
  1. Python中的@property装饰器用于什么目的?C
    A. 定义一个类的实例方法
    B. 定义一个类的类方法
    C. 将一个方法转换为属性的getter方法
    D. 将一个方法转换为属性的setter方法