面对对象

面向对象引入

以小游戏人狗大战为例

步骤一:定义人与狗的数据

person = {
'name': '钢弹',
'age': 18,
'gender': 'male',
'p_type': '猛男',
'attack_val': 800,
'life_val': 99999
dog = {
'name': '龙傲天',
'd_type': '马犬',
'attack_val': 500,
'life_val': 100000
}

"""
通过字典的形式,我们可以定义出所需要的人与狗的数据,但是如果我们这个游戏是回合制游戏,需要多个角色数据时呢
我们需要多次复制同样的数据,来满足游戏对角色的需求,那么以我们目前所学的知识,我们可以封装函数来完成
"""

步骤二:封装函数产生数据

2.1 产生数据的函数

def create_person(name, age, gender, p_type, attack_val, life_val):
   person_dict = {
       'name': name,
       'age': age,
       'gender': gender,
       'p_type': p_type,
       'attack_val': attack_val,
       'life_val': life_val
   }
   return person_dict


def create_dog(name, d_type, attack_val, life_val):
   dog_dict = {
       'name': name,
       'd_type': d_type,
       'attack_val': attack_val,
       'life_val': life_val
   }
   return dog_dict


p1 = create_person('jason', 18, 'male', '猛男', 8000, 99999999)
p2 = create_person('kevin', 28, 'female', '淑女', 100, 800)
d1 = create_dog('小黑', '恶霸', 800, 900000)
d2 = create_dog('小白', '泰迪', 100, 800000)
print(p1, p2)
print(d1, d2)
"""
这样我们通过函数就完成了多个数据的产生,那么游戏就可以开始进行了,但在此之前,我们需要先定好游戏的规则,以代码的形式完成游戏流程
"""

2.2 调用数据完成游戏流程的函数

def person_attack(person_dict, dog_dict):  # 人攻击狗的函数
   print(f"人:{person_dict.get('name')}准备揍狗:{dog_dict.get('name')}")
   dog_dict['life_val'] -= person_dict.get('attack_val')
   print(f"人揍了狗一拳 狗掉血:{person_dict.get('attack_val')} 狗剩余血量:{dog_dict.get('life_val')}")
   
   
def dog_attack(dog_dict, person_dict):  # 狗攻击人的函数
   print(f"狗:{dog_dict.get('name')}准备咬人:{person_dict.get('name')}")
   person_dict['life_val'] -= dog_dict.get('attack_val')
   print(f"狗咬了人一口 人掉血:{dog_dict.get('attack_val')} 人剩余血量:{person_dict.get('life_val')}")
   
   
person_attack(p1, d1)  # 运行游戏
dog_attack(d2, p2)
"""
人:jason准备揍狗:小黑
人揍了狗一拳 狗掉血:8000 狗剩余血量:892000
狗:小白准备咬人:kevin
狗咬了人一口 人掉血:100 人剩余血量:700
这么看来我们的游戏流程已经完成了但是...
"""


person_attack(d1, p1)
dog_attack(p1, d2)

"""
人:小黑准备揍狗:jason
人揍了狗一拳 狗掉血:800 狗剩余血量:99999199
狗:jason准备咬人:小白
狗咬了人一口 人掉血:8000 人剩余血量:792000
当我们反过来输入信息后,狗变成了人,人变成了狗,数据发生了混乱
函数的调用并不明确那个函数是对应哪些数据才可以调用,这时候就要步入新的阶段
>>>:面向对象
"""

面向对象核心思路

那么我们如何来实现人只可以使用人的攻击函数,狗只可以使用狗的攻击函数呢?

——数据与函数绑定
def get_person(name, age, gender, p_type, attack_val, life_val):
    # 产生人的函数(功能)
    def person_attack(person_dict, dog_dict):
        print(f"人:{person_dict.get('name')}准备揍狗:{dog_dict.get('name')}")
        dog_dict['life_val'] -= person_dict.get('attack_val')
        print(f"人揍了狗一拳 狗掉血:{person_dict.get('attack_val')} 狗剩余血量:{dog_dict.get('life_val')}")
    # 表示人的信息(数据)
    person_dict = {
        'name': name,
        'age': age,
        'gender': gender,
        'p_type': p_type,
        'attack_val': attack_val,
        'life_val': life_val,
        'person_attack': person_attack
    }
    return person_dict


def get_dog(name, d_type, attack_val, life_val):
    def dog_attack(dog_dict, person_dict):
        print(f"狗:{dog_dict.get('name')}准备咬人:{person_dict.get('name')}")
        person_dict['life_val'] -= dog_dict.get('attack_val')
        print(f"狗咬了人一口 人掉血:{dog_dict.get('attack_val')} 人剩余血量:{person_dict.get('life_val')}")
    dog_dict = {
        'name': name,
        'd_type': d_type,
        'attack_val': attack_val,
        'life_val': life_val,
        'dog_attack': dog_attack
    }
    return dog_dict


person1 = get_person('jason', 18, 'male', '猛男', 8000, 99999999)
dog1 = get_dog('小黑', '恶霸', 800, 900000)
person1.get('person_attack')(person1, dog1)
"""
人:jason准备揍狗:小黑
人揍了狗一拳 狗掉血:8000 狗剩余血量:892000
我们通过第一层函数,实现了角色信息的生成,由于函数内部的名称只能在内部调用,所以我们将人与狗各自的攻击函数放入到第一层函数中,并把函数名作为键值对的值存放在用户的字典中,那么当我们得到返回的字典时,就只需要将对应的攻击函数取出来即可实现函数调用,同时我们也实现了功能与数据的绑定,这也就是面向对象的核心
"""

编程思想

所谓的编程思想,或者说编程方式,只有两种——面向过程与面向对象

面向过程,顾名思义,更注重过程,放到编程来讲,面向过程是当我们看到需求时,要将需求拆分成各个组成部分,就以我们之前写的ATM为例,当我们需要登录时,我们需要先去校验用户是否存在,然后验证用户输入的密码是否正确,需要一步步完成各个组成部分,将每部分功能都写出来,主要的侧重点在于拆分与完成各组成部分的过程,并且随着每个部分的深入,问题的解决越来越简单

而面向对象,则需要引用到python中一切皆对象的概念,对象即容器,可以存放数据与方法的容器,我们可以理解为容器中既有数据值,又有函数,就像我们常用的列表,字典,他们既有数据值,也有内置方法,这就是容器,面向对象编程时,我们不需要再去一步步拆分,只需要创建好对象,任由其在被需要的时候调用,至于怎么发展就不是我们需要考虑的事情了

面向对象之类与对象

对象就是数据和方法的结合体,而类是在多个对象需要被定义时,在这些对象中包含的相同的数据和方法,我们就可以用类一次性接收,不需要在每个对象中重复编写

任何事物只有在数量达到一定程度后,根据他们相同的特征划分为相同的相同的类,比如人类,犬类,类是一个宽泛的概念,代表着这个类中每个个体所具有的共性

在现实生活中,只有当个体的对象达到一定数量后才会产生类的概念,而在编程中,如果需要产生对象时,我们需要先定义出类,才可以从这个类中产生我们需要的对象

类与对象的创建

面向对象并不是真正意义上的新技术,而是为了作为区分设计的新的语法结构,在python中,一定要先定义类,才可以用类产生对象

类的语法结构

class 类名:
        '''代码注释'''
   		对象公共的数据
        对象公共的功能
	"""
	1.class是定义类的关键字
 	2.类名的命名与变量名几乎一致,需要注意的时候首字母推荐大写用于区分
 	3.数据:变量名与数据值的绑定,功能(方法)其实就是函数
 	4.类与对象,对象才是关键,这也是面向对象编程的关键所在
 	"""

类的定义与调用

类在定义阶段会执行类体代码,但是产生对象仅仅属于类的局部名称空间,外界无法直接调用

以定义选课系统为例

# 需求:清华大学学生选课系统
# 定义类
class Student:
    # 对象公共的数据
    school_name = '清华大学'

    # 对象公共的功能
    def choice_course(self):  
# self 代表类的实例,self在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数,在某种意义上,self即类中产生的对象本身
        print('学生选课功能')
# 查看名称空间
print(Student.__dict__)  # __dict__只是python提供的一种查看名称空间的方式,并不意味着类就是字典,只不过是这个名称空间以字典的形式呈现
print(Student.__dict__.get('school_name'))
print(Student.__dict__.get('choice_course'))


'''在面向对象中 类和对象访问数据或者功能 可以统一采用句点符'''
print(Student.school_name)
print(Student.choice_course)
# 类只有在调用时才会产生对象
    
    
'''类名加括号就会产生对象,并且每执行一次都会产生一个全新的对象'''
obj1 = Student()  # 变量名obj1接收类名加括号之后的返回值(结果)
obj2 = Student()
obj3 = Student()
print(obj1, obj2, obj3)
print(obj1.__dict__)  # 在没有定义属性前,类的名称空间中是空的
print(obj2.__dict__)
print(obj3.__dict__)
print(obj1.school_name)  # 当我们通过.的方式调用类中的公共变量名时,会直接输出该变量名绑定的数据值
print(obj2.school_name)
print(obj3.school_name)
Student.school_name = '家里蹲大学'  # 我们也可以通过按照字典改值的方式修改类中的公共数据
print(obj1.school_name)
print(obj2.school_name)
print(obj3.school_name)
'''数据和功能,也可以统称为属性,数据就是类中存放的绑定给对象的属性名,功能就类中存放的可供对象使用的方法'''

对象独有的数据

就像人类同样是在人这一个大类中,个体却各有差异一样,类中的对象也有其独有的数据

以选课系统为例

class Student:
    # 对象公共的数据
    school_name = '清华大学'

    # 对象公共的功能
    def choice_course(self):
        print('学生选课功能')


obj1 = Student()
obj2 = Student()
'''推导流程1:每个对象手动添加独有的数据'''
print(obj1.__dict__)
obj1.__dict__['name'] = 'jason'
obj1.__dict__['age'] = 18
obj1.__dict__['hobby'] = 'study'
print(obj1.__dict__)
print(obj1.name)
print(obj1.age)
print(obj1.hobby)
print(obj2.__dict__)
obj2.__dict__['name'] = 'kevin'
obj2.__dict__['age'] = 28
obj2.__dict__['hobby'] = 'music'
print(obj2.__dict__)
print(obj2.name)
print(obj2.age)
print(obj2.hobby)
# 当我们使用类中自带的方法一个一个添加数据时,代码需要不断地重复,这种情况下,我们就需要用到函数
'''推导流程2:将添加对象独有数据的代码封装成函数'''
def init(obj, name, age, hobby):
    obj.__dict__['name'] = name
    obj.__dict__['age'] = age
    obj.__dict__['hobby'] = hobby
stu1 = Student()
stu2 = Student()
init(stu1, 'jason', 18, 'music')
init(stu2, 'kevin', 29, 'read')
print(stu1.__dict__)
print(stu2.__dict__)
# 当我们函数封装完毕后,我们在添加数据时,这个函数不只有现在的学生对象可以用
# 其他类产生的对象也可以用,那么为了实现只有当前类产生的对象可以采用这种方法添加数据
# 我们只能将这个函数放到类中
'''推导流程3:给学生对象添加独有数据的函数只有学生对象有资格调用'''
class Student:
    # 对象公共的数据
    school_name = '清华大学'

    # 专门给学生添加独有数据的功能
    def init(obj, name, age, hobby):
        obj.__dict__['name'] = name
        obj.__dict__['age'] = age
        obj.__dict__['hobby'] = hobby

#     # 对象公共的功能
    def choice_course(self):
        print('学生选课功能')
stu1 = Student()
Student.init(stu1, 'jason', 18, 'music')
stu2 = Student()
Student.init(stu2, 'kevin', 29, 'read')
print(stu1.__dict__, stu2.__dict__)
# 当我们将函数放到类中之后,每次添加数据还需要再调用init函数,那么是不是可以更加简便
'''推导步骤4:init方法变形'''
class Student:
    # 对象公共的数据
    school_name = '清华大学'
                                                            
    # 专门给学生添加独有数据的功能  __init__在类产生对象的过程中自动触发
    def __init__(obj, name, age, hobby):
        obj.__dict__['name'] = name
        obj.__dict__['age'] = age
        obj.__dict__['hobby'] = hobby
    # 对象公共的功能
    def choice_course(self):
        print('学生选课功能')

stu1 = Student('jason', 18, 'read')
print(stu1.__dict__)
print(stu1.name)
print(stu1.school_name)
# 当这一步完成后,我们可以省去调用函数这一步,但是还是需要在类中使用obj.__dict__[]的方法来添加数据,那么这个时候,self就派上用场了,在这个时候,self代表的就是类产生的对象本身
'''推导步骤5:变量名修改'''
class Student:
    # 对象公共的数据
    school_name = '清华大学'

    # 专门给学生添加独有数据的功能  类产生对象的过程中自动触发
    def __init__(self, name, age, hobby):
        self.name = name  # self.__dict__['name'] = name
        self.age = age
        self.hobby = hobby

    # 对象公共的功能
    def choice_course(self):
        print('学生选课功能')

stu1 = Student('jason', 18, 'read')
print(stu1.name)
print(stu1.school_name)
# 当self产生作用后,那么我们也就可以用self加句点符来添加相应的数据,类体代码的兼容性也会更强

对象独有的功能

参照上述方法,我们也可以得出,对象也可以有自己独有的功能或函数

class Student:
    # 对象公共的数据
    school_name = '清华大学'

    # 专门给学生添加独有数据的功能  类产生对象的过程中自动触发
    def __init__(self, name, age, hobby):
        self.name = name  # self.__dict__['name'] = name
        self.age = age
        self.hobby = hobby

    # 对象公共的功能
    def choice_course(self):
        print(f'学生{self.name}正在选课')


stu1 = Student('jason', 18, 'music')
stu2 = Student('kevin', 28, 'read')
# 1.直接在全局定义功能  该函数就不是学生对象独有的了
def eat():
    print('吃东西')
stu1.eat = eat
print(stu1.__dict__)
stu1.eat()
# 2.只能将函数放在类中 但是类中的函数又是对象公共的
'''定义在类中的功能,默认就是绑定给对象使用的,哪个对象来调用,哪个对象就是主导'''
Student.choice_course(123)  # 类调用需要自己传参数
stu1.choice_course()  #  choice_course(stu1)  对象调用会自动将对象当做第一个参数传入

stu1.choice_course()
stu2.choice_course()
# 当self产生作用时,对象本身就会被当作参数传递到该共功能中

# 对象修改数据值
stu1.name = 'tony'  # 当点的名字已经存在的情况下 则修改对应的值
# 对象新增数据值
stu1.pwd = 123  # 当点的名字不存在的情况下 则新增数据
print(stu1.__dict__)

PS:面向对象编程就像为我们搭建了一个工具箱,而其中不同的函数就相当于不同类型的工具,我们在取用工具时,我们就是不同的对象,当我们使用工具时,工具会与我们绑定,这个时候这个工具就是我们的专用工具,也就是对象的独有功能,当我们使用完工具放回工具箱后,谁再来用,怎么用跟我们就关系不大了,这样的好处就是工具不会丢,这样理解,类与对象的存在也正是为了程序有更好的可拓展性和更高的兼容性

原文地址:http://www.cnblogs.com/lf17603472426/p/16852539.html

发表评论

您的电子邮箱地址不会被公开。