微信公众号:码农充电站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 值
'小丽'

(完。)


推荐阅读:

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

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

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

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

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


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

Python 简明教程 --- 19,Python 类与对象的更多相关文章

  1. Python 简明教程 --- 20,Python 类中的属性与方法

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 与客户保持良好的关系可以使生产率加倍. -- Larry Bernstain 目录 类中的变量称为属 ...

  2. Python 简明教程 --- 21,Python 继承与多态

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 程序不是年轻的专利,但是,它属于年轻. 目录 我们已经知道封装,继承和多态 是面向对象的三大特征,面 ...

  3. Python 简明教程 --- 22,Python 闭包与装饰器

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...

  4. Python 简明教程 --- 23,Python 异常处理

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 要么做第一个,要么做最好的一个. 目录 我们在编写程序时,总会不自觉的出现一些错误,比如逻辑错误,语 ...

  5. Python 简明教程 --- 24,Python 文件读写

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 过去的代码都是未经测试的代码. 目录 无论是哪种编程语言,IO 操作都是非常重要的部分.I 即Inp ...

  6. Python 简明教程 --- 8,Python 字符串函数

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 好代码本身就是最好的文档.当你需要添加一个注释时,你应该考虑如何修改代码才能不需要注释. -- St ...

  7. 【笔记】Python简明教程

    Python简明教程,此资源位于http://woodpecker.org.cn/abyteofpython_cn/chinese/ s=u'中文字符' #u表示unicode,使用u之后能正常显示中 ...

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

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 代码能借用就借用. -- Tom Duff 目录 编程可分为面向过程编程和面向对象编程,它们是两种不 ...

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

    微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 如果你发现特殊情况太多,那很可能是用错算法了. -- Carig Zerouni 目录 前几节我们介 ...

随机推荐

  1. vnc远程工具的使用,Windows系统下VNC远程工具的使用教程

    服务器管理工具可以作为VNC的客户端进行VNC的相关操作,是一款功能强大的VNC客户端软件!同时,它也可以作为FTP的客户端,来进行FTP的相关操作!它能够连接Windows和Linux系统下的服务器 ...

  2. Rocket - util - Counters

    https://mp.weixin.qq.com/s/q7R2Dn9p9cch_ABN4raReQ   介绍几种计数器的实现,以及其中的一点小细节.   ​​   1. ZCounter   ​​   ...

  3. JVM虚拟机 与 GC 垃圾回收

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.JVM体系结构概述 1.JVM 与系统.硬件 ​ JVM是运行在操作系统之上的,它与硬件没有直接的交 ...

  4. Java实现 LeetCode 74 搜索二维矩阵

    74. 搜索二维矩阵 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的最后一个整数. 示例 1: ...

  5. Java实现 LeetCode 73 矩阵置零

    73. 矩阵置零 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [ [1,1,1], [1,0,1], [1,1,1] ...

  6. Python UI自动化测试实操

    本UI 自动化框架主要的实验的目的是:完成了登录页面的自动化登录与打开会员中心的页面这一自动化的过程. 废话不多说,直接上代码截图: 我们首先来看看整个工程的目录结构,这样以便于了解项目的调用关系: ...

  7. mysql基础之-mysql数据控制语言DCL(七)

    0x01 mysql中的权限分布 mysql中的用户信息都存储在系统数据库mysql的user表中 查询语句:select host,user,password from mysql.user; 创建 ...

  8. android日常开发总结的技术经验60条

    全部Activity可继承自BaseActivity,便于统一风格与处理公共事件,构建对话框统一构建器的建立,万一需要整体变动,一处修改到处有效. 数据库表段字段常量和SQL逻辑分离,更清晰,建议使用 ...

  9. 00-03.kaliLinux-vi粘贴复制功能配置

    KaliLinux在xShell的vim中默认是无法复制和粘贴的,需要做如下配置后才能使用: 方法一 进入vim命令行模式,输入: :set mouse=c #进入Command-line 模式 然后 ...

  10. 一次性搞懂 PHP 中面向对象的所有知识点。

    OOP是什么? OOP是面向对象编程,面向对象编程是一种计算机编程架构. OOP的基本原则是计算机程序是由单个能起到子程序作用的单元或对象组合而成. 基本概念: 类:定义了事务的抽象特点.包含了数据的 ...