zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    js中的原生Ajax和JQuery中的Ajax
    this的用法
    static的特性
    时政20180807
    java compiler没有1.8怎么办
    Description Resource Path Location Type Java compiler level does not match the version of the installed Java project facet Unknown Faceted Project Problem (Java Version Mismatch)
    分词器
    [数算]有一个工程甲、乙、丙单独做,分别要48天、72天、96天完成
    一点感想
    解析Excel文件 Apache POI框架使用
  • 原文地址:https://www.cnblogs.com/codeshell/p/13193866.html
Copyright © 2011-2022 走看看