良心帖!python基础入门看完这篇文章就差不多了,建议收藏!
入门Python其实很容易,但找对学习方法很重要。对Python的由来和基本语法有一个大概的了解,对我们理解和学习有更好的帮助。
小编也收到了留言,希望能多分享一点知识干货,今天我们就对Python基础知识做一个详细的内容介绍,希望能对大家有帮助。
第一部分 Python基础语法
1. 认识Python
1.1 Python 简介
Python 的创始人为吉多·范罗苏姆(Guido van Rossum)。
Python 的设计目标:
一门简单直观的语言并与主要竞争者一样强大开源,以便任何人都可以为它做贡献 代码像纯英语那样容易理解适用于短期开发的日常任务
Python 的设计哲学:
优雅、明确、简单
Python 开发者的哲学是:用一种方法,最好是只有一种方法来做一件事
Python 是完全面向对象的语言,在 Python 中一切皆对象。
可扩展性:如果需要一段关键代码运行得更快或者希望某些算法不公开,可以把这部分程序用 C 或 C++ 编写,然后在 Python 程序中使用它们。
1.2. 第一个Python程序
执行 Python 程序的三种方式:
解释器、交互式运行、IDE运行
Python 是一个格式非常严格的程序设计语言。
python 2.x 默认不支持中文。
ASCII 字符只包含 256 个字符,不支持中文
Python 2.x 的解释器名称是python
Python 3.x 的解释器名称是python3
为了照顾现有的程序,官方提供了一个过渡版本 ——Python 2.7。
提示:如果开发时,无法立即使用 Python 3.0(还有极少的第三方库不支持 3.0 的语法),建议
先使用 Python 3.0 版本进行开发 然后使用 Python 2.6、Python 2.7 来执行,并且做一些兼容性的处理
IPython 是一个 python 的交互式 shell,比默认的 python shell 好用得多,它支持 bash shell 命令,适合于学习/验证 Python 语法或者局部代码。
集成开发环境(IDE,Integrated Development Environment)——集成了开发软件需要的所有工具,一般包括以下工具:
图形用户界面
代码编辑器(支持代码补全/自动缩进)
编译器/解释器
调试器(断点/单步执行)
PyCharm 是 Python 的一款非常优秀的集成开发环境
PyCharm运行工具栏
1.4. 多文件项目的演练
开发项目就是开发一个专门解决一个复杂业务功能的软件
通常每一个项目就具有一个独立专属的目录,用于保存所有和项目相关的文件
在 PyCharm 中,要想让哪一个 Python 程序能够执行,必须首先通过鼠标右键的方式执行一下
对于初学者而言,在一个项目中设置多个程序可以执行,是非常方便的,可以方便对不同知识点的练习和测试
对于商业项目而言,通常在一个项目中,只有一个可以直接执行的 Python 源程序
让选中的程序可以执行
2. 注释
注释的作用
使用用自己熟悉的语言,在程序中对某些代码进行标注说明,增强程序的可读性
2.1 单行注释(行注释)
以 # 开头,# 右边的所有东西都被当做说明文字,而不是真正要执行的程序,只起到辅助说明作用
为了保证代码的可读性,# 后面建议先添加一个空格,然后再编写相应的说明文字;为了保证代码的可读性,注释和代码之间 至少要有 两个空格。
2.2 多行注释(块注释)
要在 Python 程序中使用多行注释,可以用 一对 连续的 三个 引号(单引号和双引号都可以)
提示:
注释不是越多越好,对于一目了然的代码,不需要添加注释
对于复杂的操作,应该在操作开始前写上若干行注释
对于不是一目了然的代码,应在其行尾添加注释(为了提高可读性,注释应该至少离开代码 2 个空格)
绝不要描述代码,假设阅读代码的人比你更懂 Python,他只是不知道你的代码要做什么
2.3 代码规范:
Python 官方提供有一系列 PEP(Python Enhancement Proposals) 文档,其中第 8 篇文档专门针对Python的代码格式给出了建议,也就是俗称的PEP 8:
文档地址:https://www.python.org/dev/peps/pep-0008/
谷歌有对应的中文文档:http://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_style_rules/
3. 运算符
3.1 算数运算符
是完成基本的算术运算使用的符号,用来处理四则运算,而“+”和“*”还可以用来处理字符串。
3.2 比较(关系)运算符
运算符 描述
==检查两个操作数的值是否相等,如果是,则条件成立,返回 True
!=检查两个操作数的值是否不相等,如果是,则条件成立,返回 True
>检查左操作数的值是否大于右操作数的值,如果是,则条件成立,返回 True
<检查左操作数的值是否小于右操作数的值,如果是,则条件成立,返回 True
>=检查左操作数的值是否大于或等于右操作数的值,如果是,则条件成立,返回 True
<=检查左操作数的值是否小于或等于右操作数的值,如果是,则条件成立,返回 True
Python 2.x 中判断不等于还可以使用<>运算符
!= 在 Python 2.x 中同样可以用来判断不等于
3.3 赋值运算符
在 Python 中,使用 = 可以给变量赋值。
在算术运算时,为了简化代码的编写,Python 还提供了一系列的 与算术运算符对应的赋值运算符,注意:赋值运算符中间不能使用空格。
运算符 描述 实例 = 简单的赋值运算符
3.4 身份运算符
身份运算符比较两个对象的内存位置。常用的有两个身份运算符,如下所述:
运算符 描述 示例
is 判断两个标识符是不是引用同一个对象 x is y,类似 id(x) == id(y) is
not判断两个标识符是不是引用不同对象 x is not y,类似 id(a) != id(b)
辨析
is 用于判断 两个变量引用的对象是否为同一个
== 用于判断 引用变量的值是否相等
3.5 成员运算符
Python成员运算符测试给定值是否为序列中的成员。有两个成员运算符,如下所述:
运算符 描述
in如果在指定的序列中找到一个变量的值,则返回true,否则返回false。
not in 如果在指定序列中找不到变量的值,则返回true,否则返回false。
3.6 逻辑运算符
运算符 逻辑表达式 描述
and x and y只有 x 和 y 的值都为 True,才会返回 True 否则只要 x 或者 y 有一个值为 False,就返回 False
or x or y只要 x或者 y 有一个值为 True,就返回 True<只有 x 和 y 的值都为 False,才会返回 False
not not x如果 x 为 True,返回 False 如果 x 为 False,返回 True
3.7 运算符优先级
以下表格的算数优先级由高到最低顺序排列:
运算符 描述
**幂 (最高优先级)
* / % //乘、除、取余数、取整除
+ -加法、减法
<= < > >=比较运算符
== !=等于运算符
= %= /= //= -= += *= **=赋值运算符
is is not身份运算符
in not in成员运算符
not or and逻辑运算符
<补>程序执行原理
Python程序执行示意图
操作系统会首先让CPU把Python 解释器的程序复制到内存中
Python 解释器根据语法规则,从上向下让CPU翻译Python 程序中的代码
CPU负责执行翻译完成的代码
Python 的解释器有多大?
执行以下终端命令可以查看 Python 解释器的大小
确认解释器所在位置which python
2. 查看 python 文件大小(只是一个软链接)ls -lh /usr/bin/python
3. 查看具体文件大小 ls -lh/usr/bin/python2.7
4. 变量
4.1 变量定义
在 Python 中,每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建
可以用其他变量的计算结果来定义变量
变量名 只有在第一次出现才是定义变量
变量名 = 值
使用交互式方式,如果要查看变量内容,直接输入变量名即可,不需要使用 print 函数
使用解释器执行,如果要输出变量的内容,必须要要使用 print 函数
4.2 变量的类型
在 Python 中定义变量是不需要指定类型(在其他很多高级语言中都需要),Python 可以根据 = 等号右侧的值,自动推导出变量中存储数据的类型
数据类型可以分为数字型和非数字型
整型 (int):Python3中的所有整数都表示为长整数。因此,长整数没有单独的数字类型。
浮点型(float)
布尔型(bool):真 True 非 0 数 —— 非零即真,假 False 0。
复数型 (complex):复数是由x + yj表示的有序对的实数浮点数组成,其中x和y是实数,j是虚数单位。
字符串(str):加号(+)是字符串连接运算符,星号(*)是重复运算符。
列表(list) 元组(tuple) 字典(dict)
提示:在 Python 2.x 中,整数根据保存数值的长度还分为:
int(整数) long(长整数)
使用 type 函数可以查看一个变量的类型
In [1]: type(name)
<补>不同类型变量之间的计算
数字型变量之间可以直接计算
在 Python 中,两个数字型变量是可以直接进行 算数运算的
如果变量是 bool 型,在计算时 True 对应的数字是 1 False 对应的数字是 0
字符串变量之间使用 + 拼接字符串
字符串变量可以和整数使用 * 重复拼接相同的字符串
数字型变量和字符串之间不能进行其他计算
<补>从键盘获取输入信息:input
在 Python 中可以使用 input 函数从键盘等待用户的输入
用户输入的任何内容Python 都认为是一个字符串
字符串变量 = input('提示信息:')
<补>类型转换函数
函数 说明 int(x) 将 x 转换为一个整数 float(x) 将 x 转换到一个浮点数 str(x) 将对象x转换为字符串表示形式 tuple(s) 将s转换为元组 list(s) 将s转换为列表
price = float(input('请输入价格:'))
<补>格式化输出:print
如果希望输出文字信息的同时,一起输出数据,就需要使用到格式化操作符
% 被称为格式化操作符,专门用于处理字符串中的格式 包含 % 的字符串,被称为格式化字符串% 和不同的字符连用,不同类型的数据需要使用不同的格式化字符
格式化字符 含义 %s 字符串 %d 有符号十进制整数,%06d 表示输出的整数显示位数,不足的地方使用 0 补全 %f 浮点数,%.2f 表示小数点后只显示两位 %% 输出 %
语法格式如下:
print('格式化字符串' % 变量1)
print('格式化字符串' % (变量1, 变量2...))
4.4.5 公共方法和变量的高级应用
4.4.5.1 内置函数
Python 包含了以下内置函数:
函数 描述 备注
len(item) 计算容器中元素个数
del(item) 删除变量
max(item) 返回容器中元素最大值 如果是字典,只针对 key 比较
min(item) 返回容器中元素最小值 如果是字典,只针对 key 比较
cmp(item1, item2) 比较两个值,-1 小于 / 0 相等 / 1 大于Python 3.x 取消了 cmp 函数
注意:字符串比较符合以下规则:'0' < 'A' < 'a'。
4.4.5.2 切片
描述 Python 表达式 结果 支持的数据类型 切片 '0123456789'[::-2] '97531' 字符串、列表、元组
切片使用索引值来限定范围,从一个大的字符串中切出小的字符串
列表和元组都是有序的集合,都能够通过索引值获取到对应的数据
字典是一个无序的集合,是使用键值对保存数据
面向对象编程 —— Object Oriented Programming 简写 OOP
面向过程 —— 怎么做?
把完成某一个需求的所有步骤从头到尾逐步实现根据开发需求,将某些功能独立的代码封装成一个又一个函数最后完成的代码,就是顺序地调用不同的函数特点:
注重步骤与过程,不注重职责分工如果需求复杂,代码会变得很复杂开发复杂项目,没有固定的套路,开发难度很大!
面向对象 —— 谁来做?
相比较函数,面向对象 是更大的封装,根据职责在 一个对象中封装多个方法 在完成某一个需求前,首先确定 职责 —— 要做的事情(方法)
根据 职责 确定不同的 对象,在 对象 内部封装不同的 方法(多个)最后完成的代码,就是顺序地让 不同的对象 调用不同的方法特点:
注重对象和职责,不同的对象承担不同的职责更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路需要在面向过程基础上,再学习一些面向对象的语法类和对象
类是对一群具有相同特征或者行为的事物的一个统称,是抽象的,特征被称为属性,行为被称为方法。
对象是由类创建出来的一个具体存在,是类的实例化。
在程序开发中,要设计一个类,通常需要满足一下三个要素:类名这类事物的名字,满足大驼峰命名法属性这类事物具有什么样的特征方法这类事物具有什么样的行为
2. 面向对象基础语法
2.1 dir 内置函数和内置方法
在 Python 中对象几乎是无所不在的,我们之前学习的变量、数据、函数都是对象。
在 Python 中可以使用以下两个方法验证:
在 标识符 / 数据 后输入一个点 .,然后按下 TAB 键,iPython 会提示该对象能够调用的方法列表。
使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的所有属性及方法。
提示__方法名__格式的方法是 Python 提供的 内置方法 / 属性。
方法名 类型 作用 :
__new__方法创建对象时,会被 自动 调用
__init__方法对象被初始化时,会被 自动 调用
__del__ 方法对象被从内存中销毁前,会被 自动 调用
__str__方法返回对象的描述信息,print 函数输出使用
提示利用好 dir() 函数,在学习时很多内容就不需要死记硬背了。
2.2 定义简单的类(只包含方法)
向对象是更大的封装,在 一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了!
定义一个只包含方法的类:
方法的定义格式和之前学习过的函数几乎一样,区别在于第一个参数必须是 self。
注意:类名的 命名规则 要符合大驼峰命名法。
当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:
对象变量 = 类名()
在面向对象开发中,引用的概念是同样适用的!
使用 print输出 对象变量,默认情况下,是能够输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)。
提示:在计算机中,通常使用 十六进制 表示 内存地址。
如果在开发中,希望使用 print输出 对象变量 时,能够打印自定义的内容,就可以利用 __str__这个内置方法了:
注意:__str__方法必须返回一个字符串。
2.3 方法中的 self 参数
在 Python 中,要 给对象设置属性,非常的容易,只需要在类的外部的代码中直接通过 对象.设置一个属性即可,但是不推荐使用:
因为:对象属性的封装应该封装在类的内部
由哪一个对象调用的方法,方法内的 self就是哪一个对象的引用
在类封装的方法内部,self 就表示当前调用方法的对象自己,在方法内部:
可以通过 self.访问对象的属性,也可以通过 self.调用对象的其他方法。调用方法时,程序员不需要传递 self 参数。
在 类的外部,通过变量名.访问对象的 属性和方法
在 类封装的方法中,通过 self.访问对象的 属性和方法
2.4 初始化方法:__init__
当使用 类名() 创建对象时,会 自动 执行以下操作:
为对象在内存中分配空间—— 创建对象
为对象的属性设置初始值—— 初始化方法(__init__)
__init__ 方法是专门用来定义一个类具有哪些属性的方法!
在 __init__ 方法内部使用 self.属性名 = 属性的初始值 就可以定义属性,定义属性之后,再使用 类创建的对象,都会拥有该属性。
在开发中,如果希望在 创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行改造:把希望设置的属性值,定义成 __init__方法的参数 在方法内部使用 self.属性 = 形参 接收外部传递的参数 在创建对象时,使用 类名(属性1, 属性2...) 调用
2.5 私有属性和私有方法
应用场景
在实际开发中,对象的某些属性或方法可能只希望在对象的内部被使用,而不希望在外部被访问到
私有属性就是对象不希望公开的属性
私有方法就是对象不希望公开的方法
定义方式
在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法:
私有属性和私有方法
伪私有属性和私有方法
Python 中,并没有 真正意义 的 私有
在给 属性、方法命名时,实际是对名称做了一些特殊处理,使得外界无法访问到
处理方式:在 名称 前面加上_类名 => _类名__名称
提示:在日常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法。
3. 封装、继承和多态
面向对象三大特性:
封装根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
继承实现代码的重用,相同的代码不需要重复的编写
多态不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
3.1 继承
3.1.1 单继承
继承的概念:子类 拥有 父类 以及 父类的父类 中封装的所有 属性 和 方法。
当 父类 的方法实现不能满足子类需求时,可以对方法进行重写(override)
重写 父类方法有两种情况:
覆盖父类的方法:父类的方法实现 和 子类的方法实现完全不同
具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现。对父类方法进行扩展:子类的方法实现 中 包含 父类的方法实现
在子类中 重写 父类的方法;在需要的位置使用 super().父类方法来调用父类方法的执行代码;其他的位置针对子类的需求,编写 子类特有的代码实现。
关于 super
在 Python 中 super 是一个 特殊的类
super()就是使用 super 类创建出来的对象
最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
调用父类方法的另外一种方式:在 Python 2.x 时,如果需要调用父类的方法,还可以使用以下方式:父类名.方法(self)。目前在 Python 3.x 还支持这种方式,但不推荐使用,因为一旦父类发生变化,方法调用位置的 类名 同样需要修改。
父类的 私有属性 和 私有方法
子类对象不能在自己的方法内部,直接访问 父类的 私有属性 或 私有方法
子类对象 可以通过 父类 的公有方法间接访问到 私有属性 或 私有方法
私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问 私有属性、方法 通常用于做一些内部的事情
3.1.2 多继承
子类 可以拥有多个父类,并且具有 所有父类 的 属性 和 方法,例如:孩子 会继承自己 父亲 和 母亲 的 特性。
Python 中的 MRO算法(Method Resolution Order)
如果 不同的父类 中存在 同名的方法,子类对象 在调用方法时,会调用 哪一个父类中的方法呢?
提示:开发时,应该尽量避免这种容易产生混淆的情况!—— 如果 父类之间 存在 同名的属性或者方法,应该尽量避免使用多继承。Python 中针对 类 提供了一个 内置属性__mro__ 可以查看 方法 搜索顺序在搜索方法时,是按照mro的输出结果 从左至右 的顺序查找的 如果在当前类中找到方法,就直接执行,不再搜索 如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索 如果找到最后一个类,还没有找到方法,程序报错
MRO 是 method resolution order —— 方法搜索顺序,主要用于 在多继承时判断 方法、属性 的调用 路径
新式类与旧式(经典)类
新式类:以 object 为基类的类,推荐使用
经典类:不以 object为基类的类,不推荐使用
在 Python 3.x 中定义类时,如果没有指定父类,会默认使用 object作为该类的 基类 —— Python 3.x 中定义的类都是新式类,在 Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类。
为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行!今后在定义类时,如果没有父类,建议统一继承自 object:
object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir(object) 函数查看。
3.2 多态
面向对象三大特性:
封装根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 定义类的准则
继承实现代码的重用,相同的代码不需要重复的编写 设计类的技巧 子类针对自己特有的需求,编写特定的代码
多态不同的 子类对象 调用相同的 父类方法,产生不同的执行结果 增加代码的灵活度 以 继承 和 重写父类方法 为前提 调用方法的技巧,不会影响到类的内部设计
多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!
案例:
在 Dog 类中封装方法 game:普通狗只是简单的玩耍
定义 XiaoTianDog 继承自 Dog,并且重写 game
方法:哮天犬需要在天上玩耍
定义 Person 类,并且封装一个 和狗玩 的方法:在方法内部,直接让 狗对象 调用 game 方法
多态示例
Person 类中只需要让 狗对象 调用 game 方法,而不关心具体是 什么狗。
4. 类属性和类方法
4.1 类的结构
通常会把:
创建出来的 对象 叫做类的实例
创建对象的 动作 叫做实例化
对象的属性叫做实例属性
对象调用的方法 叫做实例方法
每一个对象都有自己独立的内存空间,保存各自不同的属性
多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用传递到方法内部
各个不同的属性,独一份的方法
在 Python 中,类是一个特殊的对象。
Python 中 一切皆对象:
class AAA: 定义的类属于类对象obj1 = AAA() 属于实例对象
在程序运行时,类同样会被加载到内存
在程序运行时,类对象在内存中只有一份,使用 一个类可以创建出很多个对象实例
除了封装实例的属性和方法外,类对象还可以拥有自己的属性和方法——类属性、类方法,通过 类名. 的方式可以 访问类的属性 或者 调用类的方法
类的结构
4.2 类属性和实例属性
类属性就是类对象中定义的属性
通常用来记录与这个类相关的特征
类属性不会用于记录具体对象的特征
示例:
定义一个 工具类,每件工具都有自己的 name:
需求—— 知道使用这个类,创建了多少个工具对象?
属性的获取机制
在 Python 中 属性的获取 存在一个向上查找机制
因此,要访问类属性有两种方式:
类名.类属性
对象.类属性(不推荐,因为如果使用 对象.类属性 = 值 赋值语句,只会给对象添加一个属性,而不会影响到类属性的值)
4.3 类方法和静态方法
4.3.1 类方法
类属性 就是针对类对象定义的属性 使用 赋值语句 在 class 关键字下方可以定义 类属性 类属性 用于记录与这个类相关的特征
类方法就是针对类对象定义的方法在类方法内部可以直接访问类属性或者调用其他的类方法
语法如下
类方法需要用修饰器@classmethod 来标识,告诉解释器这是一个类方法
类方法的第一个参数应该是 cls 由哪一个类调用的方法,方法内的 cls 就是哪一个类的引用这个参数和实例方法的第一个参数是 self 类似提示使用其他名称也可以,不过习惯使用 cls
通过类名.调用类方法,调用方法时,不需要传递 cls 参数
在方法内部可以通过 cls.访问类的属性也可以通过 cls.调用其他的类方法
示例
定义一个工具类,每件工具都有自己的 name
需求—— 在类封装一个 show_tool_count 的类方法,输出使用当前这个类,创建的对象个数
4.3.2 静态方法
在开发时,如果需要在类中封装一个方法,这个方法:
既不需要访问实例属性或者调用实例方法也不需要访问类属性或者调用类方法
这个时候,可以把这个方法封装成一个静态方法
语法如下
静态方法需要用修饰器@staticmethod 来标识,告诉解释器这是一个静态方法
通过类名.调用静态方法
示例:
静态方法 show_help 显示游戏帮助信息
类方法 show_top_score 显示历史最高分
实例方法 start_game 开始当前玩家的游戏
探索:
实例方法—— 方法内部需要访问 实例属性实例方法 内部可以使用 类名. 访问类属性
类方法—— 方法内部只需要访问 类属性
静态方法—— 方法内部,不需要访问 实例属性 和 类属性
5. 单例
5.1 单例设计模式
设计模式设计模式是前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对某一特定问题的成熟的解决方案 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性
单例设计模式目的——让类创建的对象,在系统中只有唯一的一个实例每一次执行 类名() 返回的对象,内存地址是相同的
单例设计模式的应用场景音乐播放对象回收站对象打印机对象 ……
5.2 静态方法:__new__
使用类名()创建对象时,Python 的解释器首先会 调用 __new__ 方法为对象分配空间
__new__ 是一个 由 object 基类提供的内置的静态方法,主要作用有两个:在内存中为对象分配空间返回对象的引用
Python 的解释器获得对象的引用后,将引用作为第一个参数,传递给 __init__ 方法
重写 __new__ 方法 的代码非常固定!
重写 __new__ 方法一定要return super().__new__(cls),否则 Python 的解释器得不到分配了空间的对象引用,就不会调用对象的初始化方法
注意:__new__是一个静态方法,在调用时需要主动传递cls 参数
5.3 Python 中的单例
单例——让类创建的对象,在系统中只有唯一的一个实例定义一个类属性,初始值是 None,用于记录单例对象的引用重写 __new__ 方法 如果类属性is None,调用父类方法分配空间,并在类属性中记录结果返回类属性中记录的对象引用
只执行一次初始化工作
在每次使用 类名() 创建对象时,Python 的解释器都会自动调用两个方法:__new__ 分配空间 __init__ 对象初始化
在对 __new__ 方法改造之后,每次都会得到第一次被创建对象的引用
但是:初始化方法还会被再次调用
需求
让初始化动作只被执行一次
解决办法
定义一个类属性 init_flag 标记是否执行过初始化动作,初始值为 False
在 __init__ 方法中,判断 init_flag,如果为 False 就执行初始化动作
然后将 init_flag 设置为 True
这样,再次自动调用 __init__ 方法时,初始化动作就不会被再次执行了
Tips
1、Python 能够自动的将一对括号内部的代码连接在一起:
2、一个对象的 属性 可以是 另外一个类创建的对象。
3、在__init__方法中定义类的属性时,如果 不知道设置什么初始值,可以设置为 None):None 关键字表示什么都没有,表示一个空对象,没有方法和属性,是一个特殊的常量。可以将 None 赋值给任何一个变量。
在 Python 中针对 None 比较时,建议使用is 判断
4、eval() 函数十分强大 —— 将字符串 当成 有效的表达式 来求值 并 返回计算结果
在开发时千万不要使用 eval 直接转换 input 的结果,举个例子: