20、面向对象编程

一、面向对象的概念

面向对象,重点在于对象二字,对象指的是盛放相关的数据与功能的容器
基于该思想编写程序就在创造一个个的容器来把相关的东西盛到一起

优点:扩展性强
缺点:加大了编程的复杂度

二、类与对象

何谓对象,我们已经知道了,那又是什么?类即类别、种类,是面向对象设计最重要的概念。

具有相同或相似性质的对象的抽象就是类。因此,对象的抽象是类,类的具体化就是对象,也可以说类的实例是对象。

打个比方,有一个女生,她沉鱼落雁,闭月羞花,明眸善睐,国色天香......现在有一个叫做桥本环奈的女生具备上述所有条件,
那么桥本环奈就是我的对象,那些条件就可以理解为类,类是确定对象将会拥有的特征(属性)和行为(方法),它不是具体客观存在的东西。
而在编程里,对象是用来存放数据与功能的容器,那么类则是用来存放多个对象相同的数据与功能的容器。
所以!我另外一个对象叫杨超越,她也沉鱼落雁...很显然,我的两个对象,桥本环奈和杨超越的容貌特征是共同的属性,所以她俩的特征就是一个类,兄弟萌你们懂了吗

总结一下类的特点:

类是对象的类型。

类是具有相同属性和方法的一组对象集合(一个类可对应多个对象)。

1、类的定义

class 类名:
    代码块
# 如:
class A:
    pass
# 这里定义了一个非常简单的类,名为 A。pass 是占位符,表示什么都不做或什么都没有。

2、类的定义阶段发生的三件事情

1、会执行类体的代码
2、会产生一个类的名称空间,用来将类体代码运行过程中产生的名字都丢进去
3、将名称空间的内存地址绑定给类名

三、类的使用操作

假如现在我们有一帮学生,我们要存放他们的信息,在没有学习类之前呢,我们只能一个个重复的存,但其实除了少部分信息,他们的大部分信息基本都是一样的,那小子我们可以把他们归为一类,把他们一样的信息存放在一个公共部分‘类’里,把他们独有的信息放在‘对象’里

class Student:
    # 1.数据的定义
    school = '加里敦大学'  # 共同的特征:(来自同一个学校)

    # 2.功能的定义
    def stu_info(self):
        print('学生信息: 名字:%s 年龄:%s 性别:%s' % (
            self['name'],
            self['age'],
            self['gender'],
        ))
# self,哪个对象调用类,self就是对象自己,self可以是任意名称,但约定成俗的叫法就是self

1、属性访问

print(Student.__dict__)  # 查看类的名称空间

# 属性访问的语法(类名.函数名(变量名))
print(Student.school)  # 1.访问数据属性
print(Student.set_info)  # 2.访问函数属性

2、调用类产生对象

类的调用是类的实例化,也就是造出一个对象,是告诉Python这个类与对象进行关联,所以直接运行什么也没有。我们现在去查看对象的内容,会发现是两个空字典,因为我们现在还没有往这两个对象里丢东西,所以它当然是空的

stu1 = Student() # 造出第一个对象
stu2 = Student() # 造出第二个对象

print(stu1.__dict__)
print(stu2.__dict__)
# 运行结果
{}
{}

3、定制对象自己独有的属性

# 学生一
stu1.name = 'poco'
stu1.age = 18
stu1.gender = 'male'
# 学生二
stu2.name = 'wendy'
stu2.age = 20
stu2.gender = 'female'

print(stu1.__dict__)
print(stu2.__dict__)
# 运行结果
{'name': 'poco', 'age': 18, 'gender': 'male'}
{'name': 'wendy', 'age': 20, 'gender': 'female'}

用上述的方法就可以往这两个容器存放东西啦,再次查看内容,发现字典里已经有存入的信息了

4、__init__的使用

虽然我们实现了为对象添加独有的属性,但这种方法也太麻烦了,如果现在有N多个对象,那我们就得用很多行代码来一一定制对象的属性。

所以,我们就要使用一个叫_init_(固定的语法),

class Student:
    # 1.数据的定义
    school = '加里敦大学'  # 共同的特征:(来自同一个学校)
	
    # 这段代码在定义时并不会运行,只会在调用时运行
    def __init__(self, x, y, z):
        self.name = x
        self.age = y
        self.gender = z

    # 2.功能的定义
    def stu_info(self):
        print('学生信息: 名字:%s 年龄:%s 性别:%s' % (
            self['name'],
            self['age'],
            self['gender'],
        ))


stu1 = Student('poco',18,'male')
stu2 = Student('wendy',20,'female')

print(stu1.__dict__)
print(stu2.__dict__)
# 调用类的过程又称作实例化,会发生三件事
1.先产生一个空对象
2.会自动调用类中的__init__方法,然后将空对象已经调用类时括号内传入的参数一同传给__init__
3.返回初始化完的对象

四、对象属性的其他知识

class Student:
    school = '山东蓝翔高级技工学校'

    def __init__(self, name, age, gender, courses=None):
        if courses is None:
            courses = []
        self.name = name
        self.age = age
        self.gender = gender
        self.courses = courses

    def choose_course(self, course):
        self.courses.append(course)
        print('学生 %s 选课成功 %s' % (self.name, self.courses))


stu1_obj = Student('poco', 18, 'male')  # 实例化对象
stu2_obj = Student('wendy', 20, 'male')

1、类的两种属性

类中的属性分为两种,一种是数据属性(就是变量),一种就是函数属性,

# 1.数据属性
print(Student.school)

# 2.函数属性
print(Student.choose_course)
Student.choose_course(stu1_obj, 'Python开发')

# 运行结果
山东蓝翔高级技工学校

<function Student.choose_course at 0x000002A604DB50D0>
学生 poco 选课成功 ['Python开发']

类中的数据属性,函数属性,都是为所有对象准备的,当然,类也可以使用,

所以,类或者对象,访问属性的内容一样,内存地址也一样

print(Student.school,id(Student.school))
print(stu1_obj.school,id(stu1_obj.school))
print(stu2_obj.school,id(stu1_obj.school))
# 运行结果
山东蓝翔高级技工学校 2111351492656
山东蓝翔高级技工学校 2111351492656
山东蓝翔高级技工学校 2111351492656
# 类的属性是直接共享给所有对象使用

我们若更改某一个对象的属性,类和其他的对象属性不变

stu1_obj.school = '新东方厨师学校'  # 把对象stu1_obj的数据属性改掉
print(stu1_obj.school)
print(stu2_obj.school)
print(Student.school)
# 运行结果
新东方厨师学校
山东蓝翔高级技工学校
山东蓝翔高级技工学校

但如果直接更改类的属性,其他对象的属性也跟着改变了

Student.school = '新东方厨师学校'  # 把类Student的数据属性改掉
print(stu1_obj.school)
print(stu2_obj.school)
# 运行结果
新东方厨师学校
新东方厨师学校

2、属性查找

对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找……至于子类和父类是什么,我们会在继承中介绍......

3、绑定方法

类的函数属性是绑定给对象用的,类去访问函数,相当于普通函数,但对象是访问函数,就是绑定方法,绑定方法的特殊之处在于会自动传参,通过类调用函数需要把对象传入参数,但对象访问函数,相当于自己自动把自己传进去了。

# 我们用类访问函数时,还需要把对象传入第一个参数,实在是太麻烦
Student.choose_course(stu1_obj, 'Python开发')

# 如果用绑定方法对象,用对象直接访问函数,就不用把自己传进去了
stu1_obj.choose_course('Python开发')
stu2_obj.choose_course('linux运维')

# 绑定方法的运行结果
学生 poco 选课成功 ['Python开发']
学生 wendy 选课成功 ['linux运维']

所以 类的函数总是会有一个self参数,哪个对象去调用类的函数属性,那么,这个参数就是调用这个函数属性的对象自己,所以self我们是不需要为其传参的,他的参数就是对象本身。

所以绑定方法就是Python设计出来方便对象访问类的函数属性的。

4、绑定方法和非绑定方法2.0版

在类内部,为某个函数使用装饰器 @classmethod后,该函数就绑定到了类,总之绑定到类的方法就是专门给类用的,
但其实对象也可以调用,只不过自动传入的第一个参数仍然是类,也就是说这种调用是没有意义的,并且容易引起混淆

而 @staticmethod 修饰的方法即为非绑定方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。
简单来说,就是一个函数,跟谁都没关系,就是个普通函数,但是想放到类中,便于管理,跟对象和类都没关系,就把它写成静态方法
posted @ 2021-04-10 16:04  黑影Poco  阅读(65)  评论(0)    收藏  举报