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>
p
和 p1
都是People
类的对象。0x7fd30e60be80
是p
的地址,0x7fd30e60be48
是p1
的地址。可以看到不同的对象的地址是不同的,它们是两不同的实例,互不干扰。
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
类,它有三个属性,分别是name
,sex
,age
:
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
可以看到,在创建p
和p1
对象时,字符串执行了 __init__ 方法
被打印了出来,而我们并没有显示调用该方法,说明__init__
方法被默认执行了。
对象p
和p1
是两个不同的对象,拥有相同的属性和方法,但是属性值是不一样的。两个对象互不干扰,对象p
的地址为0x7feb6276bda0
,p1
的地址是0x7fd54352be48
。
执行代码p.print_info()
,是调用p
对象的print_info()
方法,因为,在定义该方法的时候,只有一个self
参数,所以在调用该方法的时候,不需要有参数。
5,私有属性和方法
私有属性
普通的属性,就像上面的name
,sex
和age
属性,都是公有属性
,在类的外部都可以被任意的访问,就是可以用对象.属性名
的方式来访问属性,如下:
>>> 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,set
和 get
方法
为了数据的封装性
,我们不应该直接在类的外部以对象.属性名
的方式访问属性,那么如果我们需要访问类的属性该怎么办呢?
这时我们需要为每个私有属性都提供两个方法:
- 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 简明教程 --- 16,Python 高阶函数
Python 简明教程 --- 17,Python 模块与包
Python 简明教程 --- 18,Python 面向对象
欢迎关注作者公众号,获取更多技术干货。
Python 简明教程 --- 19,Python 类与对象的更多相关文章
- Python 简明教程 --- 20,Python 类中的属性与方法
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 与客户保持良好的关系可以使生产率加倍. -- Larry Bernstain 目录 类中的变量称为属 ...
- Python 简明教程 --- 21,Python 继承与多态
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 程序不是年轻的专利,但是,它属于年轻. 目录 我们已经知道封装,继承和多态 是面向对象的三大特征,面 ...
- Python 简明教程 --- 22,Python 闭包与装饰器
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 当你选择了一种语言,意味着你还选择了一组技术.一个社区. 目录 本节我们来介绍闭包与装饰器. 闭包与 ...
- Python 简明教程 --- 23,Python 异常处理
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 要么做第一个,要么做最好的一个. 目录 我们在编写程序时,总会不自觉的出现一些错误,比如逻辑错误,语 ...
- Python 简明教程 --- 24,Python 文件读写
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 过去的代码都是未经测试的代码. 目录 无论是哪种编程语言,IO 操作都是非常重要的部分.I 即Inp ...
- Python 简明教程 --- 8,Python 字符串函数
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 好代码本身就是最好的文档.当你需要添加一个注释时,你应该考虑如何修改代码才能不需要注释. -- St ...
- 【笔记】Python简明教程
Python简明教程,此资源位于http://woodpecker.org.cn/abyteofpython_cn/chinese/ s=u'中文字符' #u表示unicode,使用u之后能正常显示中 ...
- Python 简明教程 --- 18,Python 面向对象
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 代码能借用就借用. -- Tom Duff 目录 编程可分为面向过程编程和面向对象编程,它们是两种不 ...
- Python 简明教程 --- 14,Python 数据结构进阶
微信公众号:码农充电站pro 个人主页:https://codeshellme.github.io 如果你发现特殊情况太多,那很可能是用错算法了. -- Carig Zerouni 目录 前几节我们介 ...
随机推荐
- 使用Burpsuite对手机抓包的配置
之前使用dSploit的时候就一直在想怎么对手机进行抓包分析,前两天使用了Burpsuite神器,发现通过简单的配置就可以抓手机app的数据包了,进而分析手机app的流量. 配置环境: 1.win7下 ...
- 聚类算法之k-均值聚类
k-均值聚类算法 优点:容易实现 缺点:可能收敛到局部最小值,在大规模数据集上收敛较慢 适用数据类型:数值型数据 其工作流程:首先,随机确定k个初始点作为质心,然后将数据集中的每个点分配到一个簇中,具 ...
- .NetCore3.1中的WebApi如何配置跨域
写法 一: 1. 打开Startup.cs,定义静态变量Any,用以配置跨域. private readonly string Any = "Any"; 2. 在Configure ...
- Java实现第七届蓝桥杯国赛 赢球票
标题:赢球票 某机构举办球票大奖赛.获奖选手有机会赢得若干张球票. 主持人拿出 N 张卡片(上面写着 1~N 的数字),打乱顺序,排成一个圆圈. 你可以从任意一张卡片开始顺时针数数: 1,2,3- 如 ...
- Java实现 LeetCode 224 基本计算器
224. 基本计算器 实现一个基本的计算器来计算一个简单的字符串表达式的值. 字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 . 示例 1: 输入: "1 ...
- Hive的压缩存储和简单优化
一.Hive的压缩和存储 1,MapReduce支持的压缩编码 压缩格式 工具 算法 文件扩展名 是否可切分 对应的编码/解码器 DEFLATE 无 DEFLATE .deflate 否 org.ap ...
- 使用 UniApp 实现小程序的微信登录
微信登录思路: 在main.js 中封装公共函数,用于判断用户是否登录 在main.js 中分定义全局变量,用于存储接口地址 如果没有登录.则跳转至登录页面 进入登录页面 通过 wx.login 获取 ...
- 无监督LDA、PCA、k-means三种方法之间的的联系及推导
\(LDA\)是一种比较常见的有监督分类方法,常用于降维和分类任务中:而\(PCA\)是一种无监督降维技术:\(k\)-means则是一种在聚类任务中应用非常广泛的数据预处理方法. 本文的 ...
- 在PyQt5中显示matplotlib绘制的图形
import sys from PyQt5.QtCore import Qt from PyQt5.QtWidgets import * from plot_pyqt import PlotCanva ...
- JAVA多线程实现的三种方法
JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable.Future实现有返回结果的多线程.其中前两种方式线程执行完后都没 ...