面对对象初识

【一】人狗大战小游戏引入

【1】游戏规则分析

  • 人可以打狗,狗掉血,狗可以咬人,人掉血

  • 人的属性

    • 姓名

    • 类型

    • 年龄

    • 攻击力

    • 生命值

  • 狗的属性

    • 姓名

    • 类型

    • 年龄

    • 攻击力

    • 生命值

【二】封装成函数,减少代码冗余

复制代码
def get_person(name, gender, age, t_type, attack_val, life_val):
    # 将人的攻击动作放在产生人的函数内
    def person_attack(person_obj, dog_obj):
        """
        :param person_obj: 接收一个人
        :param dog_obj: 接收一条狗
        """
        print('当前狗的血量是:%s' % dog_obj.get('life_val'))
        dog_obj['life_val'] -= person_obj.get('attack_val')
        print("""人:%s 锤了狗:%s 一下 狗掉血:%s 剩余血量:%s""" % (
            person_obj.get('name'), dog_obj.get('name'), person_obj.get('attack_val'), dog_obj['life_val']))
​
    data_dict = {
        'name': name,
        'gender': gender,
        'age': age,
        't_type': t_type,
        'attack_val': attack_val,
        'life_val': life_val,
        'person_attack': person_attack
    }
    return data_dict
​
​
def get_dog(name, t_type, attack_val, life_val):
    def dog_attack(dog_obj, person_obj):
        """
        :param dog_obj: 接收一条狗
        :param person_obj: 接收一个人
        """
        # 使用最简答的掉血逻辑  血量减去对方攻击力
        print('当前人的血量是:%s' % person_obj.get('life_val'))
        person_obj['life_val'] -= dog_obj.get('attack_val')
        print("""狗:%s 咬了人:%s 一口 人掉血:%s 剩余血量:%s""" % (
            dog_obj.get('name'), person_obj.get('name'), dog_obj.get('attack_val'), person_obj['life_val']))
​
    data_dict = {
        'name': name,
        't_type': t_type,
        'attack_val': attack_val,
        'life_val': life_val,
        'dog_attack': dog_attack
    }
    return data_dict
​
​
p1 = get_person('knight', 'male', 22, '猛男', 50, 1000)
p2 = get_person('ddt', 'female', 24, '淑女', 10, 100)
dog1 = get_dog('小黑', '松狮犬', 30, 500)
dog2 = get_dog('小白', '泰迪犬', 10, 200)
p1['person_attack'](p1, dog1)
dog1['dog_attack'](dog1, p2)

(二)什么是面对对象

【1】面向对象理解

  • 面向对象就相当于上帝,在上帝的视角,人是对象,动物是对象,石头是对象,水是对象,山是对象.....存在的可以扩充,不存在的可以创造。

【2】面向对象的优缺点

(1)面对对象的优点
  • 解决程序的延展性

  • 对某一个对象单独修改,会立刻反映到整个体系中,如对游戏中一个人物参数的特征和技能修改都很容易。

(2)面向对象的缺点
  • 编程的复杂度远高于面向过程,不了解面向对象而立即上手基于它设计程序,极容易出现过度设计的问题。

    • 一些扩展性要求低的场景使用面向对象会徒增编程难度,比如管理linux系统的shell脚本就不适合用面向对象去设计,面向过程反而更加适合。
  • 无法向面向过程的程序设计流水线式的可以很精准的预测问题的处理流程与结果,面向对象的程序一旦开始就由对象之间的交互解决问题,即便是上帝也无法准确地预测最终结果。

    • 于是我们经常看到对战类游戏,新增一个游戏人物,在对战的过程中极容易出现阴霸的技能,一刀砍死3个人,这种情况是无法准确预知的,只有对象之间交互才能准确地知道最终的结果。

【3】什么是程序

  • 程序=数据+功能

  • 编写程序的本质就是定义一系列的数据,然后写出一些功能对数据进行操作

【三】类与对象

【1】什么是类

  • 类即类别、种类,是面向对象设计最重要的概念,对象是特征与技能的结合体,而类则是一系列对象相似的特征与技能的结合体

  • 所以,先有鸡和先有蛋的问题就出来了

    • 先有的一个个具体存在的对象(比如一个具体存在的人)

    • 还是先有的人类这个概念,这个问题需要分两种情况去看

(1)现实中
  • 在现实世界中:先有对象,再有类

  • 世界上肯定是先出现各种各样的实际存在的物体,然后随着人类文明的发展,人类站在不同的角度总结出了不同的种类,如人类、动物类、植物类等概念

  • 也就说,对象是具体的存在,而类仅仅只是一个概念,并不真实存在

(2)程序中
  • 在程序中:务必保证先定义类,后产生对象

  • 这与函数的使用是类似的,先定义函数,后调用函数,类也是一样的,在程序中需要先定义类,后调用类

  • 不一样的是,调用函数会执行函数体代码返回的是函数体执行的结果,而调用类会产生对象,返回的是对象

【四】面对对象编程

  • 关键字 class 声明一个类

  • 在类程序中,特征用变量名标识,功能用函数标识

  • 因而在类中 函数名和变量名

【1】定义类

(1)类名 建议是驼峰体,例如:Student
  • 方式一:class Student(object)

  • 方式二:class Student()

  • 方式三:class Student

复制代码
class Student(object):
    # 类名后面的()参数不写的话默认就是object
    # object:父类
    # 直接定义数据属性
    school_name = "清华"
    
    
    # 函数属性
    def read(self):
        age = 18
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
        
​
# 通过实例化得到一个对象
student = Student()
print(student)      # <__main__.Student object at 0x000001399554FFD0>
# 想用类里面的属性和方法
print(student.school_name)
print(student.read())

【2】类的调用

(1)实例化类,得到对象
复制代码
student_one = Student()
student_two = Student()
​
# 每一次得到的对象都是新的
print(id(student_one))
# 2274496937888
print(id(student_two))
# 2274496937696
(2)如何修改对象的属性
复制代码
# 【1】通过类的名称空间修改属性
# 类的名称空间不允许修改属性
space_class = Student.__dict__
print(space_class, type(space_class))  # <class 'mappingproxy'>
​
# 这两种方式都可以获取
print(space_class['school_name'])
print(space_class.get('school_name'))
​
​
# 【2】修改对象的属性
class Student(object):
    # 数据属性
    school_name = '清华'
​
    # 函数属性
    def read(self):
        age = 18
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
​
​
student = Student()
student_one= Student()
# 添加一个student字典,赋给obj_space
obj_space = student.__dict__
# 添加一个键为name,值为knight的键值对
obj_space['name'] = 'knight'
print(obj_space,type(obj_space))    # {'name': 'knight'} <class 'dict'>
print(obj_space['name'])        # knight
​
# 输出里面定义过的学校名
print(student.school_name)      # 清华
# 输出添加后的name值
print(student.name)             # knight
# student_one是复制的student
print(student_one.school_name)  # 清华
​
​
# 【3】批量修改属性
class Student(object):
    # 数据属性
    school_name = '清华'
​
    # 函数属性
    def read(self):
        age = 18
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
​
​
student_one = Student()
student_two = Student()
# 方式一:通过名称空间字典替换
student_one.__dict__['name'] = 'knight'
# 方式二:通过  对象.属性名=属性值替换
# (1)逐个添加
student_one.name = 'knight'
student_one.age = 18
student_one.gender = 'male'
student_two.name = 'opp'
student_two.age = 19
student_two.gender = 'female'
print(student_one.name)     # knight
print(student_one.age)      # 18
print(student_one.gender)   # male
# (2)批量向对象中添加各自独有的属性值和属性名
def init_obj(obj,name,age,gender):
    obj.name = name
    obj.age = age
    obj.gender = gender
student_one = Student()
student_two = Student()
init_obj(obj=student_one,name='knight',age=18,gender='male')
print(student_one.name)
(3)在类内部初始化自己的参数
复制代码
class Student(object):
    # 数据属性
    school_name = '清华'
​
    def init_obj(self, name, age, gender):  # 这个self就是类的对象本身
        self.name = name
        self.age = age
        self.gender = gender
​
    # 函数属性
    def read(self):
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
        print(f"当前姓名是{self.name}")
        print(f"当前年龄是{self.age}")
        print(f"当前性别是{self.gender}")
student = Student()
# 给值,初始化
student.init_obj(name='knight',age=20,gender='male')
student.read()
(4)魔法方法值初始化方法 __init__
复制代码
class Student(object):
    # 数据属性
    school_name = '清华'
​
    def __init__(self, name, age, gend  er):  # 这个self就是类的对象本身
        self.name = name
        self.age = age
        self.gender = gender
​
    # 函数属性
    def read(self):
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
        print(f"当前姓名是{self.name}")
        print(f"当前年龄是{self.age}")
        print(f"当前性别是{self.gender}")
​
​
# 给值,初始化
student = Student(name='knight',age=20,gender='male')
student.read()
# 需要再添加学生的信息
student_one = Student(name='hyt',age=22,gender='female')
student_one.read()
# 查看类的名称空间
print(student.__dict__) # {'name': 'knight', 'age': 20, 'gender': 'male'}
(5)属性查找顺序
复制代码
class Student(object):
    # 数据属性
    school_name = '清华'
​
    def __init__(self, name, age, gender):  # 这个self就是类的对象本身
        self.name = name
        self.age = age
        self.gender = gender
​
    # 函数属性
    def read(self):
        # self:表示对象自己本身
        print(f"当前学校是{self.school_name}")
        print(f"当前姓名是{self.name}")
        print(f"当前年龄是{self.age}")
        print(f"当前性别是{self.gender}")
​
​
# 给值,初始化
student = Student(name='knight',age=20,gender='male')
print(student.name)
# 可以通过.覆盖原来的值
student.name = 'hyt'    # student.__dict__['name'] = 'hyt'
print(student.name)
​
# 属性查找顺序
print(student.name)
print(student.school_name)
# 查找顺序
# 首先在自己的对象中查找
# 自己找不到就去父类里面找
# 父类没找到就去基类中找
# 如果基类里面也没有,就去object中找
# 否则报错
(6)列表特性回顾
复制代码
num_one_list = [1, 2, 3, 4]
num_two_list = [5, 6, 7, 8]
num_one_list.append(9)
# 每一个列表都是一个单独的对象
print(num_one_list)
print(num_two_list)
​
​
class Student:
    def __init__(self, name):
        self.name = name
​
​
s1 = Student(name='knight')
print(id(s1))
s1.name = 'hyt'
print(id(s1))

【3】类的属性扩展

复制代码
class Duck(Animal,object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
​
    def speak(self):
        print(f"这是一一只鸭子叫{self.name}已经{self.age}岁了")
​
​
duck = Duck(name='tang', age=1)
# 属性介绍
# 【1】获取当前类的名字
print(Duck.__name__)
# 【2】获取类中文档字符串(只能获取三引号中的)
print(Duck.__doc__)
# 【3】获取类的父类
print(Duck.__base__)    # <class '__main__.Animal'>
# 【4】获取类的所有父类
print(Duck.__bases__)   # (<class '__main__.Animal'>, <class 'object'>)
# 【5】获取当前类的名称空间(字典)
print(Duck.__dict__)
# 【6】获取类定义所在的模块名
print(Duck.__module__)  # __main__
# 【7】实例化得到对象
相关推荐
SiYuanFeng8 分钟前
Colab复现 NanoChat:从 Tokenizer(CPU)、Base Train(CPU) 到 SFT(GPU) 的完整踩坑实录
python·colab
炸炸鱼.1 小时前
Python 操作 MySQL 数据库
android·数据库·python·adb
_深海凉_2 小时前
LeetCode热题100-颜色分类
python·算法·leetcode
AC赳赳老秦2 小时前
OpenClaw email技能:批量发送邮件、自动回复,高效处理工作邮件
运维·人工智能·python·django·自动化·deepseek·openclaw
zhaoshuzhaoshu2 小时前
Python 语法之数据结构详细解析
python
AI问答工程师3 小时前
Meta Muse Spark 的"思维压缩"到底是什么?我用 Python 复现了核心思路(附代码)
人工智能·python
zfan5204 小时前
python对Excel数据处理(1)
python·excel·pandas
小饕4 小时前
我从零搭建 RAG 学到的 10 件事
python
老歌老听老掉牙4 小时前
PyQt5+Qt Designer实战:可视化设计智能参数配置界面,告别手动布局时代!
python·qt
格鸰爱童话4 小时前
向AI学习项目技能(六)
java·人工智能·spring boot·python·学习