Python 之面向对象

面向对象编Object Oriented Programming 简写 OOP

面向对象与面向过程对比

面向过程:

  •     注重 步骤与过程,不注重职责分工
  •     如果需求复杂,代码会变得很复杂
  •     开发复杂项目,没有固定的套路,开发难度很大!

面向对象:

  •     注重 对象和职责,不同的对象承担不同的职责
  •     更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路
  •     需要在面向过程基础上,再学习一些面向对象的语法

面向对象三大特性

  1. 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的  中
    • 定义类的准则
  2. 继承 实现代码的重用,相同的代码不需要重复的编写
    • 设计类的技巧
    • 子类针对自己特有的需求,编写特定的代码
  3. 多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果

    • 多态 可以 增加代码的灵活度
    • 以 继承 和 重写父类方法 为前提
    • 是调用方法的技巧,不会影响到类的内部设计

类和对象的概念 

 

 是对一群具有 相同 特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用

  • 特征 被称为 属性(变量)
  • 行为 被称为 方法

在程序开发中,要设计一个类,通常需要满足一下三个要素:

  1. 类名 这类事物的名字,满足大驼峰命名法(每一个单词的首字母大写、单词与单词之间没有下划线
  2. 属性 这类事物具有什么样的特征
  3. 方法 这类事物具有什么样的行为

对象 

  • 对象 是 由类创建出来的一个具体存在,可以直接使用
  • 由 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的属性、方法 

类和对象的关系

  • 类是模板对象 是根据  这个模板创建出来的,应该 先有类,再有对象
  •  只有一个,而 对象 可以有很多个
    • 不同的对象 之间 属性 可能会各不相同
  •  中定义了什么 属性和方法对象 中就有什么属性和方法,不可能多,也不可能少

面相对象实现⽅法

dir() 内置函数 

在 Python 中 对象几乎是无所不在的,我们之前学习的 变量数据函数 都是对象

使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的 所有属性及方法

定义简单的类(只包含方法)

class 类名:

    def 方法1(self, 参数列表):
        pass

    def 方法2(self, 参数列表):
        pass
  • 方法 的定义格式和之前学习过的函数 几乎一样
  • 区别在于第一个参数必须是 self,大家暂时先记住,稍后介绍 self

创建对象

当一个类定义完成之后,要使用这个类来创建对象,语法格式如下  

对象变量 = 类名()
class Cat:
    """这是一个猫类"""

    def eat(self):
        print("小猫爱吃鱼")

    def drink(self):
        print("小猫在喝水")

tom = Cat()
tom.drink()
tom.eat()

方法中的 self 参数 

self指的是调⽤该函数的对象。

  • 由 哪一个对象 调用的方法,方法内的 self 就是 哪一个对象的引用
  • 调用方法时,程序员不需要传递 self 参数
  • 在 类封装的方法中,通过 self. 访问对象的 属性和方法 

 例:

# 1. 定义类
class Washer():
 def wash(self):
 print('我会洗⾐服')
 # <__main__.Washer object at 0x0000024BA2B34240>
 print(self)

# 2. 创建对象
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)
# haier1对象调⽤实例⽅法
haier1.wash()
haier2 = Washer()
# <__main__.Washer object at 0x0000022005857EF0>
print(haier2)

注意:打印对象和self得到的结果是⼀致的,都是当前对象的内存中存储地址。

 

添加和获取对象属性

1、在类的外部给对象增加属性(简单,但不推荐)

语法

在 类的外部的代码 中直接通过 . 设置一个属性即可

 对象名.属性名 = 值

例:

haier1.width = 500
haier1.height = 800
tom.name = "Tom"
...

lazy_cat.name = "大懒猫"

2、类的外部访问对象的属性

语法

对象名.属性名

 例:

print(f'haier1洗⾐机的宽度是{haier1.width}')
print(f'haier1洗⾐机的⾼度是{haier1.height}')

3、在类里面获取对象属性

语法

self.属性名

# 定义类
class Washer():
 def print_info(self):
     # 类⾥⾯获取实例属性
     print(f'haier1洗⾐机的宽度是{self.width}')
     print(f'haier1洗⾐机的⾼度是{self.height}')

# 创建对象
haier1 = Washer()

# 添加实例属性
haier1.width = 500
haier1.height = 800
haier1.print_info()

初始化方法__init__()  

  • 当使用 类名() 创建对象时,会 自动 执行以下操作来初始化对象:
    1. 为对象在内存中 分配空间 —— 创建对象
    2. 为对象的属性 设置初始值 —— 通过初始化方法(__init__() )
  • __init__ ()是对象的内置方法是 专门 用来定义一个类 具有哪些属性的方法!;
  • __init__(self) 中的self参数,不需要开发者传递,python解释器会⾃动把当前的对象引 ⽤传递过去

1、在初始化方法内部定义属性 

  • self.属性名 = 属性的初始值 
class Washer():

 # 定义初始化功能的函数
 def __init__(self):
     # 添加实例属性
     self.width = 500
     self.height = 800
 def print_info(self):
     # 类⾥⾯调⽤实例属性
     print(f'洗⾐机的宽度是{self.width}, ⾼度是{self.height}')

haier1 = Washer()
haier1.print_info()

2、带参数的__init__() 

在开发中,如果在 创建对象的同时,就设置对象的属性,可以做以下操作:

  1. 把希望设置的属性值,定义成 __init__ 方法的参数
  2. 在方法内部使用 self.属性 = 形参 接收外部传递的参数
  3. 在创建对象时,使用 类名(属性1, 属性2...) 调用

思考:⼀个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢? 答:传参数。 

class Washer():
    def __init__(self, width, height):
         self.width = width
         self.height = height
    def print_info(self):
         print(f'洗⾐机的宽度是{self.width}')
         print(f'洗⾐机的⾼度是{self.height}')

haier1 = Washer(10, 20)
haier1.print_info()

haier2 = Washer(30, 40)
haier2.print_info()

 __str__ 方法 

  •  使用 print 输出 对象时,默认打印对象在内存中的地址十六进制表示
  • 如果类定义了 __str__ ⽅法,那么就会打印 在这个⽅法中 return 的数据
  • 注意:__str__ 方法必须返回一个字符串
class Washer():
   def __init__(self, width, height):
       self.width = width
       self.height = height
   def __str__(self):
       return '这是海尔洗⾐机的说明书'

haier1 = Washer(10, 20)
# 这是海尔洗⾐机的说明书
print(haier1)
class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 来了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

    def __str__(self):
        return "我是小猫:%s" % self.name

tom = Cat("Tom")
print(tom)

 __del__ 方法

  • 在 Python 中

    • 当使用 类名() 创建对象时,为对象 分配完空间后,自动 调用 __init__ 方法
    • 当一个 对象被从内存中销毁 前,会 自动 调用 __del__ 方法
  • 应用场景

    • __init__ 改造初始化方法,可以让创建对象更加灵活
    • __del__ 如果希望在对象被销毁前,再做一些事情,可以考虑一下 __del__ 方法
  • 生命周期

    • 一个对象从调用 类名() 创建,生命周期开始
    • 一个对象的 __del__ 方法一旦被调用,生命周期结束
    • 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
class Cat:

    def __init__(self, new_name):

        self.name = new_name

        print("%s 来了" % self.name)

    def __del__(self):

        print("%s 去了" % self.name)

# tom 是一个全局变量
tom = Cat("Tom")
print(tom.name)

# del 关键字可以删除一个对象
del tom

print("-" * 50)

当删除对象时,python解释器也会默认调⽤ __del__() ⽅法。

class Washer():
     def __init__(self, width, height):
         self.width = width
         self.height = height
     def __del__(self):
         print(f'{self}对象已经被删除')

haier1 = Washer(10, 20)
# <__main__.Washer object at 0x0000026118223278>对象已经被删除
del haier1

  封装 

  • 封装 是面向对象编程的一大特点
  • 面向对象编程的 第一步 —— 将 属性 和 方法 封装 到一个抽象的  中
  • 外界 使用  创建 对象,然后 让对象调用方法
  • 对象方法的细节 都被 封装 在 类的内部
  • 一个对象的 属性 可以是 另外一个类创建的对象

  • 在 对象的方法内部,是可以 直接访问对象的属性 的
  • 同一个类 创建的 多个对象 之间,属性 互不干扰!

定义没有初始值的属性

在定义属性时,如果 不知道设置什么初始值,可以设置为 None

  • None 关键字 表示 什么都没有
  • 表示一个 空对象没有方法和属性,是一个特殊的常量
  • 可以将 None 赋值给任何一个变量
class Soldier:

    def __init__(self, name):

        # 姓名
        self.name = name
        # 枪,士兵初始没有枪 None 关键字表示什么都没有
        self.gun = None

  私有属性和私有方法

  • 在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到
  • 私有属性 就是 对象 不希望公开的 属性
  • 私有方法 就是 对象 不希望公开的 方法

定义方式

在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法

class Women:

    def __init__(self, name):

        self.name = name
        self.__age = 18

    def __secret(self):
        # 在对象的方法内部,是可以访问对象的私有属性的
        print("%s 的年龄是 %d" % (self.name, self.__age))


xiaofang = Women("小芳")

# 私有属性,在外界不能够被直接访问
# print(xiaofang.__age)
# 私有方法,同样不允许在外界直接访问
# xiaofang.__secret()

伪私有属性和私有方法(科普) 

Python 中,并没有 真正意义 的 私有

  • 在给 属性方法 命名时,实际是对 名称 做了一些特殊处理,使得外界无法访问到
  • 处理方式:在 名称 前面加上 _类名 => _类名__名称
# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)

# 私有方法,外部不能直接调用
xiaofang._Women__secret()

注:在Python中,⼀般定义函数名 get_xx ⽤来获取私有属性,定义 set_xx ⽤来修改私有属性值 

继承 

继承的概念、语法和特点

继承的概念

Python⾯向对象的继承指的是多个类之间的所属关系,即⼦类默认继承⽗类的所有属性和⽅法子类 拥有 父类 的所有 方法 和 属性

 继承的语法

class 类名(父类名):

    pass

例:

# ⽗类A
class A(object):
    def __init__(self):
        self.num = 1
    def info_print(self):
        print(self.num)

# ⼦类B
class B(A):
    pass

result = B()
result.info_print() # 1
  • 子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发
  • 子类 中应该根据 职责,封装 子类特有的 属性和方法​​​​​​​

 新式类与旧式(经典)类

object 是 Python为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看

  • 新式类:以 object 为基类的类,推荐使用
  • 经典类:不以 object 为基类的类,不推荐使用

  • 在 Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类

  • 在 Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类 

新式类 和 经典类 在多继承时 —— 会影响到方法的搜索顺序;为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行! 今后在定义类时,如果没有父类,建议统一继承自 object

class 类名(object):
    pass

单继承

 一个父类继承给一个子类

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')


# 2. 定义徒弟类,继承师父类
class Prentice(Master):
    pass


# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()

print(daqiu.kongfu)

daqiu.make_cake()

 多继承 

  • 所谓多继承意思就是⼀个类同时继承了多个⽗类
  • 子类 可以拥有 所有父类 的 属性 和 方法

 语法:

class 子类名(父类名1, 父类名2...)
    pass

Python 中的 MRO —— 方法搜索顺序  

  • Python 中针对  提供了一个 内置属性 __mro__ 可以查看 属性和方法 搜索顺序,也就是类继承的层级关系
  • MRO 是 method resolution order,主要用于 在多继承时判断 属性和方法 的调用 路径
  •  当⼀个类有多个⽗类的时候,默认使⽤第⼀个⽗类的同名属性和⽅法
  • ⼦类和⽗类具有同名属性和⽅法,默认使⽤⼦类的同名属性和⽅法。 
  • :如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承 
class A:

    def test(self):
        print("test 方法")


class B:

    def demo(self):
        print("demo 方法")


class C(A, B):
    """多继承可以让子类对象,同时具有多个父类的属性和方法"""
    pass


# 创建子类对象
c = C()

c.test()
c.demo()
print(C.__mro__)


(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)

  • 在搜索方法时,是按照 __mro__ 的输出结果 从左至右 的顺序查找的
  • 如果在当前类中 找到方法,就直接执行,不再搜索
  • 如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索
  • 如果找到最后一个类,还没有找到方法,程序报错

继承的传递性

  • C 类从 B 类继承,B 类又从 A 类继承
  • 那么 C 类就具有 B 类和 A 类的所有属性和方法

子类 拥有 父类 以及 父类的父类 中封装的所有 属性 和 方法

⼦类重写⽗类同名⽅法和属性

  • 当 父类 的方法实现不能满足子类需求时,可以对方法进行 重写(override)

1、覆盖父类的方法

如果在开发中,父类的方法实现 和 子类的方法实现完全不同,就可以使用 覆盖 的方式,在子类中 重新编写 父类的方法实现

  • 具体的实现方式,就相当于在 子类中定义了一个和父类同名的方法并且实现
  • 重写之后,在运行时,只会调用子类中重写的方法,而不再会调用 父类封装的方法
⼦类调⽤⽗类的同名⽅法和属性
父类名.方法(self)
# ⼦类和⽗类具有同名属性和⽅法,默认使⽤⼦类的同名属性和⽅法。
# 故事:很多顾客都希望也能吃到古法和学校的技术的煎饼果⼦。
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果⼦配⽅]'

    def make_cake(self):
        print(f'运⽤{self.kongfu}制作煎饼果⼦')



class School(object):
    def __init__(self):
        self.kongfu = '[学校煎饼果⼦配⽅]'

    def make_cake(self):
        print(f'运⽤{self.kongfu}制作煎饼果⼦')



# 独创配⽅
class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果⼦配⽅]'

    def make_cake(self):
         # 如果是先调⽤了⽗类的属性和⽅法,⽗类属性会覆盖⼦类属性,故在调⽤属性前,先调⽤⾃⼰⼦类的初始化
         self.__init__()
         print(f'运⽤{self.kongfu}制作煎饼果⼦')

         # 调⽤⽗类⽅法,但是为保证调⽤到的也是⽗类的属性,必须在调⽤⽅法前调⽤⽗类的初始化
         def make_master_cake(self):
             Master.__init__(self)
             Master.make_cake(self)

         def make_school_cake(self):
             School.__init__(self)
             School.make_cake(self)



daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
daqiu.make_master_cake()
daqiu.make_school_cake()
daqiu.make_cake()
print(Prentice.__mro__)

2、对父类方法进行 扩展

如果在开发中,子类的方法实现 中 包含 父类的方法实现(父类原本封装的方法实现 是 子类方法的一部分),就可以使用 扩展 的方式

⼦类调⽤⽗类的同名⽅法和属性 

super()

  • 在 Python 中 super 是一个 特殊的类,super() 就是使用 super 类创建出来的对象
  • 最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
  • 在需要的位置使用 super().父类方法 来调用父类方法的执行

注:

  • 在开发时,父类名 和 super() 两种方式不要混用
  • 如果使用 当前子类名 调用方法,会形成递归调用,出现死循环
lass Animal:

    def eat(self):
        print("吃---")

    def drink(self):
        print("喝---")

    def run(self):
        print("跑---")

    def sleep(self):
        print("睡---")


class Dog(Animal):

    def bark(self):
        print("汪汪叫")


class XiaoTianQuan(Dog):

    def fly(self):
        print("我会飞")

    def bark(self):

        # 1. 针对子类特有的需求,编写代码
        print("神一样的叫唤...")

        # 2. 使用 super(). 调用原本在父类中封装的方法
        # super().bark()

        # 父类名.方法(self)
        Dog.bark(self)
        # 注意:如果使用子类调用方法,会出现递归调用 - 死循环!
        # XiaoTianQuan.bark(self)

        # 3. 增加其他子类的代码
        print("$%^*%^$%^#%$%")


xtq = XiaoTianQuan()

# 如果子类中,重写了父类的方法
# 在使用子类对象调用方法时,会调用子类中重写的方法
xtq.bark()

父类的 私有属性 和 私有方法

  1. 子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法
  2. 子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法
  • 私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问
  • 私有属性、方法 通常用于做一些内部的事情
class A:

    def __init__(self):

        self.num1 = 100
        self.__num2 = 200

    def __test(self):
        print("私有方法 %d %d" % (self.num1, self.__num2))

    def test(self):
        print("父类的公有方法 %d" % self.__num2)

        self.__test()


class B(A):

    def demo(self):

        # 1. 在子类的对象方法中,不能访问父类的私有属性
        # print("访问父类的私有属性 %d" % self.__num2)

        # 2. 在子类的对象方法中,不能调用父类的私有方法
        # self.__test()

        # 3. 访问父类的公有属性
        print("子类方法 %d" % self.num1)

        # 4. 调用父类的公有方法
        self.test()
        pass

# 创建一个子类对象
b = B()
print(b)

b.demo()
# 在外界访问父类的公有属性/调用公有方法
# print(b.num1)
# b.test()

# 在外界不能直接访问对象的私有属性/调用私有方法
# print(b.__num2)
# b.__test()

多态 

定义

多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果

好处

可以 增加代码的灵活度,多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!

实现步骤

  • 定义⽗类,并提供公共⽅法
  • 定义⼦类,并重写⽗类⽅法
  • 传递⼦类对象给调⽤者,可以看到不同⼦类执⾏效果不同

注:是调用方法的技巧,不会影响到类的内部设计

class Dog(object):

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

    def game(self):
        print("%s 蹦蹦跳跳的玩耍..." % self.name)


class XiaoTianDog(Dog):

    def game(self):
        print("%s 飞到天上去玩耍..." % self.name)


class Person(object):

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

    def game_with_dog(self, dog):

        print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))

        # 让狗玩耍
        dog.game()


# 1. 创建一个狗对象
# wangcai = Dog("旺财")
wangcai = XiaoTianDog("飞天旺财")

# 2. 创建一个小明对象
xiaoming = Person("小明")

# 3. 让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai)

类属性和类方法 

实例

  1. 使用面相对象开发,第 1 步 是设计 
  2. 使用 类名() 创建对象,创建对象 的动作有两步:
    • 1) 在内存中为对象 分配空间
    • 2) 调用初始化方法 __init__ 为 对象初始化
  3. 对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例

因此,通常也会把:

  1. 创建出来的 对象 叫做  的 实例
  2. 创建对象的 动作 叫做 实例化
  3. 对象的属性 叫做 实例属性
  4. 对象调用的方法 叫做 实例方法

在程序执行时:

  1. 对象各自拥有自己的 实例属性
  2. 调用对象方法,可以通过 self.
    • 访问自己的属性
    • 调用自己的方法

总结

  • 每一个对象 都有自己 独立的内存空间保存各自不同的属性
  • 多个对象的方法在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部

类对象

Python 中 一切皆对象

  • class AAA: 定义的类属于 类对象
  • obj1 = AAA() 属于 实例对象
  • 在程序运行时, 同样 会被加载到内存
  • 在 Python 中, 是一个特殊的对象 —— 类对象
  • 在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例
  • 除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法
    1. 类属性
    2. 类方法

类属性 

概念

  • 类属性 就是给 类对象 中定义的 属性
  • 通常用来记录 与这个类相关 的特征
  • 类属性 不会用于记录 具体对象的特征

定义

使用 赋值语句 在 class 关键字下方可以定义 类属性

类属性的优点

  • 记录的某项数据 始终保持⼀致时,则定义类属性。
  • 实例属性 要求 每个对象 为其 单独开辟⼀份内存空间 来记录数据,⽽ 类属性 为全类所共有 ,仅占⽤⼀份内存,更加节省内存空间。

需求

  • 定义一个 工具类
  • 每件工具都有自己的 name
  • 需求 —— 知道使用这个类,创建了多少个工具对象?

class Tool(object):

    # 使用赋值语句,定义类属性,记录创建工具对象的总数
    count = 0

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

        # 针对类属性做一个计数+1
        Tool.count += 1


# 创建工具对象
tool1 = Tool("斧头")
tool2 = Tool("榔头")
tool3 = Tool("铁锹")

# 知道使用 Tool 类到底创建了多少个对象?
print("现在创建了 %d 个工具" % Tool.count)

 属性获取机制

在 Python 中 属性的获取 存在一个 向上查找机制

 

因此,要访问类属性有两种方式:

  1. 类名.类属性
  2. 对象.类属性 (不推荐)

:如果使用对象.类属性 = 值 赋值语句,只会给对象添加一个属性,而不会影响到类属性的值

修改类属性

类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了 ⼀个实例属性。

class Dog(object):
    tooth = 10

wangcai = Dog()
xiaohei = Dog()

# 修改类属性
Dog.tooth = 12
print(Dog.tooth) # 12
print(wangcai.tooth) # 12
print(xiaohei.tooth) # 12

# 不能通过对象修改属性,如果这样操作,实则是创建了⼀个实例属性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12

类方法 

定义

类方法 就是针对 类对象 定义的方法

语法

@classmethod
def 类方法名(cls):
    pass

1.类方法需要用 装饰器 @classmethod 来标识,告诉解释器这是一个类方法

2.类方法的 第一个参数 应该是 cls

  • 由 哪一个类 调用的方法,方法内的 cls 就是 哪一个类的引用
  • 这个参数和 实例方法 的第一个参数是 self 类似
  • 提示 使用其他名称也可以,不过习惯使用 cls

3.通过 类名. 调用 类方法调用方法时,不需要传递 cls 参数

4.在类方法内部,可以直接使用 cls. 访问 类属性 或者 调用类方法

 类⽅法使⽤场景

  • 当⽅法中 需要使⽤类对象 (如访问私有类属性等)时,定义类⽅法
  • 类⽅法⼀般和类属性配合使⽤ 
class Dog(object):
    __tooth = 10

    @classmethod
    def get_tooth(cls):
        return cls.__tooth

wangcai = Dog()
result = wangcai.get_tooth()
print(result) # 10

静态方法 

静态⽅法特点

  • 需要通过装饰器 @staticmethod 来进⾏修饰,静态⽅法既不需要传递类对象也不需要传递实例对象 (形参没有self/cls)
  • 静态⽅法 也能够通过 实例对象 和 类对象 去访问

静态⽅法使⽤场景 

  • 当⽅法中 既不需要使⽤实例对象(如实例对象,实例属性),也不需要使⽤类对象 (如类属性、类⽅ 法、创建实例等)时,定义静态⽅法
  • 取消不需要的参数传递,有利于 减少不必要的内存占⽤和性能消耗

语法

@staticmethod
def 静态方法名():
    pass
  • 静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法
  • 通过 类名. 调用 静态方法

静态方法不需要传递第一个参数

class Dog(object):
    @staticmethod
    def info_print():
        print('这是⼀个狗类,⽤于创建狗实例....')

wangcai = Dog()
# 静态⽅法既可以使⽤对象访问⼜可以使⽤类访问
wangcai.info_print()
Dog.info_print()

综合需求

  1. 设计一个 Game 类
  2. 属性:
    • 定义一个 类属性 top_score 记录游戏的 历史最高分
    • 定义一个 实例属性 player_name 记录 当前游戏的玩家姓名
  3. 方法:
    • 静态方法 show_help 显示游戏帮助信息
    • 类方法 show_top_score 显示历史最高分
    • 实例方法 start_game 开始当前玩家的游戏
  4. 主程序步骤
    • 1) 查看帮助信息
    • 2) 查看历史最高分
    • 3) 创建游戏对象,开始游戏

class Game(object):

    # 游戏最高分,类属性
    top_score = 0

    @staticmethod
    def show_help():
        print("帮助信息:让僵尸走进房间")

    @classmethod
    def show_top_score(cls):
        print("游戏最高分是 %d" % cls.top_score)

    def __init__(self, player_name):
        self.player_name = player_name

    def start_game(self):
        print("[%s] 开始游戏..." % self.player_name)

        # 使用类名.修改历史最高分
        Game.top_score = 999

# 1. 查看游戏帮助
Game.show_help()

# 2. 查看游戏最高分
Game.show_top_score()

# 3. 创建游戏对象,开始游戏
game = Game("小明")

game.start_game()

# 4. 游戏结束,查看游戏最高分
Game.show_top_score()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值