面向对象、类

一、面向对象

什么是面向对象?

  面向对象是一门编程思想!

  

  面向过程编程思想与面向对象编程思想对比:

    - 面向过程编程思想:

      核心是 “过程”二字,过程是指解决问题的步骤,即先干什么再干什么!

      基于该编程思想编写程序,就好比在设计一条工厂流水线,一种机械式的思维方式

      优点:

        将复杂的问题流程化,进而简单化

      缺点:

        牵一发而动全身,程序的可扩展性差

    - 面向对象编程思想:

      核心是 “对象” 二字,对象指的是“特征与技能”的结合体。

      基于该编程思想编写程序,就好比把自己当做一个上帝在创造世界,一种“上帝式”的思维方式

      优点:

        可扩展性高

      缺点:

        面向对象编写程序的复杂程度比面向过程高

  注意:编程思想仅仅是一门思想,与任何技术无关

 

 

二、类

1、什么是类?

  类指的是类型、类别。

  在两种角度去看待类:

    - 现实世界中:

      - 先有一个个对象,经过社会的文明发展,随之总结出类,对象是实际存在的,而类是抽象产生的

    - python程序中:

      - 必须先由类,再通过调用类产生对象

 

  对象指的是“特征与技能”的结合体, 类指的是一系列“对象之间相同的特征与技能”的结合体

 

2、如何定义类?

  如何写类并产生对象:

    - 先从现实世界中通过一个个对象总结出类

    - 然后再定义类,后调用产生对象。

 

  比如 “选课系统”:

    选课系统 - 学生类:

      - 学生对象1:

        特征:

          - 姓名:tank

          - 性别:female

          - 年龄:95

          - 学校:家里蹲

        技能:

          - 技术:python

          - 学习:learn

          - 选课:course

 

      - 学生对象2

        特征:

          - 姓名:jason

          - 性别:female

          - 年龄:99

          - 学校:家里蹲

        技能:

          - 技术:python

          - 学习:learn

          - 选课:course

 

3、定义类的语法

  语法:

    class 关键字:帮你产生类

 

    class 类名:

      - 对象之间相同的特征

        - 学校

        school = "家里蹲"

      - 对象之间相同的技能

        - python

          def Python():

            pass

        - learn

          def Learn():

            pass

        - course

          def Course():

            pass

 

  类名的规范:

    - 驼峰命名法(推荐)

 

  定义一个学生类并对属性进行增删查改:

# 定义一个家里蹲学生类
class JldStudent:    # 类名指向的是类的内存地址
    # 学生相同的特征
    # 在类中的特征(即变量)称之为“属性”
    school = "OldBoy"


    # 注意:在类内部定义函数,会默认产生一个参数self
    # 学生相同的技能(即函数)称之为“方法”
    def learn(self):    # self此处当做一个形参
        print("learning...")


# 查看类的名称空间
print(JldStudent.__dict__)
print(JldStudent.__dict__["school"])    # 可调用属性
print(JldStudent.__dict__["learn"])    # 获取learn方法对象
JldStudent.__dict__["learn"](123)    # 方法对象+(),相当于执行learn函数(方法)

# 类提供了一种特殊获取名字的方式  “类名.名字”的方式
#
print(JldStudent.school)
JldStudent.learn(12)

#
JldStudent.school = "Cld"
print(JldStudent.school)

#
del JldStudent.school
# print(JldStudent.school)    # AttributeError: type object 'JldStudent' has no attribute 'school'

#
JldStudent.age = 18
print(JldStudent.age)

  执行结果:

{'__module__': '__main__', 'school': 'OldBoy', 'learn': <function JldStudent.learn at 0x0000026D35CD97B8>, '__dict__': <attribute '__dict__' of 'JldStudent' objects>, '__weakref__': <attribute '__weakref__' of 'JldStudent' objects>, '__doc__': None}
OldBoy
<function JldStudent.learn at 0x0000026D35CD97B8>
learning...
OldBoy
learning...
Cld
18

 

4、类的名称空间

  - 类的名称空间:

    在定义阶段时产生,会将类中所有的名字,扔进类的名称空间

  - 函数的名称空间:

    在调用函数时产生,函数调用结束后销毁

 

 

三、对象

1、对象的产生

  对象名=类名()   --->  调用类产生对象

  类的名称空间在定义时产生,对象的名称空间在调用类时产生

 

  调用类产生对象的过程称之为类的实例化,对象称之为一个类的实例

 

  定义一个类:

class Student:
    # 学校 ---> 属性
    school = "Jld"
    # 技能 ---> 方法
    def learn(self):
        print(self)    # 打印输出为 <__main__.Student object at 0x00000000021B6248>,是一个对象
        print("learning...")


# 获取对象,产生对象
obj = Student()
print(obj)    # 打印输出为 <__main__.Student object at 0x00000000021B6248>,也是一个对象

# 对象调用类内部的名字(属性)
print(obj.school)
# 对象调用类内部的函数(方法),无需传入参数:会将对象当做第一个参数传给该函数(方法)
obj.learn()    # 对象的绑定方法,无需传参

  执行结果:

<__main__.Student object at 0x000001BE191C6908>
Jld
<__main__.Student object at 0x000001BE191C6908>
learning...

 

  由对象来调用类内部的函数,称之为对象的绑定方法。

  对象的绑定方法特殊之处:会将对象当做第一个参数自动传给该函数(方法),所以对象调用类内部的函数时无需传参

 

2、为对象添加独有的属性

  定义一个类:

class Student:
    # 学校  --> 属性
    school = "Jld"

    def __init__(self, name, sex, age):    # 参数:obj1, "张三", "female", 84
        print(self.__dict__)
        # 给对象添加新的属性
        self.name = name    # stu1.name = "张三"
        self.sex = sex    # stu1.sex = "female"
        self.age = age    # stu1.age = 84
        print(self.__dict__)

    # 技能 ---> 方法
    def learn(self):
        print("learning...")

# obj1 = Student()    # Student(obj1) ---> __init__(self) ---> self==obj1
# obj2 = Student()    # Student(obj2) ---> __init__(self) ---> self==obj2
# obj3 = Student()    # Student(obj3) ---> __init__(self) ---> self==obj3


# 给对象添加独有的属性: # 第一种方法(很麻烦):调用类后,为对象传入对象独有的特征(属性) obj1.name = "张三" obj1.sex = "female" obj1.age = 84 # 第二种方法:调用类时,为对象传入对象独有的特征(属性) # __init__(self, name, sex, age):obj1 --> self "张三" --> name "female" --> sex 84 --> age # 调用类时:会将对象当做第一个参数,并与括号内所有的参数一并传给__init__() obj1 = Student("张三", "female", 84)

  执行结果:

{}
{'name': '张三', 'sex': 'female', 'age': 84}

 

注意:凡是在类内部定义的.__或者__结尾的方法都有特殊意义

  __init__():在类内部定义的方法,在调用类时触发,会自动将对象当做第一个参数自动传入并执行

 

3、对象名字的查找顺序

  对象名字的查找顺序:

    ① 对象.属性,会先找对象自己的

    ② 若对象没有,会去找类的

    ③ 对象没有,类也没有,就会报错

 

  定义一个类:

class people:
    country = "China"
    name = "李四"
    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age

    def run(self):
        print("running...")



obj1 = people("张三", "female", 95)
print(obj1.name)    # 张三   找对象自己的name属性
print(obj1.country)    # China   对象没有,找类中的属性
# 报错:AttributeError: 'people' object has no attribute 'json'
print(obj1.json)    # 对象没有,类也没有,就报错

 

4、一切皆对象

  在python中一切皆对象

  比如:python的八大数据类型都是类

    定义数据类型时,内部会自动调用相应的类,然后产生对象

"""
在python中一切皆对象
"""
class foo:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z


# 产生对象
# 调用类产生对象的过程称之为类的实例化,对象称之为一个类的实例

foo_obj = foo(10, 20, 30)
print(foo_obj)

# 查看 字符串 类型
print(type(str))    # <class 'type'>
# 查看 列表 类型
print(type(list))    # <class 'type'>
# 查看 字典 类型
print(type(dict))    # <class 'type'>
# 查看 元组 类型
print(type(tuple))    # <class 'type'>
# 查看 浮点型 类型
print(type(float))    # <class 'type'>
# 查看 整型 类型
print(type(int))    # <class 'type'>
# 查看 布尔值 类型
print(type(bool))    # <class 'type'>

# 除了这些还有很多都是类,既然是类,就可以是对象,所以在python中一切皆对象

  执行结果:

<__main__.foo object at 0x0000014471D71C88>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>
<class 'type'>

 

 

四、根据面向对象编程编写一个“人狗大作战”例子

"""
需求:有一个人对象,狗对象,狗咬人,人打狗

- 对象人1
    - 特征
        - 生命:1000
        - 名字:name = "张三"
        - 攻击力:arg
    - 技能
        - 打:hit
- 对象人2
    - 特征
        - 生命:950
        - 名字:name = "李四"
        - 攻击力:arg
    - 技能
        - 打:hit

- 抽象出类
    - 人类:
        - 相同特征
            - 生命
        - 相同特征
            - 打




- 狗对象1
    - 特征
        - 生命值:150
        - 名字:name = "二哈"
        - 品种:dog_type = "哈士奇"
        - 攻击力:arg
    - 技能
        - 咬:bite
- 狗对象2
    - 特征
        - 生命值:250
        - 名字:name = "小短腿"
        - 品种:dog_type = "柯基"
        - 攻击力:arg
    - 技能
        - 咬:bite

- 抽象出类
    - 狗类:
        - 相同特征
            - 生命
        - 相同特征
            - 咬
"""


import time

# 人类
class People:
    def __init__(self, name, life, arg):
        self.name = name
        self.life = life
        self.arg = arg

    # 人对象调用hit时,传入狗对象
    def hit(self, dog_obj):
        print(f"[{self.name}]要开始打[{dog_obj.name}]了")
        # 减掉狗对象的生命值   值为人对象的攻击力
        dog_obj.life -= self.arg
        print(f"[{dog_obj.name}]的生命值减掉:[{self.arg}],剩余血量为:[{dog_obj.life}]")

        if dog_obj.life <= 0:
            print(f"[{dog_obj.name}]已经没了")
            return True

# 狗类
class Dogs:
    def __init__(self, name, life, dog_type, arg):
        self.name = name
        self.life = life
        self.dog_type = dog_type
        self.arg = arg

    # 狗对象调用bite时,传入人对象
    def bite(self, p_obj):
        print(f"[{self.name}]要开始咬[{p_obj.name}]了")
        # 减掉人对象的生命值   值为狗对象的攻击力
        p_obj.life -= self.arg
        print(f"[{p_obj.name}]的生命值减掉:[{self.arg}],剩余血量为:[{p_obj.life}]")

        if p_obj.life <= 0:
            print(f"[{p_obj.name}]已经没了")
            return True



p1 = People("张三", 1000, 50)    # 人对象
d1 = Dogs("二哈", 150, "哈士奇", 200)    # 狗对象


while True:
    # 开始狗咬人,人打狗
    res1 = d1.bite(p1)
    if res1:
        break

    time.sleep(1)    # 休眠1秒

    res2 = p1.hit(d1)
    if res2:
        break

    time.sleep(1)    # 休眠1秒

  执行结果:

[二哈]要开始咬[张三]了
[张三]的生命值减掉:[200],剩余血量为:[800]
[张三]要开始打[二哈]了
[二哈]的生命值减掉:[50],剩余血量为:[100]
[二哈]要开始咬[张三]了
[张三]的生命值减掉:[200],剩余血量为:[600]
[张三]要开始打[二哈]了
[二哈]的生命值减掉:[50],剩余血量为:[50]
[二哈]要开始咬[张三]了
[张三]的生命值减掉:[200],剩余血量为:[400]
[张三]要开始打[二哈]了
[二哈]的生命值减掉:[50],剩余血量为:[0]
[二哈]已经没了

 

 

五、面向对象总结

  面向对象:

    核心是“对象”,对象指的是特征与技能的结合体

    基于该编程思想编写程序,就好比在创造世界,一种上帝式的思维方式

 

    优点:

      可扩展性强

    缺点:

      编写复杂难度较面向过程高

1、类的实例化:调用类的过程称之为类的实例化,产生的对象也可以称之为类的一个实例

  调用类产生对象发生的事情:

    ① 会产生一个空对象的名称空间

    ② 会自动触发__init__,并且会将对象当做第一个参数传入

    ③ 会将调用类括号内的参数一并传给__init__()

# 定义一个类
class
People: national = "han" def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex # 注意:看到self就应该知道是对象本身,在这里就是下面代码中的p_obj对象 def learn(self): print("learning...") p_obj = People("张三", 184, "female") print(p_obj.name, p_obj.age, p_obj.sex)

  执行结果:

张三 184 female

 

2、查看类与对象的名称空间:类.__dict__      对象.__dict__

# 使用上面People类执行下列代码

print
(People.__dict__) # 查看类的名称空间 print(p_obj.__dict__) # 查看对象的名称空间

  执行结果:

{'__module__': '__main__', 'national': 'han', '__init__': <function People.__init__ at 0x000001B4D9BC96A8>, 'learn': <function People.learn at 0x000001B4D9BC9620>, '__dict__': <attribute '__dict__' of 'People' objects>, '__weakref__': <attribute '__weakref__' of 'People' objects>, '__doc__': None}
{'name': '张三', 'age': 184, 'sex': 'female'}

 

3、类或对象的属性操作:增、删、查、改

# 使用上面People类执行下列代码

# 类的属性操作
People.sal = 3000    #
People.number = 1    #
del People.number    #
People.age = 60    #
print(People.age)    #

# 对象的属性操作
p_obj.county = "China"    #
del p_obj.sex    #
p_obj.name = "李四"    #
print(p_obj.name)    #

  执行结果:

4500
李四

 

4、类中数据属性(类中的变量):类中的属性是给对象使用的,对象引用类中的属性,指向的都是类中同一个内存地址

# 使用上面People类执行下列代码

p_obj1 = People("王五", 84, "female")
p_obj2 = People("赵六", 85, "male")
p_obj3 = People("孙七", 86, "female")
print(p_obj1.national, id(p_obj1))
print(p_obj2.national, id(p_obj2))
print(p_obj3.national, id(p_obj3))

  执行结果:

han 2612115777632
han 2612115777744
han 2612115777800

 

5、类中的方法(类中的函数):类中的方法是给对象使用的,由对象来调用就会将方法绑定给不同的对象,并且会将对象当做第一个对象传入

# 使用上面People类执行下列代码

p_obj1 = People("王五", 84, "female")
p_obj2 = People("赵六", 85, "male")
p_obj3 = People("孙七", 86, "female")

print(People.learn)
print(p_obj1.learn)
print(p_obj2.learn)
print(p_obj3.learn)

  执行结果:

<function People.learn at 0x0000022590CA9620>
<bound method People.learn of <__main__.People object at 0x0000022590CBA860>>
<bound method People.learn of <__main__.People object at 0x0000022590CBA8D0>>
<bound method People.learn of <__main__.People object at 0x0000022590CBA908>>

 

6、对象属性的查找顺序:先从对象自己的名称空间找 ---> 类的名称空间查找

# 使用上面People类执行下列代码

print(p_obj1.national)    # 从类中查找
print(p_obj1.national2)    # 类中也没有,报错

 

7、对象绑定方法的特殊之处

  ① 会将对象当做第一个参数传入

  ② 若对象的绑定发放中还有其他参数,会一并传入。

 

8、一切皆对象:在python3中,类即类型

# 使用上面People类执行下列代码

print(type(p_obj))    # <class '__main__.People'>
str1 = "orange"
print(type(str1))    # <class 'str'>
list1 = [1, 2, 3]
print(type(list1))    # <class 'list'>

  执行结果:

<class '__main__.People'>
<class 'str'>
<class 'list'>
posted @ 2020-10-23 23:20  chchcharlie、  阅读(310)  评论(0编辑  收藏  举报