面向对象——类,封装

什么是对象?

  • 对象是内存中专门用来存储数据的一块区域。
  • 对象中可以存放各种数据(比如:数字、布尔值、代码)
  • 对象由三部分组成:
    1.对象的标识(id)
    2.对象的类型(type)
    3.对象的值(value)

面向对象(oop)

  • Python是一门面向对象的编程语言
  • 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的
  • 面向过程的编程的语言

    • 面向过程指将我们的程序的逻辑分解为一个一个的步骤,
      通过对每个步骤的抽象,来完成程序
    • 例子:

      • 孩子上学
        1.妈妈起床
        2.妈妈上厕所
        3.妈妈洗漱
        4.妈妈做早饭
        5.妈妈叫孩子起床
        6.孩子上厕所
        7.孩子要洗漱
        8.孩子吃饭
        9.孩子背着书包上学校
    • 面向过程的编程思想将一个功能分解为一个一个小的步骤,
      我们通过完成一个一个的小的步骤来完成一个程序
    • 这种编程方式,符合我们人类的思维,编写起来相对比较简单
    • 但是这种方式编写代码的往往只适用于一个功能,
      如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,
      所以它可复用性比较低,并且难于维护
  • 面向对象的编程语言

    • 面向对象的编程语言,关注的是对象,而不关注过程
    • 对于面向对象的语言来说,一切都是对象
    • 例子:
      1.孩他妈起床叫孩子上学

    • 面向对象的编程思想,将所有的功能统一保存到对应的对象中
      比如,妈妈功能保存到妈妈的对象中,孩子的功能保存到孩子对象中
      要使用某个功能,直接找到对应的对象即可
    • 这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。
    • 但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点
  • 简单归纳一下,面向对象的思想
    1.找对象
    2.搞对象

类(class)

  • 相当于一个模板,或者蓝图,用来创建对象
  • int,float,bool都是类,但是他们都是自带的类,有时候不能满足需求,所以需要自定义
  • 我们创建的类使用大驼峰命名法,即大写字母开头,其后每个单词首字母大写。
  • 类也属于对象,类属于'type'类型的对象

类的定义

  • 类和对象是对现实生活中事物的抽象

  • 所有事物都由两部分构成:

    1. 数据(属性)
    2. 行为(方法)
  • 在类中,可以自定义函数和变量,变量会成为实例们的公共属性,所有实例均可以访问,函数也会成为公共函数,可以使用实例名.函数名的方法调用。

  • 调用方法时,会将本身传入参数,因此定义任意函数必须写一个参数,通常这个参数规定为'self'

  • 注意:一般情况下,属性保存到实例对象中,而方法保存到类对象中

    class Person():
        def function_1(self, a, b, ...):
            pass
        def function_2(self, a, b, ...):
            pass
        def function_3(self, a, b, ...):
            pass
        ...
    
    p1 = Person()
    p1.name = 'wyy'

特殊方法(__init__)

  • 之前说到,属性一般保存在实例中,所以实际有可能出现下面这种情况:

    p1 = Person()
    p1.name = 'wyy'
    
    p2 = Person()
    p2.name = 'zhl'
    
    p3 = Person()
    p3.name = 'dkr'
    ...
  • 这样很麻烦,而且有可能忘记初始化一些必须的变量,所以出现了__init__方法

  • 这个方法不需要我们手动调用,它会在实例被创建时自动执行,作用可以传入参数,并且初始化一些函数内变量,下面例子:

    class Person():
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def say_hello(self):
            print("Hi, I'm %s" %self.name)
    
    p1 = Person('wyy', 16)
    p1.say_hello()
  • 这样就可以很方便的初始化变量,而且忘记写还会报错。

总结类的基本结构

class 类名([父类]):

    公共属性...

    def __init__(self, a, b, ...):
        pass

    def method_1(self, a, b, ...):
        pass

    def method_2(self, a, b, ...):
        pass

    ...

封装

  • 封装是面向对象的三大特性之一

  • 封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法

  • 如何隐藏一个对象中的属性?

  • 将对象的属性名,修改为一个外部不知道的名字

  • 如何获取(修改)对象中的属性?

    • 需要提供一个getter和setter方法使外部可以访问到属性
    • getter 获取对象中的指定属性(get_属性名)
    • setter 用来设置对象的指定属性(set_属性名)
  • 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性

    1. 隐藏了属性名,使调用者无法随意的修改对象中的属性

    2. 增加了getter和setter方法,很好的控制的属性是否是只读的
  • 如果希望属性是只读的,则可以直接去掉setter方法

  • 如果希望属性不能被外部访问,则可以直接去掉getter方法

    1. 使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的

    2. 使用getter方法获取属性,使用setter方法设置属性
  • 可以在读取属性和修改属性的同时做一些其他的处理

    1. 使用getter方法可以表示一些计算的属性
    class Person():
        def __init__(self, name, age):
            self.hidden_name = name
            self.hidden_age = age
    
        def get_name(self):
            return self.hidden_name
    
        def set_name(self, name):
            self.hidden_name = name
        ...

隐藏类中的属性

  • 上面的方法已经满足了要求,但是很麻烦,所以python提供了命名方法,对于一个属性,如果将其前面加上双下划线,程序会自动改名为_类名__属性名

  • 但是我们一般不这么用,而是将属性名前面加上单下划线,这是一个约定:

    class Person():
        def __init__(self, name, age):
            self._name = name
            self._age = age
    
        def get_name(self):
            return self._name
    
        def set_name(self, name):
            self._name = name
        ...

property和setter装饰器

  • 我们在上述类中,如果有一个实例需要访问一个属性,需要调用getter方法,需要修改则需要setter方法,比较麻烦,我想要像访问一个属性一样修改/得到属性值

  • property装饰器,在getter方法前装饰,这样就可以像访问属性一样调用getter方法,注意:getter方法名需要和属性名相同

  • setter装饰器,用于setter方法前装饰,格式为@属性名.setter,注意:setter装饰器必须在property装饰过的属性中使用

    class Person():
        def __init__(self, name, age):
            self._name = name
            self._age = age
    
        @property
        def name(self):
            return self._name
    
        @name.setter
        def name(self, name):
            self._name = name;
    
        @property
        def age(self):
            return self._age
    
        @age.setter
        def age(self, age):
            self._age = age;
    
    p1 = Person('wyy', 16)
    print(p1.name, p1.age)
    
    p1.name = 'zhl'
    p1.age = 17
    print(p1.name, p1.age)
  • 可以这样直接访问

  • 注意:setter一定得在property装饰器装饰过的属性中使用

参考:阿里云大学Python学习路线

Last modification:April 6th, 2020 at 10:57 pm