本文是基于黑马程序员2018年的Python基础班的内容编写的,以2018年的资料为蓝本,2016年的资料为补充,还参考了一些网上的教程,旨在更好地总结Python基础知识,力求简明扼要,以供实战演练时可以快速查询遗忘的知识点。全文分为两大部分,分别是Python基础语法和面向对象。html
Python 的创始人为吉多·范罗苏姆(Guido van Rossum)。python
Python 的设计目标:git
- 一门简单直观的语言并与主要竞争者同样强大
- 开源,以便任何人均可觉得它作贡献
- 代码像纯英语那样容易理解
- 适用于短时间开发的平常任务
Python 的设计哲学:程序员
- 优雅、明确、简单
Python 开发者的哲学是:用一种方法,最好是只有一种方法来作一件事面试
Python 是彻底面向对象的语言,在 Python 中一切皆对象。算法
可扩展性:若是须要一段关键代码运行得更快或者但愿某些算法不公开,能够把这部分程序用
C
或C++
编写,而后在Python
程序中使用它们。shell
执行 Python 程序的三种方式: 解释器、交互式运行、IDE运行编程
Python 是一个格式很是严格的程序设计语言。 python 2.x 默认不支持中文。ubuntu
ASCII
字符只包含256
个字符,不支持中文
为了照顾现有的程序,官方提供了一个过渡版本 —— Python 2.6。设计模式
提示:若是开发时,没法当即使用 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 的 配置信息 是保存在 用户家目录下 的 .PyCharmxxxx.x
目录下的,xxxx.x
表示当前使用的 PyCharm 的版本号
$ rm -r ~/.PyCharm2016.3
复制代码
$ tar -zxvf pycharm-professional-2017.1.3.tar.gz
复制代码
/opt
目录下,能够方便其余用户使用
/opt
目录用户存放给主机额外安装的软件
$ sudo mv pycharm-2017.1.3/ /opt/
复制代码
$ cd /opt/pycharm-2017.1.3/bin
复制代码
$ ./pycharm.sh
复制代码
Create the entry for all users
快捷方式文件 /usr/share/applications/jetbrains-pycharm.desktop
在
ubuntu
中,应用程序启动的快捷方式一般都保存在/usr/share/applications
目录下
要卸载 PyCharm 只须要作如下两步工做:
$ sudo rm -r /opt/pycharm-2016.3.1/
复制代码
$ rm -r ~/.PyCharm2016.3/
复制代码
若是再也不使用 PyCharm 还须要将
/usr/share/applications/
下的jetbrains-pycharm.desktop
删掉
PyCharm
中,要想让哪个 Python
程序可以执行,必须首先经过 鼠标右键的方式执行 一下#
开头,#
右边的全部东西都被当作说明文字,而不是真正要执行的程序,只起到辅助说明做用print("hello python") # 输出 `hello python`
复制代码
为了保证代码的可读性,
#
后面建议先添加一个空格,而后再编写相应的说明文字;为了保证代码的可读性,注释和代码之间 至少要有 两个空格。
""" 这是一个多行注释 在多行注释之间,能够写不少不少的内容…… """
print("hello python")
复制代码
提示:
Python
官方提供有一系列 PEP(Python Enhancement Proposals) 文档,其中第 8 篇文档专门针对 Python 的代码格式 给出了建议,也就是俗称的 PEP 8:
是完成基本的算术运算使用的符号,用来处理四则运算,而“+”和“*”还能够用来处理字符串。
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 10 + 20 = 30 |
- | 减 | 10 - 20 = -10 |
* | 乘 | 10 * 20 = 200 |
/ | 除 | 10 / 20 = 0.5 |
// | 取整除 | 返回除法的整数部分(商) 9 // 2 输出结果 4 |
% | 取余数 | 返回除法的余数 9 % 2 = 1 |
** | 幂 | 又称次方、乘方,2 ** 3 = 8 |
运算符 | 描述 |
---|---|
== | 检查两个操做数的值是否 相等,若是是,则条件成立,返回 True |
!= | 检查两个操做数的值是否 不相等,若是是,则条件成立,返回 True |
> | 检查左操做数的值是否 大于 右操做数的值,若是是,则条件成立,返回 True |
< | 检查左操做数的值是否 小于 右操做数的值,若是是,则条件成立,返回 True |
>= | 检查左操做数的值是否 大于或等于 右操做数的值,若是是,则条件成立,返回 True |
<= | 检查左操做数的值是否 小于或等于 右操做数的值,若是是,则条件成立,返回 True |
- Python 2.x 中判断 不等于 还可使用
<>
运算符!=
在 Python 2.x 中一样能够用来判断 不等于
=
能够给变量赋值。在算术运算时,为了简化代码的编写,Python
还提供了一系列的 与 算术运算符 对应的 赋值运算符,注意:赋值运算符中间不能使用空格。运算符 | 描述 | 实例 |
---|---|---|
= | 简单的赋值运算符 | c = a + b 将 a + b 的运算结果赋值为 c |
+= | 加法赋值运算符 | c += a 等效于 c = c + a |
-= | 减法赋值运算符 | c -= a 等效于 c = c - a |
*= | 乘法赋值运算符 | c *= a 等效于 c = c * a |
/= | 除法赋值运算符 | c /= a 等效于 c = c / a |
//= | 取整除赋值运算符 | c //= a 等效于 c = c // a |
%= | 取 模 (余数)赋值运算符 | c %= a 等效于 c = c % a |
**= | 幂赋值运算符 | c **= a 等效于 c = c ** a |
身份运算符比较两个对象的内存位置。经常使用的有两个身份运算符,以下所述:
运算符 | 描述 | 示例 |
---|---|---|
is | 判断两个标识符是否是引用同一个对象 | x is y,相似 id(x) == id(y) |
is not | 判断两个标识符是否是引用不一样对象 | x is not y,相似 id(a) != id(b) |
辨析
Python成员运算符测试给定值是否为序列中的成员。 有两个成员运算符,以下所述:
运算符 | 描述 |
---|---|
in | 若是在指定的序列中找到一个变量的值,则返回true,不然返回false。 |
not in | 若是在指定序列中找不到变量的值,则返回true,不然返回false。 |
运算符 | 逻辑表达式 | 描述 |
---|---|---|
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 |
运算符 | 描述 |
---|---|
** | 幂 (最高优先级) |
* / % // | 乘、除、取余数、取整除 |
+ - | 加法、减法 |
<= < > >= | 比较运算符 |
== != | 等于运算符 |
= %= /= //= -= += *= **= | 赋值运算符 |
is is not | 身份运算符 |
in not in | 成员运算符 |
not or and | 逻辑运算符 |
# 1. 确认解释器所在位置
$ which python
# 2. 查看 python 文件大小(只是一个软连接)
$ ls -lh /usr/bin/python
# 3. 查看具体文件大小
$ ls -lh /usr/bin/python2.7
复制代码
变量名 = 值
复制代码
使用交互式方式,若是要查看变量内容,直接输入变量名便可,不须要使用
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)
复制代码
bool
型,在计算时
True
对应的数字是 1
False
对应的数字是 0
+
拼接字符串*
重复拼接相同的字符串input
函数从键盘等待用户的输入字符串变量 = input("提示信息:")
复制代码
函数 | 说明 |
---|---|
int(x) | 将 x 转换为一个整数 |
float(x) | 将 x 转换到一个浮点数 |
str(x) | 将对象x转换为字符串表示形式 |
tuple(s) | 将s转换为元组 |
list(s) | 将s转换为列表 |
price = float(input("请输入价格:"))
复制代码
%
被称为 格式化操做符,专门用于处理字符串中的格式
%
的字符串,被称为 格式化字符串%
和不一样的 字符 连用,不一样类型的数据 须要使用 不一样的格式化字符格式化字符 | 含义 |
---|---|
%s | 字符串 |
%d | 有符号十进制整数,%06d 表示输出的整数显示位数,不足的地方使用 0 补全 |
%f | 浮点数,%.2f 表示小数点后只显示两位 |
%% | 输出 % |
print("格式化字符串" % 变量1)
print("格式化字符串" % (变量1, 变量2...))
复制代码
标示符就是程序员定义的 变量名、函数名
- 标示符能够由 字母、下划线 和 数字 组成
- 不能以数字开头
- 不能与关键字重名
关键字 就是在
Python
内部已经使用的标识符
- 关键字 具备特殊的功能和含义
- 开发者 不容许定义和关键字相同的名字的标识符
- 经过如下命令能够查看
Python
中的关键字In [1]: import keyword In [2]: print(keyword.kwlist) 复制代码
命名规则 能够被视为一种 惯例,并没有绝对与强制 目的是为了 增长代码的识别和可读性 注意
Python
中的 标识符 是 区分大小写的
=
的左右应该各保留一个空格_
下划线 链接,例如:first_name
、last_name
、qq_number
、qq_password
。固然,还有驼峰命名法: 小驼峰式命名法:第一个单词以小写字母开始,后续单词的首字母大写,例如:firstName
、lastName
。 大驼峰式命名法,每个单词的首字母都采用大写字母,例如:FirstName
、LastName
、CamelCase
。
在 Python
中,全部 非数字型变量 都支持如下特色: 1. 都是一个 序列 sequence
,也能够理解为 容器 2. 取值 []
3. 遍历 for in
4. 计算长度len
、最大/最小值max/min
、比较、删除del
5. 连接 +
和 重复 *
6. 切片
List
(列表) 是 Python
中使用 最频繁 的数据类型,在其余语言中一般叫作 数组,专门用于存储 一串 信息,列表用 []
定义,数据 之间使用 ,
分隔,列表的 索引 从 0
开始。索引 就是数据在 列表 中的位置编号,索引 又能够被称为 下标 注意:从列表中取值时,若是 超出索引范围,程序会报错
name_list = ["zhangsan", "lisi", "wangwu"]
复制代码
del
关键字(delete
) 一样能够删除列表中元素del
关键字本质上是用来 将一个变量从内存中删除的del
关键字将变量从内存中删除,后续的代码就不能再使用这个变量了In [1]: l = [1,2,3,4]
In [2]: del l[1]
In [3]: l[1]
Out[3]: 3
复制代码
在平常开发中,要从列表删除数据,建议 使用列表提供的方法
函数名(参数)
复制代码
函数须要死记硬背
对象.方法名(参数)
复制代码
在变量后面输入
.
,而后选择针对这个变量要执行的操做,记忆起来比函数要简单不少
遍历 就是 从头至尾 依次 从 列表 中获取数据,在 循环体内部 针对 每个元素,执行相同的操做。
在 Python 中为了提升列表的遍历效率,使用 for
就可以实现迭代遍历。
# for 循环内部使用的变量 in 列表
for name in name_list:
循环内部针对列表元素进行操做
print(name)
复制代码
Tuple
(元组)与列表相似,不一样之处在于元组的 元素不能修改
Python
开发中,有特定的应用场景
,
分隔()
定义,元组的 索引 从 0
开始,索引 就是数据在 元组 中的位置编号。info_tuple = ("zhangsan", 18, 1.75)
复制代码
建立空元组:
info_tuple = ()
复制代码
元组中 只包含一个元素 时,须要 在元素后面添加逗号:
info_tuple = (50, )
复制代码
- 在 Python 中,可使用
for
循环遍历全部非数字型类型的变量:列表、元组、字典 以及 字符串- 提示:在实际开发中,除非 可以确认元组中的数据类型,不然针对元组的循环遍历需求并非不少
- 在开发中,更多的应用场景是:
- 函数的 参数 和 返回值,一个函数能够接收 任意多个参数,或者 一次返回多个数据
- 格式字符串,格式化字符串后面的
()
本质上就是一个元组- 让列表不能够被修改,以保护数据安全
list
函数能够把元组转换成列表list(元组)
复制代码
tuple
函数能够把列表转换成元组tuple(列表)
复制代码
dict
(字典) 是 除列表之外 Python 之中 最灵活 的数据类型。 字典一样能够用来 存储多个数据,一般用于存储 描述一个 物体 的相关信息
{}
定义。,
分隔:
key
是索引value
是数据:
分隔xiaoming = {"name": "小明",
"age": 18,
"gender": True,
"height": 1.75}
复制代码
# for 循环内部使用的 `key 的变量` in 字典
for k in xiaoming:
print("%s: %s" % (k, xiaoming[k]))
复制代码
提示:在实际开发中,因为字典中每个键值对保存数据的类型是不一样的,因此针对字典的循环遍历需求并非不少
for in
遍历 字典物体
的相关信息 —— 描述更复杂的数据信息card_list = [{"name": "张三",
"qq": "12345",
"phone": "110"},
{"name": "李四",
"qq": "54321",
"phone": "10086"}
]
复制代码
"
或者 一对单引号 '
定义一个字符串
\"
或者 \'
作字符串的转义,可是在实际开发中:
"
,可使用 '
定义字符串'
,可使用 "
定义字符串for
循环遍历 字符串中每个字符大多数编程语言都是用
"
来定义字符串
string = "Hello Python"
for c in string:
print(c)
复制代码
提示:在 python 中对字符串操做,内置提供的方法足够多,使得在开发时,可以针对字符串进行更加灵活的操做!应对更多的开发需求!
方法 | 说明 |
---|---|
string.isspace() | 若是 string 中只包含空格,则返回 True |
string.isalnum() | 若是 string 至少有一个字符而且全部字符都是字母或数字则返回 True |
string.isalpha() | 若是 string 至少有一个字符而且全部字符都是字母则返回 True |
string.isdecimal() | 若是 string 只包含数字则返回 True,全角数字 |
string.isdigit() | 若是 string 只包含数字则返回 True,全角数字 、⑴ 、\u00b2 |
string.isnumeric() | 若是 string 只包含数字则返回 True,全角数字 ,汉字数字 |
string.istitle() | 若是 string 是标题化的(每一个单词的首字母大写)则返回 True |
string.islower() | 若是 string 中包含至少一个区分大小写的字符,而且全部这些(区分大小写的)字符都是小写,则返回 True |
string.isupper() | 若是 string 中包含至少一个区分大小写的字符,而且全部这些(区分大小写的)字符都是大写,则返回 True |
方法 | 说明 |
---|---|
string.startswith(str) | 检查字符串是不是以 str 开头,是则返回 True |
string.endswith(str) | 检查字符串是不是以 str 结束,是则返回 True |
string.find(str, start=0, end=len(string)) | 检测 str 是否包含在 string 中,若是 start 和 end 指定范围,则检查是否包含在指定范围内,若是是返回开始的索引值,不然返回 -1 |
string.rfind(str, start=0, end=len(string)) | 相似于 find(),不过是从右边开始查找 |
string.index(str, start=0, end=len(string)) | 跟 find() 方法相似,不过若是 str 不在 string 会报错 |
string.rindex(str, start=0, end=len(string)) | 相似于 index(),不过是从右边开始 |
string.replace(old_str, new_str, num=string.count(old)) | 把 string 中的 old_str 替换成 new_str,若是 num 指定,则替换不超过 num 次 |
方法 | 说明 |
---|---|
string.capitalize() | 把字符串的第一个字符大写 |
string.title() | 把字符串的每一个单词首字母大写 |
string.lower() | 转换 string 中全部大写字符为小写 |
string.upper() | 转换 string 中的小写字母为大写 |
string.swapcase() | 翻转 string 中的大小写 |
方法 | 说明 |
---|---|
string.ljust(width) | 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串 |
string.rjust(width) | 返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串 |
string.center(width) | 返回一个原字符串居中,并使用空格填充至长度 width 的新字符串 |
方法 | 说明 |
---|---|
string.lstrip() | 截掉 string 左边(开始)的空白字符 |
string.rstrip() | 截掉 string 右边(末尾)的空白字符 |
string.strip() | 截掉 string 左右两边的空白字符 |
方法 | 说明 |
---|---|
string.partition(str) | 把字符串 string 分红一个 3 元素的元组 (str前面, str, str后面) |
string.rpartition(str) | 相似于 partition() 方法,不过是从右边开始查找 |
string.split(str="", num) | 以 str 为分隔符拆分 string,若是 num 有指定值,则仅分隔 num + 1 个子字符串,str 默认包含 '\r', '\t', '\n' 和空格 |
string.splitlines() | 按照行('\r', '\n', '\r\n')分隔,返回一个包含各行做为元素的列表 |
string.join(seq) | 以 string 做为分隔符,将 seq 中全部的元素(的字符串表示)合并为一个新的字符串 |
字符串[开始索引:结束索引:步长]
复制代码
注意:
[开始索引, 结束索引)
=> 开始索引 <= 范围 < 结束索引
起始
位开始,到 结束
位的前一位 结束(不包含结束位自己)1
,若是连续切片,数字和冒号均可以省略num_str = "0123456789"
# 1. 截取从 2 ~ 5 位置 的字符串
print(num_str[2:6])
# 2. 截取从 2 ~ `末尾` 的字符串
print(num_str[2:])
# 3. 截取从 `开始` ~ 5 位置 的字符串
print(num_str[:6])
# 4. 截取完整的字符串
print(num_str[:])
# 5. 从开始位置,每隔一个字符截取字符串
print(num_str[::2])
# 6. 从索引 1 开始,每隔一个取一个
print(num_str[1::2])
# 倒序切片
# -1 表示倒数第一个字符
print(num_str[-1])
# 7. 截取从 2 ~ `末尾 - 1` 的字符串
print(num_str[2:-1])
# 8. 截取字符串末尾两个字符
print(num_str[-2:])
# 9. 字符串的逆序(面试题)
print(num_str[::-1])
复制代码
Python 包含了如下内置函数:
函数 | 描述 | 备注 |
---|---|---|
len(item) | 计算容器中元素个数 | |
del(item) | 删除变量 | del 有两种方式 |
max(item) | 返回容器中元素最大值 | 若是是字典,只针对 key 比较 |
min(item) | 返回容器中元素最小值 | 若是是字典,只针对 key 比较 |
cmp(item1, item2) | 比较两个值,-1 小于 / 0 相等 / 1 大于 | Python 3.x 取消了 cmp 函数 |
注意:字符串 比较符合如下规则: "0" < "A" < "a"。
描述 | Python 表达式 | 结果 | 支持的数据类型 |
---|---|---|---|
切片 | "0123456789"[::-2] | "97531" | 字符串、列表、元组 |
运算符 | Python 表达式 | 结果 | 描述 | 支持的数据类型 |
---|---|---|---|---|
+ | [1, 2] + [3, 4] | [1, 2, 3, 4] | 合并 | 字符串、列表、元组 |
* | ["Hi!"] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | 重复 | 字符串、列表、元组 |
in | 3 in (1, 2, 3) | True | 元素是否存在 | 字符串、列表、元组、字典 |
not in | 4 not in (1, 2, 3) | True | 元素是否不存在 | 字符串、列表、元组、字典 |
> >= == < <= | (1, 2, 3) < (2, 2, 3) | True | 元素比较 | 字符串、列表、元组 |
注意
in
在对 字典 操做时,判断的是 字典的键in
和 not in
被称为 成员运算符for 循环
的语法以下:for 变量 in 集合:
循环体代码
else:
没有经过 break 退出循环,循环结束后,会执行的代码
复制代码
应用场景:
- 变量 和 数据 都是保存在 内存 中的
- 在 Python 中 函数 的 参数传递 以及 返回值 都是靠 引用 传递的
在 Python 中:变量 和 数据 是分开存储的,数据 保存在内存中的一个位置,变量 中保存着数据在内存中的地址,就叫作 引用,使用 id()
函数能够查看变量中保存数据所在的 内存地址。
注意:若是变量已经被定义,当给一个变量赋值的时候,本质上是 修改了数据的引用
- 变量 再也不 对以前的数据引用
- 变量 改成 对新赋值的数据引用
在 Python 中,变量的名字相似于 便签纸 贴在 数据 上:
a
,而且赋值为 1
代码 | 图示 |
---|---|
a = 1 |
![]() |
a
赋值为 2
代码 | 图示 |
---|---|
a = 2 |
![]() ![]() |
b
,而且将变量 a
的值赋值给 b
代码 | 图示 |
---|---|
b = a |
![]() |
在 Python
中,函数的 实参/返回值 都是是靠 引用 来传递来的
def test(num):
print("-" * 50)
print("%d 在函数内的内存地址是 %x" % (num, id(num)))
result = 100
print("返回值 %d 在内存中的地址是 %x" % (result, id(result)))
print("-" * 50)
return result
a = 10
print("调用函数前 内存地址是 %x" % id(a))
r = test(a)
print("调用函数后 实参内存地址是 %x" % id(a))
print("调用函数后 返回值内存地址是 %x" % id(r))
复制代码
不可变类型,内存中的数据不容许被修改:
int
, bool
, float
, complex
, long(2.x)
str
tuple
可变类型,内存中的数据能够被修改:
list
dict
注意:字典的
key
只能使用不可变类型的数据
注意
(hash)
hash(o)
的函数:接收一个 不可变类型 的数据做为 参数,返回 结果是一个 整数。哈希
是一种 算法,其做用就是提取数据的 特征码(指纹),相同的内容 获得 相同的结果,不一样的内容 获得 不一样的结果。key
进行 hash
已决定如何在内存中保存字典的数据,以方便 后续 对字典的操做:增、删、改、查:键值对的 key
必须是不可变类型数据,键值对的 value
能够是任意类型的数据。提示:在其余的开发语言中,大多 不推荐使用全局变量 —— 可变范围太大,致使程序很差维护!
注意:函数执行时,须要处理变量时 会:
注意:函数不能直接修改全局变量的引用,若是要修改,必需要用global
声明该变量是全局变量。
num = 10
def demo1():
print("demo1" + "-" * 50)
# global 关键字,告诉 Python 解释器 num 是一个全局变量
global num
# 只是定义了一个局部变量,不会修改到全局变量,只是变量名相同而已
num = 100
print(num)
def demo2():
print("demo2" + "-" * 50)
print(num)
demo1()
demo2()
print("over")
复制代码
注意:为了不局部变量和全局变量出现混淆,在定义全局变量时,有些公司会有一些开发要求,例如:全局变量名前应该增长 g_
或者 gl_
的前缀。
一、if 判断语句基本语法:
if 要判断的条件:
条件成立时,要作的事情
……
复制代码
注意:代码的缩进为一个
tab
键,或者 4 个空格 —— 建议使用空格
- 在 Python 开发中,Tab 和空格不要混用!
二、若是须要在 不知足条件的时候,作某些事情,该如何作呢?
if 要判断的条件:
条件成立时,要作的事情
……
else:
条件不成立时,要作的事情
……
复制代码
条件1 and 条件2 :两个条件同时知足,返回 True
条件1 or 条件2:两个条件只要有一个知足,返回 True
not 条件:非,不是
复制代码
三、若是但愿 再增长一些条件,条件不一样,须要执行的代码也不一样 时,就可使用 elif
:
if 条件1:
条件1知足执行的代码
……
elif 条件2:
条件2知足时,执行的代码
……
elif 条件3:
条件3知足时,执行的代码
……
else:
以上条件都不知足时,执行的代码
……
复制代码
注意
elif
和 else
都必须和 if
联合使用,而不能单独使用if
、elif
和 else
以及各自缩进的代码,当作一个 完整的代码块四、在开发中,使用 if
进行条件判断,若是但愿 在条件成立的执行语句中 再 增长条件判断,就可使用 if 的嵌套:
if 条件 1:
条件 1 知足执行的代码
……
if 条件 1 基础上的条件 2:
条件 2 知足时,执行的代码
……
# 条件 2 不知足的处理
else:
条件 2 不知足时,执行的代码
# 条件 1 不知足的处理
else:
条件1 不知足时,执行的代码
……
复制代码
Python
中,要使用随机数,首先须要导入 随机数 的 模块 —— “工具包”import random
复制代码
导入模块后,能够直接在 模块名称 后面敲一个 .
而后按 Tab
键,会提示该模块中包含的全部函数
random.randint(a, b)
,返回 [a, b]
之间的整数,包含 a
和 b
例如:
random.randint(12, 20) # 生成的随机数n: 12 <= n <= 20
random.randint(20, 20) # 结果永远是 20
random.randint(20, 10) # 该语句是错误的,下限必须小于上限
复制代码
# 导入随机工具包
# 注意:在导入工具包的时候,应该将导入的语句,放在文件的顶部
# 由于,这样能够方便下方的代码,在任何须要的时候,使用工具包中的工具
import random
# 从控制台输入要出的拳 —— 石头(1)/剪刀(2)/布(3)
player = int(input("请输入您要出的拳 石头(1)/剪刀(2)/布(3):"))
# 电脑 随机 出拳 —— 先假定电脑只会出石头,完成总体代码功能
computer = random.randint(1, 3)
print("玩家选择的拳头是 %d - 电脑出的拳是 %d" % (player, computer))
# 比较胜负
# 1 石头 胜 剪刀
# 2 剪刀 胜 布
# 3 布 胜 石头
# if (()
# or ()
# or ()):
if ((player == 1 and computer == 2)
or (player == 2 and computer == 3)
or (player == 3 and computer == 1)):
print("欧耶,电脑弱爆了!")
# 平局
elif player == computer:
print("真是心有灵犀啊,再来一盘")
# 其余的状况就是电脑获胜
else:
print("不服气,咱们决战到天明!")
复制代码
在程序开发中,一共有三种流程方式:
while
语句基本语法:
初始条件设置 —— 一般是重复执行的 计数器
while 条件(判断 计数器 是否达到 目标次数):
条件知足时,作的事情1
条件知足时,作的事情2
条件知足时,作的事情3
...(省略)...
处理条件(计数器 + 1)
复制代码
因为程序员的缘由,忘记 在循环内部 修改循环的判断条件,致使循环持续执行,程序将陷入死循环而没法终止!
计数器 +1 :能够经过赋值运算符简化代码的编写。 常见的计数方法有两种,能够分别称为:
1
开始)—— 更符合人类的习惯0
开始)—— 几乎全部的程序语言都选择从 0 开始计数所以,你们在编写程序时,应该尽可能养成习惯:除非需求的特殊要求,不然 循环 的计数都从 0 开始
break
和continue
是专门在循环中使用的关键字
break
:某一条件知足时,退出循环,再也不执行后续的代码continue
:某一条件知足时,不执行后续的代码直接进入下一次循环break
和 continue
只针对 当前所在循环 有效while
嵌套就是:while
里面还有 while
,每一次循环中还要作完一个循环。while 条件 1:
条件知足时,作的事情1
条件知足时,作的事情2
条件知足时,作的事情3
...(省略)...
while 条件 2:
条件知足时,作的事情1
条件知足时,作的事情2
条件知足时,作的事情3
...(省略)...
处理条件 2
处理条件 1
复制代码
示例:
""" 打印 9 行小星星: * ** *** **** ***** ****** ******* ******** ********* """
# 定义起始行
row = 1
# 最大打印 9 行
while row <= 9:
# 定义起始列
col = 1
# 最大打印 row 列
while col <= row:
# end = "",表示输出结束后,不换行
# "\t" 能够在控制台输出一个制表符,协助在输出文本时对齐
print("%d * %d = %d" % (col, row, row * col), end="\t")
# 列数 + 1
col += 1
# 一行打印完成的换行
print("")
# 行数 + 1
row += 1
复制代码
\t
在控制台输出一个 制表符,协助在输出文本时 垂直方向 保持对齐\n
在控制台输出一个 换行符制表符 的功能是在不使用表格的状况下在 垂直方向 按列对齐文本
转义字符 | 描述 |
---|---|
\\ | 反斜杠符号 |
\' | 单引号 |
\" | 双引号 |
\n | 换行 |
\t | 横向制表符 |
\r | 回车 |
所谓函数,就是把 具备独立功能的代码块 组织为一个小模块,在须要的时候 调用。在开发程序时,使用函数能够提升编写的效率以及代码的 重用,函数的使用包含两个步骤: 1. 定义函数 —— 封装 独立的功能 2. 调用函数 —— 享受 封装 的成果
def 函数名():
函数封装的代码
……
复制代码
函数名()
便可完成对函数的调用。PyCharm 的调试工具:
- F8 Step Over 能够单步执行代码,会把函数调用看做是一行代码直接执行
- F7 Step Into 能够单步执行代码,若是是函数,会进入函数内部
CTRL + Q
能够查看函数的说明信息。注意:由于 函数体相对比较独立,函数定义的上方,应该和其余代码(包括注释)保留 两个空行
,
分隔。def sum_2_num(num1, num2):
result = num1 + num2
print("%d + %d = %d" % (num1, num2, result))
sum_2_num(50, 20)
复制代码
问题 1:在函数内部,针对参数使用 赋值语句,会不会影响调用函数时传递的 实参变量? —— 不会!
问题 2:若是传递的参数是 可变类型,在函数内部,使用 方法 修改了数据的内容,一样会影响到外部的数据,例如列表变量调用
+=
本质上是在执行列表变量的extend
方法。
定义函数时,能够给 某个参数 指定一个默认值,具备默认值的参数就叫作 缺省参数,* 调用函数时,若是没有传入 缺省参数 的值,则在函数内部使用定义函数时指定的 参数默认值,将常见的值设置为参数的缺省值,从而 简化函数的调用。例如:对列表排序的方法:
gl_num_list = [6, 3, 9]
# 默认就是升序排序,由于这种应用需求更多
gl_num_list.sort()
print(gl_num_list)
# 只有当须要降序排序时,才须要传递 `reverse` 参数
gl_num_list.sort(reverse=True)
print(gl_num_list)
复制代码
def print_info(name, gender=True):
gender_text = "男生"
if not gender:
gender_text = "女生"
print("%s 是 %s" % (name, gender_text))
复制代码
提示
注意
有时可能须要 一个函数 可以处理的参数 个数 是不肯定的,这个时候,就可使用 多值参数。
python
中有 两种 多值参数:
*
能够接收 元组**
能够接收 字典*args
—— 存放 元组 参数,前面有一个 *
**kwargs
—— 存放 字典 参数,前面有两个 **
def demo(num, *args, **kwargs):
print(num)
print(args)
print(kwargs)
demo(1, 2, 3, 4, 5, name="小明", age=18, gender=True)
print("-"*20)
demo(1,(2,3,4,5),{"name":"小明", "age":18, "gender":True})
print("-"*20)
demo(1,(2,3,4,5), name="小明", age=18, gender=True)
复制代码
args
kwargs
*
*
def demo(*args, **kwargs):
print(args)
print(kwargs)
# 须要将一个元组变量/字典变量传递给函数对应的参数
gl_nums = (1, 2, 3)
gl_xiaoming = {"name": "小明", "age": 18}
# 会把 num_tuple 和 xiaoming 做为元组传递个 args
# demo(gl_nums, gl_xiaoming)
demo(*gl_nums, **gl_xiaoming)
复制代码
return
关键字能够返回结果,调用函数一方,能够 使用变量 来 接收 函数的返回结果。注意:
return
表示返回,后续的代码都不会被执行
def sum_2_num(num1, num2):
"""对两个数字的求和"""
return num1 + num2
# 调用函数,并使用 result 变量接收计算结果
result = sum_2_num(10, 20)
print("计算结果是 %d" % result)
复制代码
技巧
Python
中,能够 将一个元组 使用 赋值语句 同时赋值给 多个变量# Python 专有,利用元组交换两个变量的值
a, b = b, a
复制代码
def test1():
print("*" * 50)
print("test 1")
print("*" * 50)
def test2():
print("-" * 50)
print("test 2")
test1()
print("-" * 50)
test2()
复制代码
提示:工做中针对需求的变化,应该冷静思考,不要轻易修改以前已经完成的,可以正常执行的函数!
函数调用自身的 编程技巧 称为递归
特色:一个函数 内部 调用本身
代码特色:
案例 —— 计算数字累加:
需求:
sum_numbers
num
的整数参数def sum_numbers(num):
if num == 1:
return 1
# 假设 sum_numbers 可以完成 num - 1 的累加
temp = sum_numbers(num - 1)
# 函数内部的核心算法就是 两个数字的相加
return num + temp
print(sum_numbers(2))
复制代码
模块是 Python 程序架构的一个核心概念
模块 就比如是 工具包,要想使用这个工具包中的工具,就须要 导入 import 这个模块, 每个以扩展名 py
结尾的 Python
源代码文件都是一个 模块,在模块中定义的 全局变量 、 函数 都是模块可以提供给外界直接使用的工具。
import
导入这个模块模块名.变量
/ 模块名.函数
的方式,使用这个模块中定义的变量或者函数模块可让 曾经编写过的代码 方便的被 复用! 模块名也是一个标识符,若是在给 Python 文件起名时,以数字开头 是没法在
PyCharm
中经过导入这个模块的。
C
是compiled
编译过 的意思。
__pycache__
的目录。hm_10_分隔线模块.cpython-35.pyc
文件,cpython-35
表示 Python
解释器的版本。pyc
文件是由 Python 解释器将 模块的源码 转换为 字节码。Python
这样保存 字节码 是做为一种启动 速度的优化。
Python
在解释源程序时是分红两个步骤的:
Python
重编译时,它会自动检查源文件和字节码文件的时间戳。文件的做用:将数据长期保存下来,在须要的时候使用 文件的存储方式:在计算机中,文件是以 二进制 的方式保存在磁盘上的 文本文件:可使用 文本编辑软件 查看,本质上仍是二进制文件 二进制文件:保存的内容 不是给人直接阅读的,而是 提供给其余软件使用的,例如:图片文件、音频文件、视频文件等等,二进制文件不能使用 文本编辑软件 查看
操做文件的套路: 在 计算机 中要操做文件的套路很是固定,一共包含三个步骤:
操做文件的函数/方法 在 Python
中要操做文件须要记住 1 个函数和 3 个方法
序号 | 函数/方法 | 说明 |
---|---|---|
01 | open | 打开文件,而且返回文件操做对象 |
02 | read | 将文件内容读取到内存 |
03 | write | 将指定内容写入文件 |
04 | close | 关闭文件 |
open
函数负责打开文件,而且返回文件对象 read
/write
/close
三个方法都须要经过 文件对象 来调用
读取文件示例
open
函数的第一个参数是要打开的文件名(文件名区分大小写) 若是文件 存在,返回 文件操做对象 若是文件 不存在,会 抛出异常
read
方法能够一次性 读入 并 返回 文件的 全部内容
close
方法负责 关闭文件 若是 忘记关闭文件,会形成系统资源消耗,并且会影响到后续对文件的访问
注意:read
方法执行后,会把 文件指针 移动到 文件的末尾
# 1\. 打开 - 文件名须要注意大小写
file = open("README")
# 2\. 读取
text = file.read()
print(text)
# 3\. 关闭
file.close()
复制代码
提示
read
方法后,文件指针 会移动到 读取内容的末尾
思考:若是执行了一次 read
方法,读取了全部内容,那么再次调用 read
方法,还可以得到到内容吗? 答案:不能!第一次读取以后,文件指针移动到了文件末尾,再次调用不会读取到任何的内容。
open
函数默认以 只读方式 打开文件,而且返回文件对象f = open("文件名", "访问方式")
复制代码
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。若是文件不存在,抛出异常 |
w | 以只写方式打开文件。若是文件存在会被覆盖。若是文件不存在,建立新文件 |
a | 以追加方式打开文件。若是该文件已存在,文件指针将会放在文件的结尾。若是文件不存在,建立新文件进行写入 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。若是文件不存在,抛出异常 |
w+ | 以读写方式打开文件。若是文件存在会被覆盖。若是文件不存在,建立新文件 |
a+ | 以读写方式打开文件。若是该文件已存在,文件指针将会放在文件的结尾。若是文件不存在,建立新文件进行写入 |
提示:频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以 只读、只写 的方式来操做文件
写入文件示例
# 打开文件
f = open("README", "w")
f.write("hello python!\n")
f.write("今每天气真好")
# 关闭文件
f.close()
复制代码
readline()
read
方法默认会把文件的 全部内容 一次性读取到内存readline
方法能够一次读取一行内容读取大文件的正确姿式
# 打开文件
file = open("README")
while True:
# 读取一行内容
text = file.readline()
# 判断是否读到内容
if not text:
break
# 每读取一行的末尾已经有了一个 `\n`
print(text, end="")
# 关闭文件
file.close()
复制代码
复制大文件
# 1\. 打开文件
file_read = open("README")
file_write = open("README[复件]", "w")
# 2\. 读取并写入文件
while True:
# 每次读取一行
text = file_read.readline()
# 判断是否读取到内容
if not text:
break
file_write.write(text)
# 3\. 关闭文件
file_read.close()
file_write.close()
复制代码
os
模块文件管理操做
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | rename | 重命名文件 | os.rename(源文件名, 目标文件名) |
02 | remove | 删除文件 | os.remove(文件名) |
目录管理操做
序号 | 方法名 | 说明 | 示例 |
---|---|---|---|
01 | listdir | 目录列表 | os.listdir(目录名) |
02 | mkdir | 建立目录 | os.mkdir(目录名) |
03 | rmdir | 删除目录 | os.rmdir(目录名) |
04 | getcwd | 获取当前目录 | os.getcwd() |
05 | chdir | 修改工做目录 | os.chdir(目标目录) |
06 | path.isdir | 判断是不是文件 | os.path.isdir(文件路径) |
提示:文件或者目录操做都支持 相对路径 和 绝对路径
ASCII
编码,UNICODE
编码等Python 2.x 默认使用
ASCII
编码格式 Python 3.x 默认使用UTF-8
编码格式
ASCII
编码
256
个 ASCII
字符ASCII
在内存中占用 1 个字节 的空间
8
个 0/1
的排列组合方式一共有 256
种,也就是 2 ** 8
UTF-8
编码格式
UTF-8
字符,涵盖了 地球上几乎全部地区的文字UTF-8
是 UNICODE
编码的一种编码格式Ptyhon 2.x 中如何使用中文?
# *-* coding:utf8 *-*
,解释器会以 utf-8
编码来处理 python 文件,这方式是官方推荐使用的!# coding=utf8
。Python 2.x 中如何正确遍历 unicode 字符串?
UTF-8
的编码格式,可是在遍历字符串时,仍然会 以字节为单位遍历 字符串u
,告诉解释器这是一个 unicode
字符串(使用 UTF-8
编码格式的字符串)# *-* coding:utf8 *-*
# 在字符串前,增长一个 `u` 表示这个字符串是一个 utf8 字符串
hello_str = u"你好世界"
print(hello_str)
for c in hello_str:
print(c)
复制代码
Python 解释器
遇到 到一个错误,会中止程序的执行,而且提示一些错误信息,这就是 异常程序开发时,很难将 全部的特殊状况 都处理的面面俱到,经过 异常捕获 能够针对突发事件作集中的处理,从而保证程序的 稳定性和健壮性
![]()
try except else finally
简单的捕获异常语法
try(尝试)
来 捕获异常try:
尝试执行的代码
except:
出现错误的处理
复制代码
try
尝试,下方编写要尝试代码,不肯定是否可以正常执行的代码except
若是不是,下方编写尝试失败的代码简单异常捕获1 —— 要求用户输入整数
try:
# 提示用户输入一个数字
num = int(input("请输入数字:"))
except:
print("请输入正确的数字")
复制代码
错误类型捕获
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except (错误类型2, 错误类型3):
# 针对错误类型2 和 3,对应的代码处理
pass
except Exception as result:
print("未知错误 %s" % result)
复制代码
Python
解释器 抛出异常 时,最后一行错误信息的第一个单词,就是错误类型异常类型捕获2 —— 要求用户输入整数
try:
num = int(input("请输入整数:"))
result = 8 / num
print(result)
except ValueError:
print("请输入正确的整数")
except ZeroDivisionError:
print("除 0 错误")
复制代码
捕获未知错误
Python
解释器 抛出异常而被终止,能够再增长一个 except
语法以下:
except Exception as result:
print("未知错误 %s" % result)
复制代码
异常捕获完整语法
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except 错误类型2:
# 针对错误类型2,对应的代码处理
pass
except (错误类型3, 错误类型4):
# 针对错误类型3 和 4,对应的代码处理
pass
except Exception as result:
# 打印错误信息
print(result)
else:
# 没有异常才会执行的代码
pass
finally:
# 不管是否有异常,都会执行的代码
print("不管是否有异常,都会执行的代码")
复制代码
else
只有在没有异常时才会执行的代码
finally
不管是否有异常,都会执行的代码
以前一个演练的 完整捕获异常 的代码以下:
try:
num = int(input("请输入整数:"))
result = 8 / num
print(result)
except ValueError:
print("请输入正确的整数")
except ZeroDivisionError:
print("除 0 错误")
except Exception as result:
print("未知错误 %s" % result)
else:
print("正常执行")
finally:
print("执行完成,可是不保证正确")
复制代码
提示:
- 在开发中,能够在主函数中增长 异常捕获,而在主函数中调用的其余函数,只要出现异常,都会传递到主函数的异常捕获中
- 这样就不须要在代码中,增长大量的异常捕获,可以保证代码的整洁
''' 需求: 1. 定义函数 `demo1()` **提示用户输入一个整数而且返回** 2. 定义函数 `demo2()` 调用 `demo1()` 3. 在主程序中调用 `demo2()` '''
def demo1():
return int(input("请输入一个整数:"))
def demo2():
return demo1()
try:
print(demo2())
except ValueError:
print("请输入正确的整数")
except Exception as result:
print("未知错误 %s" % result)
复制代码
raise
应用场景
Python
解释器会 抛出 异常以外示例
抛出异常
Python
中提供了一个 Exception
异常类Exception
的 对象raise
关键字 抛出 异常对象''' **需求** * 定义 `input_password` 函数,提示用户输入密码 * 若是用户输入长度 < 8,抛出异常 * 若是用户输入长度 >=8,返回输入的密码 '''
def input_password():
# 1\. 提示用户输入密码
pwd = input("请输入密码:")
# 2\. 判断密码长度,若是长度 >= 8,返回用户输入的密码
if len(pwd) >= 8:
return pwd
# 3\. 密码长度不够,须要抛出异常
# 1> 建立异常对象 - 使用异常的错误信息字符串做为参数
ex = Exception("密码长度不够")
# 2> 抛出异常对象
raise ex
try:
user_pwd = input_password()
print(user_pwd)
except Exception as result:
print("发现错误:%s" % result)
复制代码
模块是 Python 程序架构的一个核心概念
py
结尾的 Python
源代码文件都是一个 模块模块的两种导入方式
1)import 导入
import 模块名1, 模块名2
复制代码
提示:在导入模块时,每一个导入应该独占一行
import 模块名1
import 模块名2
复制代码
模块名.
使用 模块提供的工具 —— 全局变量、函数、类as
指定模块的别名若是模块的名字太长,可使用
as
指定模块的名称,以方便在代码中的使用
import 模块名1 as 模块别名
复制代码
注意:模块别名 应该符合 大驼峰命名法
2)from...import 导入
from ... import
的方式import 模块名
是 一次性 把模块中 全部工具所有导入,而且经过 模块名/别名 访问# 从 模块 导入 某一个工具
from 模块名1 import 工具名
复制代码
注意
若是 两个模块,存在 同名的函数,那么 后导入模块的函数,会 覆盖掉先导入的函数
import
代码应该统一写在 代码的顶部,更容易及时发现冲突as
关键字 给其中一个工具起一个别名from...import *
# 从 模块 导入 全部工具
from 模块名1 import *
复制代码
注意
这种方式不推荐使用,由于函数重名并无任何的提示,出现问题很差排查
Python
的解释器在 导入模块 时,会:
在开发时,给文件起名,不要和 系统的模块文件 重名
Python
中每个模块都有一个内置属性__file__
能够 查看模块 的 完整路径
原则 —— 每个文件都应该是能够被导入的
Python
文件 就是一个 模块实际开发场景
__name__
属性
__name__
属性能够作到,测试模块的代码 只在测试状况下被运行,而在 被导入时不会被执行!__name__
是 Python
的一个内置属性,记录着一个 字符串__name__
就是 模块名__name__
是 __main__
在不少 Python
文件中都会看到如下格式的代码:
# 导入模块
# 定义全局变量
# 定义类
# 定义函数
# 在代码的最下方
def main():
# ...
pass
# 根据 __name__ 判断是否执行下方代码
if __name__ == "__main__":
main()
复制代码
__init__.py
_
好处:使用 import 包名
能够一次性导入 包 中 全部的模块
案例
hm_message
的 包send_message
和 receive_message
send_message
文件中定义一个 send
函数receive_message
文件中定义一个 receive
函数hm_message
的包__init__.py
__init__.py
中指定 对外界提供的模块列表# 从 当前目录 导入 模块列表
from . import send_message
from . import receive_message
复制代码
setup.py
的文件from distutils.core import setup
setup(name="hm_message", # 包名
version="1.0", # 版本
description="itheima's 发送和接收消息模块", # 描述信息
long_description="完整的发送和接收消息模块", # 完整描述信息
author="itheima", # 做者
author_email="itheima@itheima.com", # 做者邮箱
url="www.itheima.com", # 主页
py_modules=["hm_message.send_message",
"hm_message.receive_message"])
复制代码
有关字典参数的详细信息,能够参阅官方网站:docs.python.org/2/distutils…
$ python3 setup.py build
复制代码
$ python3 setup.py sdist
复制代码
注意:要制做哪一个版本的模块,就使用哪一个版本的解释器执行!
4)安装模块
$ tar -zxvf hm_message-1.0.tar.gz
$ sudo python3 setup.py install
复制代码
5)卸载模块
直接从安装目录下,把安装模块的 目录 删除就能够
$ cd /usr/local/lib/python3.5/dist-packages/
$ sudo rm -r hm_message*
复制代码
pip
安装第三方模块
Python
包 / 模块
pygame
就是一套很是成熟的 游戏开发模块pip
是一个现代的,通用的 Python
包管理工具Python
包的查找、下载、安装、卸载等功能安装和卸载命令以下:
# 将模块安装到 Python 2.x 环境
$ sudo pip install pygame
$ sudo pip uninstall pygame
# 将模块安装到 Python 3.x 环境
$ sudo pip3 install pygame
$ sudo pip3 uninstall pygame
复制代码
面向对象编程 —— Object Oriented Programming
简写 OOP
面向对象 —— 谁来作?
相比较函数,面向对象 是更大的封装,根据职责在 一个对象中封装多个方法
在完成某一个需求前,首先肯定 职责 —— 要作的事情(方法) 根据 职责 肯定不一样的 对象,在 对象 内部封装不一样的 方法(多个) 最后完成的代码,就是顺序地让 不一样的对象 调用 不一样的方法 特色: 注重 对象和职责,不一样的对象承担不一样的职责 更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路 须要在面向过程基础上,再学习一些面向对象的语法
在 Python 中 对象几乎是无所不在的,咱们以前学习的 变量、数据、函数 都是对象。 在 Python 中可使用如下两个方法验证:
标识符 / 数据
后输入一个点 .
,而后按下 TAB
键,iPython 会提示该对象可以调用的方法列表。dir
传入 标识符 / 数据
,能够查看对象内的 全部属性及方法。 提示__方法名__
格式的方法是 Python 提供的 内置方法 / 属性
。序号 | 方法名 | 类型 | 做用 |
---|---|---|---|
01 | __new__ |
方法 | 建立对象时,会被 自动 调用 |
02 | __init__ |
方法 | 对象被初始化时,会被 自动 调用 |
03 | __del__ |
方法 | 对象被从内存中销毁前,会被 自动 调用 |
04 | __str__ |
方法 | 返回对象的描述信息,print 函数输出使用 |
提示 利用好 dir()
函数,在学习时不少内容就不须要死记硬背了。
面向对象是更大的封装,在 一个类中封装多个方法,这样经过这个类建立出来的对象,就能够直接调用这些方法了!
定义一个只包含方法的类:
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
复制代码
方法 的定义格式和以前学习过的函数几乎同样,区别在于第一个参数必须是 self
。 注意:类名 的 命名规则 要符合 大驼峰命名法。 当一个类定义完成以后,要使用这个类来建立对象,语法格式以下:
对象变量 = 类名()
复制代码
在面向对象开发中,引用的概念是一样适用的!
使用 print
输出 对象变量,默认状况下,是可以输出这个变量 引用的对象 是 由哪个类建立的对象,以及 在内存中的地址(十六进制表示)。
提示:在计算机中,一般使用 十六进制 表示 内存地址。
若是在开发中,但愿使用 print
输出 对象变量 时,可以打印 自定义的内容,就能够利用 __str__
这个内置方法了:
class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 来了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
def __str__(self):
return "我是小猫:%s" % self.name
tom = Cat("Tom")
print(tom)
复制代码
注意:
__str__
方法必须返回一个字符串。
在 Python 中,要 给对象设置属性,很是的容易,只须要在 类的外部的代码 中直接经过 对象.
设置一个属性便可,可是不推荐使用:
class Cat:
"""这是一个猫类"""
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫在喝水")
tom = Cat()
# 给对象设置属性
tom.name = "Tom"
复制代码
由于:对象属性的封装应该封装在类的内部
由哪个对象调用的方法,方法内的
self
就是哪个对象的引用
self
就表示当前调用方法的对象本身,在方法内部: 能够经过 self.
访问对象的属性,也能够经过 self.
调用对象的其余方法。变量名.
访问对象的 属性和方法 在 类封装的方法中,经过 self.
访问对象的 属性和方法__init__
类名()
建立对象时,会 自动 执行如下操做: 为对象在内存中分配空间 —— 建立对象 为对象的属性设置初始值 —— 初始化方法(__init__
)
__init__
方法是 专门 用来定义一个类具备哪些属性的方法!
在 __init__
方法内部使用 self.属性名 = 属性的初始值
就能够定义属性,定义属性以后,再使用 类建立的对象,都会拥有该属性。
在开发中,若是但愿在 建立对象的同时,就设置对象的属性,能够对 __init__
方法进行 改造:
__init__
方法的参数self.属性 = 形参
接收外部传递的参数类名(属性1, 属性2...)
调用class Cat:
def __init__(self, name):
print("初始化方法 %s" % name)
self.name = name
...
tom = Cat("Tom")
...
lazy_cat = Cat("大懒猫")
...
复制代码
应用场景
定义方式
伪私有属性和私有方法 Python 中,并无 真正意义 的 私有 在给 属性、方法 命名时,实际是对名称作了一些特殊处理,使得外界没法访问到 处理方式:在 名称 前面加上_类名
=> _类名__名称
# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)
# 私有方法,外部不能直接调用
xiaofang._Women__secret()
复制代码
提示:在平常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法。
面向对象三大特性:
继承的概念:子类 拥有 父类 以及 父类的父类 中封装的全部 属性 和 方法。
class 类名(父类名):
pass
复制代码
当 父类 的方法实现不能知足子类需求时,能够对方法进行重写(override) 重写 父类方法有两种状况:
super().父类方法
来调用父类方法的执行代码;其余的位置针对子类的需求,编写 子类特有的代码实现。super
是一个 特殊的类super()
就是使用 super 类
建立出来的对象调用父类方法的另一种方式:在 Python 2.x 时,若是须要调用父类的方法,还可使用如下方式:
父类名.方法(self)
。目前在 Python 3.x 还支持这种方式,但不推荐使用,由于一旦 父类发生变化,方法调用位置的 类名 一样须要修改。
子类对象 不能 在本身的方法内部,直接 访问 父类的 私有属性 或 私有方法 子类对象 能够经过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法
- 私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问
- 私有属性、方法 一般用于作一些内部的事情
子类 能够拥有 多个父类,而且具备 全部父类 的 属性 和 方法,例如:孩子 会继承本身 父亲 和 母亲 的 特性。
class 子类名(父类名1, 父类名2...):
pass
复制代码
__mro__
能够查看 方法 搜索顺序
MRO 是 method resolution order —— 方法搜索顺序,主要用于 在多继承时判断 方法、属性 的调用 路径
object
为基类的类,推荐使用object
为基类的类,不推荐使用在 Python 3.x 中定义类时,若是没有指定父类,会 默认使用 object做为该类的 基类 —— Python 3.x 中定义的类都是 新式类,在 Python 2.x 中定义类时,若是没有指定父类,则不会以 object 做为 基类。
class 类名(object):
pass
复制代码
object
是 Python 为全部对象提供的 基类,提供有一些内置的属性和方法,可使用dir(object)
函数查看。
面向对象三大特性:
多态 更容易编写出出通用的代码,作出通用的编程,以适应需求的不断变化!
案例: 在 Dog 类中封装方法 game:普通狗只是简单的玩耍 定义 XiaoTianDog 继承自 Dog,而且重写 game 方法:哮天犬须要在天上玩耍 定义 Person 类,而且封装一个 和狗玩 的方法:在方法内部,直接让 狗对象 调用 game 方法
一般会把: 建立出来的 对象 叫作 类的实例 建立对象的 动做 叫作 实例化 对象的属性 叫作 实例属性 对象调用的方法 叫作 实例方法 每个对象 都有本身独立的内存空间,保存各自不一样的属性 多个对象的方法,在内存中只有一份,在调用方法时,须要把对象的引用传递到方法内部
在 Python 中,类是一个特殊的对象。
Python 中 一切皆对象:
- class AAA: 定义的类属于 类对象
- obj1 = AAA() 属于 实例对象
在程序运行时,类一样会被加载到内存 在程序运行时,类对象在内存中只有一份,使用 一个类能够建立出不少个对象实例 除了封装实例的属性和方法外,类对象还能够拥有本身的属性和方法——类属性、类方法,经过 类名.
的方式能够 访问类的属性 或者 调用类的方法
类属性 就是 类对象中定义的属性 一般用来记录与这个类相关的特征 类属性不会用于记录具体对象的特征 示例: 定义一个 工具类,每件工具都有本身的 name
: 需求 —— 知道使用这个类,建立了多少个工具对象?
class Tool(object):
# 使用赋值语句,定义类属性,记录建立工具对象的总数
count = 0
def __init__(self, name):
self.name = name
# 针对类属性作一个计数+1
Tool.count += 1
# 建立工具对象
tool1 = Tool("斧头")
tool2 = Tool("榔头")
tool3 = Tool("铁锹")
# 知道使用 Tool 类到底建立了多少个对象?
print("如今建立了 %d 个工具" % Tool.count)
复制代码
在 Python 中 属性的获取 存在一个 向上查找机制
所以,要访问类属性有两种方式:
类名.类属性
对象.类属性
(不推荐,由于若是使用 对象.类属性 = 值
赋值语句,只会给对象添加一个属性,而不会影响到类属性的值)class
关键字下方能够定义 类属性语法以下
@classmethod
def 类方法名(cls):
pass
复制代码
@classmethod
来标识,告诉解释器这是一个类方法cls
cls
就是 哪个类的引用self
相似cls
cls
参数cls.
访问类的属性cls.
调用其余的类方法示例
name
show_tool_count
的类方法,输出使用当前这个类,建立的对象个数@classmethod
def show_tool_count(cls):
"""显示工具对象的总数"""
print("工具对象的总数 %d" % cls.count)
复制代码
语法以下
@staticmethod
def 静态方法名():
pass
复制代码
@staticmethod
来标识,告诉解释器这是一个静态方法示例:
show_help
显示游戏帮助信息show_top_score
显示历史最高分start_game
开始当前玩家的游戏class Game(object):
# 游戏最高分,类属性
top_score = 0
@staticmethod
def show_help():
print("帮助信息:让僵尸走进房间")
@classmethod
def show_top_score(cls):
print("游戏最高分是 %d" % cls.top_score)
def __init__(self, player_name):
self.player_name = player_name
def start_game(self):
print("[%s] 开始游戏..." % self.player_name)
# 使用类名.修改历史最高分
Game.top_score = 999
# 1. 查看游戏帮助
Game.show_help()
# 2. 查看游戏最高分
Game.show_top_score()
# 3. 建立游戏对象,开始游戏
game = Game("小明")
game.start_game()
# 4. 游戏结束,查看游戏最高分
Game.show_top_score()
复制代码
探索:
设计模式
单例设计模式
类名()
返回的对象,内存地址是相同的单例设计模式的应用场景
__new__
Python
的解释器 首先 会 调用 __new__
方法为对象 分配空间__new__
是一个 由 object
基类提供的 内置的静态方法,主要做用有两个:
Python
的解释器得到对象的 引用 后,将引用做为 第一个参数,传递给 __init__
方法重写
__new__
方法 的代码很是固定!
__new__
方法 必定要 return super().__new__(cls)
,不然 Python 的解释器 得不到 分配了空间的 对象引用,就不会调用对象的初始化方法__new__
是一个静态方法,在调用时须要 主动传递 cls
参数class MusicPlayer(object):
def __new__(cls, *args, **kwargs):
# 若是不返回任何结果,就不会调用对象的初始化方法
return super().__new__(cls)
def __init__(self):
print("初始化音乐播放对象")
player = MusicPlayer()
print(player)
复制代码
None
,用于记录 单例对象的引用__new__
方法is None
,调用父类方法分配空间,并在类属性中记录结果class MusicPlayer(object):
# 定义类属性记录单例对象引用
instance = None
def __new__(cls, *args, **kwargs):
# 1\. 判断类属性是否已经被赋值
if cls.instance is None:
cls.instance = super().__new__(cls)
# 2\. 返回类属性的单例引用
return cls.instance
复制代码
类名()
建立对象时,Python
的解释器都会自动调用两个方法:
__new__
分配空间__init__
对象初始化__new__
方法改造以后,每次都会获得 第一次被建立对象的引用需求
解决办法
init_flag
标记是否 执行过初始化动做,初始值为 False
__init__
方法中,判断 init_flag
,若是为 False
就执行初始化动做init_flag
设置为 True
__init__
方法时,初始化动做就不会被再次执行 了class MusicPlayer(object):
# 记录第一个被建立对象的引用
instance = None
# 记录是否执行过初始化动做
init_flag = False
def __new__(cls, *args, **kwargs):
# 1\. 判断类属性是不是空对象
if cls.instance is None:
# 2\. 调用父类的方法,为第一个对象分配空间
cls.instance = super().__new__(cls)
# 3\. 返回类属性保存的对象引用
return cls.instance
def __init__(self):
if not MusicPlayer.init_flag:
print("初始化音乐播放器")
MusicPlayer.init_flag = True
# 建立多个对象
player1 = MusicPlayer()
print(player1)
player2 = MusicPlayer()
print(player2)
复制代码
一、Python 可以自动的将一对括号内部的代码链接在一块儿:
return ("户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s"
% (self.house_type, self.area,
self.free_area, self.item_list))
复制代码
二、一个对象的 属性 能够是 另一个类建立的对象。 三、在__init__
方法中定义类的属性时,若是 不知道设置什么初始值,能够设置为 None
):None
关键字 表示 什么都没有,表示一个 空对象,没有方法和属性,是一个特殊的常量。能够将 None 赋值给任何一个变量。
在 Python 中针对
None
比较时,建议使用is
判断
四、eval() 函数十分强大 —— 将字符串 当成 有效的表达式 来求值 并 返回计算结果
# 基本的数学计算
In [1]: eval("1 + 1")
Out[1]: 2
# 字符串重复
In [2]: eval("'*' * 10")
Out[2]: '**********'
# 将字符串转换成列表
In [3]: type(eval("[1, 2, 3, 4, 5]"))
Out[3]: list
# 将字符串转换成字典
In [4]: type(eval("{'name': 'xiaoming', 'age': 18}"))
Out[4]: dict
复制代码
在开发时千万不要使用 eval 直接转换 input 的结果,举个例子:
__import__('os').system('ls')
# 等价代码
import os
os.system("终端命令")
复制代码
参考教程: 1.【易百python教程】https://www.yiibai.com/python