微信公众号:码农充电站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. 解决pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='files.pythonhosted.org', port=443): Read timed out.问题

    国内的其他镜像源清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/阿里云 http://mirrors.aliyun.com/pypi/simple/中国科技 ...

  2. 微信小程序路由跳转(navigateTo,redirectTo ,switchTab ,reLaunch )

    navigateTo, redirectTo 只能打开非 tabBar 页面. switchTab 只能打开 tabBar 页面. reLaunch 可以打开任意页面. 通过redirect重定向的页 ...

  3. Alpha冲刺 —— 5.2

    这个作业属于哪个课程 软件工程 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 Alpha冲刺 作业正文 正文 github链接 项目地址 其他参考文献 无 一.会议内容 1.展 ...

  4. git可视化打包更新文件

    每次当我们修改了项目代码的时候,总需要理出来一个更新包发给测试部门或者给客户更新.当我们一次的修改的代码多了之后,我们就很难按照文件夹一个一个的去提交出来哪些的更新的,哪些是未修改的.于是乎就在度娘能 ...

  5. Java实现蓝桥杯 算法提高 盾神与积木游戏

    题目描述 最近的m天盾神都去幼儿园陪小朋友们玩去了~ 每个小朋友都拿到了一些积木,他们各自需要不同数量的积木来拼一些他们想要的东西.但是有的小朋友拿得多,有的小朋友拿得少,有些小朋友需要拿到其他 小朋 ...

  6. Java实现 LeetCode 713 乘积小于K的子数组(子集数量+双指针)

    713. 乘积小于K的子数组 给定一个正整数数组 nums. 找出该数组内乘积小于 k 的连续的子数组的个数. 示例 1: 输入: nums = [10,5,2,6], k = 100 输出: 8 解 ...

  7. Java实现基础练习十进制转十六进制

    基础练习 十进制转十六进制 时间限制:1.0s 内存限制:512.0MB 提交此题 锦囊1 锦囊2 问题描述 十六进制数是在程序设计时经常要使用到的一种整数的表示方式.它有0,1,2,3,4,5,6, ...

  8. Java实现 LeetCode 40 组合总和 II(二)

    40. 组合总和 II 给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合. candidates 中的每个数字在 ...

  9. Jmeter之Json提取器详解(史上最全)

    参考资料:https://www.bbsmax.com/A/D854lmBw5E/ Jsonpath在线测试:http://jsonpath.com/ 实际工作中用到的一些场景: 提取某个特定的值 提 ...

  10. Github上可以涨薪30k的Java教程和实战项目终于可以免费下载了

    写在前面 大家都知道 Github 是一个程序员福地,这里有各种厉害的开源框架.软件或者教程.这些东西对于我们学习和进步有着莫大的进步,所以我有了这个将 Github 上非常棒的 Java 开源项目整 ...