• Python 简明教程 --- 19,Python 类与对象


    微信公众号:码农充电站pro
    个人主页:https://codeshellme.github.io

    那些能用计算机迅速解决的问题,就别用手做了。
    —— Tom Duff

    目录
    在这里插入图片描述

    上一节 我们介绍了Python 面向对象的相关概念,我们已经知道类与对象面向对象编程中非常重要的概念。

    类就是一个模板,是抽象的。对象是由类创建出来的实例,是具体的。由同一个类创建出来的对象拥有相同的方法属性,但属性的值可以是不同的。不同的对象是不同的实例,互不干扰。

    1,类的定义

    如下,是一个最简单的类,实际上是一个空类,不能做任何事情:

    class People:
        pass
    

    在Python 中定义一个类,需要用到class 关键字,后边是类名,然后是一个冒号:,然后下一行是类中的代码,注意要有缩进

    2,创建对象

    People 虽然是一个空类,但依然可以创建对象,创建一个对象的语法为:

    对象名 = 类名(参数列表)
    

    参数列表是跟__init__ 构造方法相匹配的,如果没有编写__init__ 方法,创建对象时,就不需要写参数,如下:

    >>> p = People()
    >>> p
    <__main__.People object at 0x7fd30e60be80>
    >>> 
    >>> p1 = People()
    >>> p1
    <__main__.People object at 0x7fd30e60be48>
    

    pp1 都是People类的对象。0x7fd30e60be80p 的地址,0x7fd30e60be48p1 的地址。可以看到不同的对象的地址是不同的,它们是两不同的实例,互不干扰。

    3,属性

    类中可以包含属性类中的变量),创建出来的对象就会拥有相应的属性,每个对象的属性的值可以不同。

    创建好对象后,可以用如下方法给对象添加属性:

    >>> p = People()
    >>> p.name = '小明' # 添加 name 属性
    >>> p.sex = '男'    # 添加 sex 属性
    >>> p.name         # 访问对象的属性
    '小明'
    >>> p.sex          # 访问对象的属性
    '男'
    

    虽然在技术上可以这样做,但是一般情况下,我们并不这样为对象添加属性,这样会破坏类的封装性,使得代码混乱,不利于维护。

    当访问一个不存在的属性时,会出现异常:

    >>> p.job         # 一个不存在的属性
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'People' object has no attribute 'job'
    

    我们一般会在__init__ 方法中为类添加属性并赋值。

    4,__init__ 方法

    在Python 的类中,以双下划线__开头和结尾的方法,被称为魔法方法,每个魔法方法都有特定的含义。Python 为我们规定了一些魔法方法,让我们自己实现这些方法。

    __init__ 方法叫做构造方法,用来初始化对象。Python 解释器会在生成对象时,自动执行构造方法,而无需用户显示调用。

    __init__ 方法不需要有返回值。

    类中的所有实例方法 方法,都至少有一个参数,就是self。Python 中的self 相当于C++ 和Java 中的this 指针,都是代表当前对象。只是Python 中的self 需要显示写在方法的第一个参数,而this 指针则不需要写在方法参数中。

    构造方法一般用于初始化对象的一些属性,构造函数可以不写,也可以只有一个self 参数。

    当构造函数只有一个self 参数时,创建该类的对象时,不需要添加参数。当构造函数除了self 参数还有其它参数时,创建该类的对象时,则需要添加相匹配的参数。

    比如,我们定义一个People 类,它有三个属性,分别是namesexage

    class People:
    
        def __init__(self, name, sex, age):
            self.name = name
            self.sex = sex
            self.age = age
            print('执行了 __init__ 方法')
    
        def print_info(self):
            print('people:%s sex:%s age:%s' % (
                self.name, self.sex, self.age))
    

    在这个People 类中除了有一个__init__ 方法外,还有一个print_info 方法,每个方法中的都有self 参数,并且是第一个参数,self 代表当前对象。

    在创建该类的对象时,需要传递匹配的参数(self 参数不用传递):

    >>> p = People('小明', '男', 18)
    执行了 __init__ 方法
    >>> p 
    <People.People object at 0x7feb6276bda0>
    >>> p.print_info()
    people:小明 sex:男 age:18
    >>>
    >>> p1 = People('小美', '女', 18)
    执行了 __init__ 方法
    >>> p1
    <People.People object at 0x7fd54352be48>
    >>> p1.print_info()
    people:小美 sex:女 age:18
    

    可以看到,在创建pp1 对象时,字符串执行了 __init__ 方法 被打印了出来,而我们并没有显示调用该方法,说明__init__ 方法被默认执行了。

    对象pp1 是两个不同的对象,拥有相同的属性和方法,但是属性值是不一样的。两个对象互不干扰,对象p 的地址为0x7feb6276bda0p1 的地址是0x7fd54352be48

    执行代码p.print_info(),是调用p 对象的print_info() 方法,因为,在定义该方法的时候,只有一个self 参数,所以在调用该方法的时候,不需要有参数。

    5,私有属性和方法

    私有属性

    普通的属性,就像上面的namesexage 属性,都是公有属性,在类的外部都可以被任意的访问,就是可以用对象.属性名的方式来访问属性,如下:

    >>> p = People('小明', '男', 18)
    执行了 __init__ 方法
    >>> p.name  # 访问属性
    '小明'
    >>> p.name = '小丽'  # 修改属性
    >>> p.name  # 访问属性
    '小丽'
    

    这样就破坏了数据的封装性,这种访问方式是不可控(会不受限制的被任意访问)的,不利于代码的维护,不符合面向对象的编程规范。

    所以,通常我们会将类中的属性,改为私有属性,就是不能以对象.属性名 这样的方式访问类属性。

    在Python 中,通过在属性名的前边添加双下划线__,来将公有属性变为私有属性,如下:

    #! /usr/bin/env python3
    
    class People:
    
        def __init__(self, name, sex, age):
            self.__name = name   # 两个下划线
            self.__sex = sex     # 两个下划线
            self._age = age      # 一个下划线
            print('执行了 __init__ 方法')
    
        def print_info(self):
            print('people:%s sex:%s age:%s' % (
                self.__name, self.__sex, self._age))
    

    这样就无法通过对象.属性名的方式来访问属性了,如下:

    >>> p = People('小美', '女', 18)
    执行了 __init__ 方法
    >>> p.__name        # 出现异常
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    AttributeError: 'People' object has no attribute '__name'
    

    但是,Python 中这种私有属性的方式,并不是真正的私有属性,Python 只是将__name 转换为了_People__name,即是在__name 的前边加上了_类名(_People),我们依然可以这样访问__name 属性:

    >>> p._People__name
    '小美'
    

    但我们并不提倡这种方式,这会让代码变得混乱难懂。

    可以注意到,People 类中的_age 属性是以单下划线开头的,这种以单下划线开头的属性是可以在类的外部被访问的:

    >>> p._age
    18
    

    但是根据Python 规范,以单下划线开头的属性,也被认为是私有属性,也不应该在类的外部访问(虽然在技术上是可以访问的)。

    注意:以双下划线__ 开头且结尾的属性__xxx__,是特殊属性,是公有的,可在类的外部访问

    私有方法

    私有方法与私有属性类似,也可以在方法名的前边加上双下划线__,来将某个方法变成私有的,一般不需要被外部访问的方法,应该将其设置为私有方法

    6,setget 方法

    为了数据的封装性,我们不应该直接在类的外部以对象.属性名的方式访问属性,那么如果我们需要访问类的属性该怎么办呢?

    这时我们需要为每个私有属性都提供两个方法:

    • set 方法:用于设置属性的值
    • get 方法:用于访问属性的值

    为了减少代码量,这里只为__name 属性设置了这两个方法,代码如下:

    #! /usr/bin/env python3
    
    class People:
    
        def __init__(self, name, sex, age):
            self.__name = name
            self.__sex = sex
            self._age = age
            print('执行了 __init__ 方法')
    
        def print_info(self):
            print('people:%s sex:%s age:%s' % (
                self.__name, self.__sex, self._age))
    
        # set 和 get 方法
        def set_name(self, name):
            self.__name = name
    
        def get_name(self):
            return self.__name
    

    用户可以这样设置和访问类的属性:

    >>> from People import People
    >>> p = People('小美', '女', 18)
    执行了 __init__ 方法
    >>> p.get_name()         # 获取 name 值
    '小美'
    >>> p.set_name('小丽')   # 设置新的值
    >>> p.get_name()        # 再次获取name 值
    '小丽'
    

    因为这种setget 方法,是由类的开发者提供的,是被开发者控制的。

    类的开发者会根据需要,来控制类的使用者如何使用该类,即哪些类的属性和方法应该被使用者访问,以及如何被使用者访问。

    如此,类的使用者就不能随便的访问类中的属性,这就达到了封装的目的。

    (完。)


    推荐阅读:

    Python 简明教程 --- 14,Python 数据结构进阶

    Python 简明教程 --- 15,Python 函数

    Python 简明教程 --- 16,Python 高阶函数

    Python 简明教程 --- 17,Python 模块与包

    Python 简明教程 --- 18,Python 面向对象


    欢迎关注作者公众号,获取更多技术干货。

    码农充电站pro

  • 相关阅读:
    一分钟了解Docker
    RobotFramework
    RobotFramework不同版本优劣势
    从零学习基于Python的RobotFramework自动化
    Python 接口自动化常用方法封装
    (转载)解决MySql 数据库 提示:1045 access denied for user 'root'@'localhost' using password yes
    (转载)html中div使用自动高度
    javascriptDOM对象之scrollTo()方法,滚动到页面指定位置
    CSS3之响应式布局
    Html5NodeJs安装less之千辛万苦CMD系列
  • 原文地址:https://www.cnblogs.com/codeshell/p/13193866.html
Copyright © 2020-2023  润新知