关于PYTHON的编写一个python程序,输出如下语句问题,请教大神。我写了一段代码?

Python 中的 标识符 是 区分大小写的驼峰命名法当 变量名 是由二个或多个单词组成时,还可以利用驼峰命名法来命名小驼峰式命名法:第一个单词以小写字母开始,后续单词的首字母大写,例如:firstName、lastName在默认情况下,print 函数输出内容之后,会自动在内容末尾增加换行,如果不希望末尾增加换行,可以在 print 函数输出内容的后面增加 , end=""模块是 Python 程序架构的一个核心概念模块 就好比是 工具包,要想使用这个工具包中的工具,就需要 导入 import 这个模块每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块在模块中定义的 全局变量 、 函数 都是模块能够提供给外界直接使用的工具Pyc 文件:C 是 compiled 编译过 的意思pyc 文件是由 Python 解释器将 模块的源码 转换为 字节码Python 这样保存 字节码 是作为一种启动 速度的优化当 Python 重编译时,它会自动检查源文件和字节码文件的时间戳如果你又修改了源代码,下次程序运行时,字节码将自动重新创建01. 列表1.1 列表的定义List(列表) 是 Python 中使用 最频繁 的数据类型,在其他语言中通常叫做 数组专门用于存储 一串 信息列表用 [] 定义,数据 之间使用 , 分隔列表的 索引 从 0 开始
索引 就是数据在 列表 中的位置编号,索引 又可以被称为 下标
注意:从列表中取值时,如果 超出索引范围,程序会报错
name_list = ["zhangsan", "lisi", "wangwu"]
1.2 列表常用操作列表可以使用的方法如下:In [1]: name_list.
name_list.append
name_list.count
name_list.insert
name_list.reverse
name_list.clear
name_list.extend
name_list.pop
name_list.sort
name_list.copy
name_list.index
name_list.remove
序号分类关键字 / 函数 / 方法说明1增加列表.insert(索引, 数据)在指定位置插入数据列表.append(数据)在末尾追加数据列表.extend(列表2)将列表2 的数据追加到列表2修改列表[索引] = 数据修改指定索引的数据3删除del 列表[索引]删除指定索引的数据列表.remove(数据)删除第一个出现的指定数据列表.pop()删除末尾数据列表.pop(索引)删除指定索引数据列表.clear清空列表4统计len(列表)列表长度列表.count(数据)数据在列表中出现的次数5排序列表.sort()升序排序列表.sort(reverse=True)降序排序列表.reverse()逆序、反转del 关键字(科普)使用 del 关键字(delete) 同样可以删除列表中元素del 关键字本质上是用来 将一个变量从内存中删除的如果使用 del 关键字将变量从内存中删除,后续的代码就不能再使用这个变量了del name_list[1]
在日常开发中,要从列表删除数据,建议 使用列表提供的方法
1.3 循环遍历# for 循环内部使用的变量 in 列表
for name in name_list:
循环内部针对列表元素进行操作
print(name)
1.4 应用场景尽管 Python 的 列表 中可以 存储不同类型的数据但是在开发中,更多的应用场景是
列表 存储相同类型的数据通过 迭代遍历,在循环体内部,针对列表中的每一项元素,执行相同的操作02. 元组2.1 元组的定义Tuple(元组)与列表类似,不同之处在于元组的 元素不能修改
元组 表示多个元素组成的序列元组 在 Python 开发中,有特定的应用场景用于存储 一串 信息,数据 之间使用 , 分隔元组用 () 定义元组的 索引 从 0 开始
索引 就是数据在 元组 中的位置编号info_tuple = ("zhangsan", 18, 1.75)
创建空元组info_tuple = ()
元组中 只包含一个元素 时,需要 在元素后面添加逗号具体原因看另一篇博客2.2 元组常用操作info.count
info.index
2.3 循环遍历取值 就是从 元组 中获取存储在指定位置的数据遍历 就是 从头到尾 依次 从 元组 中获取数据# for 循环内部使用的变量 in 元组
for item in info:
循环内部针对元组元素进行操作
print(item)
在 Python 中,可以使用 for 循环遍历所有非数字型类型的变量:列表、元组、字典 以及 字符串提示:在实际开发中,除非 能够确认元组中的数据类型,否则针对元组的循环遍历需求并不是很多2.4 应用场景尽管可以使用 for in 遍历 元组但是在开发中,更多的应用场景是:
函数的 参数 和 返回值,一个函数可以接收 任意多个参数,或者 一次返回多个数据格式字符串,格式化字符串后面的 () 本质上就是一个元组让列表不可以被修改,以保护数据安全info = ("zhangsan", 18)
print("%s 的年龄是 %d" % info)
元组和列表之间的转换使用 list 函数可以把元组转换成列表list(元组)
使用 tuple 函数可以把列表转换成元组tuple(列表)
03. 字典3.1 字典的定义dictionary(字典) 是 除列表以外 Python 之中 最灵活 的数据类型字典同样可以用来 存储多个数据
通常用于存储 描述一个 物体 的相关信息和列表的区别
列表 是 有序 的对象集合字典 是 无序 的对象集合字典用 {} 定义字典使用 键值对 存储数据,键值对之间使用 , 分隔
键 key 是索引值 value 是数据键 和 值 之间使用 : 分隔键必须是唯一的值 可以取任何数据类型,但 键 只能使用 字符串、数字或 元组xiaoming = {"name": "小明",
"age": 18,
"gender": True,
"height": 1.75}
3.2 字典常用操作字典 能够使用的函数如下:In [1]: xiaoming.
xiaoming.clear
xiaoming.items
xiaoming.setdefault
xiaoming.copy
xiaoming.keys
xiaoming.update
xiaoming.fromkeys
xiaoming.pop
xiaoming.values
xiaoming.get
xiaoming.popitem
3.3 循环遍历遍历 就是 依次 从 字典 中获取所有键值对# for 循环内部使用的 `key 的变量` in 字典
for k in xiaoming:
print("%s: %s" % (k, xiaoming[k]))
提示:在实际开发中,由于字典中每一个键值对保存数据的类型是不同的,所以针对字典的循环遍历需求并不是很多
3.4 应用场景尽管可以使用 for in 遍历 字典但是在开发中,更多的应用场景是:
使用 多个键值对,存储 描述一个 物体 的相关信息 —— 描述更复杂的数据信息将 多个字典 放在 一个列表 中,再进行遍历,在循环体内部针对每一个字典进行 相同的处理card_list = [{"name": "张三",
"qq": "12345",
"phone": "110"},
{"name": "李四",
"qq": "54321",
"phone": "10086"}
]
04. 字符串4.1 字符串的定义字符串 就是 一串字符,是编程语言中表示文本的数据类型在 Python 中可以使用 一对双引号 " 或者 一对单引号 ' 定义一个字符串
虽然可以使用 \" 或者 \' 做字符串的转义,但是在实际开发中:
如果字符串内部需要使用 ",可以使用 ' 定义字符串如果字符串内部需要使用 ',可以使用 " 定义字符串可以使用 索引 获取一个字符串中 指定位置的字符,索引计数从 0 开始也可以使用 for 循环遍历 字符串中每一个字符
大多数编程语言都是用 " 来定义字符串
string = "Hello Python"
for c in string:
print(c)
4.2 字符串的常用操作字符串 能够使用的 方法 如下:In [1]: hello_str.
hello_str.capitalize
hello_str.isidentifier
hello_str.rindex
hello_str.casefold
hello_str.islower
hello_str.rjust
hello_str.center
hello_str.isnumeric
hello_str.rpartition
hello_str.count
hello_str.isprintable
hello_str.rsplit
hello_str.encode
hello_str.isspace
hello_str.rstrip
hello_str.endswith
hello_str.istitle
hello_str.split
hello_str.expandtabs
hello_str.isupper
hello_str.splitlines
hello_str.find
hello_str.join
hello_str.startswith
hello_str.format
hello_str.ljust
hello_str.strip
hello_str.format_map
hello_str.lower
hello_str.swapcase
hello_str.index
hello_str.lstrip
hello_str.title
hello_str.isalnum
hello_str.maketrans
hello_str.translate
hello_str.isalpha
hello_str.partition
hello_str.upper
hello_str.isdecimal
hello_str.replace
hello_str.zfill
hello_str.isdigit
hello_str.rfind
提示:正是因为 python 内置提供的方法足够多,才使得在开发时,能够针对字符串进行更加灵活的操作!应对更多的开发需求!
1) 判断类型 - 9方法说明string.isspace()如果 string 中只包含空格,则返回 Truestring.isalnum()如果 string 至少有一个字符并且所有字符都是字母或数字则返回 Truestring.isalpha()如果 string 至少有一个字符并且所有字符都是字母则返回 Truestring.isdecimal()如果 string 只包含数字则返回 True,全角数字string.isdigit()如果 string 只包含数字则返回 True,全角数字、⑴、\u00b2string.isnumeric()如果 string 只包含数字则返回 True,全角数字,汉字数字string.istitle()如果 string 是标题化的(每个单词的首字母大写)则返回 Truestring.islower()如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写,则返回 Truestring.isupper()如果 string 中包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写,则返回 True2) 查找和替换 - 7方法说明string.startswith(str)检查字符串是否是以 str 开头,是则返回 Truestring.endswith(str)检查字符串是否是以 str 结束,是则返回 Truestring.find(str, start=0, end=len(string))检测 str 是否包含在 string 中,如果 start 和 end 指定范围,则检查是否包含在指定范围内,如果是返回开始的索引值,否则返回 -1string.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 次3) 大小写转换 - 5方法说明string.capitalize()把字符串的第一个字符大写string.title()把字符串的每个单词首字母大写string.lower()转换 string 中所有大写字符为小写string.upper()转换 string 中的小写字母为大写string.swapcase()翻转 string 中的大小写4) 文本对齐 - 3方法说明string.ljust(width)返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串string.rjust(width)返回一个原字符串右对齐,并使用空格填充至长度 width 的新字符串string.center(width)返回一个原字符串居中,并使用空格填充至长度 width 的新字符串5) 去除空白字符 - 3方法说明string.lstrip()截掉 string 左边(开始)的空白字符string.rstrip()截掉 string 右边(末尾)的空白字符string.strip()截掉 string 左右两边的空白字符6) 拆分和连接 - 5方法说明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 中所有的元素(的字符串表示)合并为一个新的字符串4.3 字符串的切片切片 方法适用于 字符串、列表、元组
切片 使用 索引值 来限定范围,从一个大的 字符串 中 切出 小的 字符串列表 和 元组 都是 有序 的集合,都能够 通过索引值 获取到对应的数据字典 是一个 无序 的集合,是使用 键值对 保存数据字符串[开始索引:结束索引:步长]
注意:指定的区间属于 左闭右开 型 [开始索引, 结束索引) => 开始索引 >= 范围 < 结束索引
从 起始 位开始,到 结束位的前一位 结束(不包含结束位本身)从头开始,开始索引 数字可以省略,冒号不能省略到末尾结束,结束索引 数字可以省略,冒号不能省略步长默认为 1,如果连续切片,数字和冒号都可以省略索引的顺序和倒序在 Python 中不仅支持 顺序索引,同时还支持 倒序索引所谓倒序索引就是 从右向左 计算索引
最右边的索引值是 -1,依次递减演练需求
截取从 2 ~ 5 位置 的字符串
截取从 2 ~ 末尾 的字符串
截取从 开始 ~ 5 位置 的字符串
截取完整的字符串
从开始位置,每隔一个字符截取字符串
从索引 1 开始,每隔一个取一个
截取从 2 ~ 末尾 - 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])
05. 公共方法5.1 Python 内置函数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”5.2 切片描述Python 表达式结果支持的数据类型切片“0123456789”[::-2]“97531”字符串、列表、元组切片 使用 索引值 来限定范围,从一个大的 字符串 中 切出 小的 字符串列表 和 元组 都是 有序 的集合,都能够 通过索引值 获取到对应的数据字典 是一个 无序 的集合,是使用 键值对 保存数据5.3 运算符运算符Python 表达式结果描述支持的数据类型+[1, 2] + [3, 4][1, 2, 3, 4]合并字符串、列表、元组*[“Hi!”] * 4[‘Hi!’, ‘Hi!’, ‘Hi!’, ‘Hi!’]重复字符串、列表、元组in3 in (1, 2, 3)True元素是否存在字符串、列表、元组、字典not in4 not in (1, 2, 3)True元素是否不存在字符串、列表、元组、字典> >= == < <=(1, 2, 3) < (2, 2, 3)True元素比较字符串、列表、元组注意in 在对 字典 操作时,判断的是 字典的键in 和 not in 被称为 成员运算符成员运算符成员运算符用于 测试 序列中是否包含指定的 成员运算符描述实例in如果在指定的序列中找到值返回 True,否则返回 False3 in (1, 2, 3) 返回 Truenot in如果在指定的序列中没有找到值返回 True,否则返回 False3 not in (1, 2, 3) 返回 False注意:在对 字典 操作时,判断的是 字典的键5.4 完整的 for 循环语法在 Python 中完整的 for 循环 的语法如下:for 变量 in 集合:
循环体代码
else:
没有通过 break 退出循环,**循环结束后,会执行的代码**所以加了break说明上面的没有全部便利,下面的就不会被执行
应用场景在 迭代遍历 嵌套的数据类型时,例如 一个列表包含了多个字典需求:要判断 某一个字典中 是否存在 指定的 值
如果 存在,提示并且退出循环如果 不存在,在 循环整体结束 后,希望 得到一个统一的提示students = [
{"name": "阿土",
"age": 20,
"gender": True,
"height": 1.7,
"weight": 75.0},
{"name": "小美",
"age": 19,
"gender": False,
"height": 1.6,
"weight": 45.0},
]
find_name = "阿土"
for stu_dict in students:
print(stu_dict)
# 判断当前遍历的字典中姓名是否为find_name
if stu_dict["name"] == find_name:
print("找到了")
# 如果已经找到,直接退出循环,就不需要再对后续的数据进行比较
break
else:
print("没有找到")
print("循环结束")
python中使用 Shebang(可以直接在linux服务器中直接用./执行python文件)-1. 使用 which 查询 python3 解释器所在路径$ which python3
修改要运行的 主 python 文件,在第一行增加以下内容#! /usr/bin/python3
变量进阶01. 变量的引用
变量 和 数据 都是保存在 内存 中的在 Python 中 函数 的 参数传递 以及 返回值 都是靠 引用 传递的1.1 引用的概念在 Python 中变量 和 数据 是分开存储的数据 保存在内存中的一个位置变量 中保存着数据在内存中的地址变量 中 记录数据的地址,就叫做 引用使用 id() 函数可以查看变量中保存数据所在的 内存地址
注意:如果变量已经被定义,当给一个变量赋值的时候,本质上是 修改了数据的引用
变量 不再 对之前的数据引用变量 改为 对新赋值的数据引用1.2 变量引用 的示例在 Python 中,变量的名字类似于 便签纸 贴在 数据 上1.3 函数的参数和返回值的传递在 Python 中,函数的 实参/返回值 都是是靠 引用 来传递来的,也就是说调用函数时,调用的参数/返回的数据都用的是数据的引用而不是数据本身02. 可变和不可变类型 不可变类型,内存中的数据不允许被修改:
数字类型 int, bool, float, complex, long(2.x)字符串 str元组 tuple 可变类型,内存中的数据可以被修改:
列表 list字典 dict注意:字典的 key 只能使用不可变类型的数据注意可变类型的数据变化,是通过 方法 来实现的如果给一个可变类型的变量,赋值了一个新的数据,引用会修改
变量 不再 对之前的数据引用变量 改为 对新赋值的数据引用哈希 (hash)Python 中内置有一个名字叫做 hash(o) 的函数
接收一个 不可变类型 的数据作为 参数返回 结果是一个 整数哈希 是一种 算法,其作用就是提取数据的 特征码(指纹)
相同的内容 得到 相同的结果不同的内容 得到 不同的结果在 Python 中,设置字典的 键值对 时,会首先对 key 进行 hash 已决定如何在内存中保存字典的数据,以方便 后续 对字典的操作:增、删、改、查
键值对的 key 必须是不可变类型数据键值对的 value 可以是任意类型的数据03. 局部变量和全局变量局部变量 是在 函数内部 定义的变量,只能在函数内部使用全局变量 是在 函数外部定义 的变量(没有定义在某一个函数内),所有函数 内部 都可以使用这个变量
提示:在其他的开发语言中,大多 不推荐使用全局变量 —— 可变范围太大,导致程序不好维护!
3.1 局部变量局部变量 是在 函数内部 定义的变量,只能在函数内部使用函数执行结束后,函数内部的局部变量,会被系统回收不同的函数,可以定义相同的名字的局部变量,但是 彼此之间 不会产生影响局部变量的生命周期所谓 生命周期 就是变量从 被创建 到 被系统回收 的过程局部变量 在 函数执行时 才会被创建函数执行结束后 局部变量 被系统回收局部变量在生命周期 内,可以用来存储 函数内部临时使用到的数据3.2 全局变量全局变量 是在 函数外部定义 的变量,所有函数内部都可以使用这个变量注意:函数执行时,需要处理变量时 会:首先 查找 函数内部 是否存在 指定名称 的局部变量,如果有,直接使用如果没有,查找 函数外部 是否存在 指定名称 的全局变量,如果有,直接使用如果还没有,程序报错!1) 函数不能直接修改 全局变量的引用全局变量 是在 函数外部定义 的变量(没有定义在某一个函数内),所有函数 内部 都可以使用这个变量
提示:在其他的开发语言中,大多 不推荐使用全局变量 —— 可变范围太大,导致程序不好维护!
在函数内部,可以 通过全局变量的引用获取对应的数据但是,不允许直接修改全局变量的引用 —— 使用赋值语句修改全局变量的值
注意:只是在函数内部定义了一个局部变量而已,只是变量名相同 —— 在函数内部不能直接修改全局变量的值
2) 在函数内部修改全局变量的值如果在函数中需要修改全局变量,需要使用 global 进行声明,这个就可以在函数内部修改全局变量的名字3) 全局变量定义的位置为了保证所有的函数都能够正确使用到全局变量,应该 将全局变量定义在其他函数的上方a = 10
def demo():
print("%d" % a)
print("%d" % b)
print("%d" % c)
b = 20
demo()
c = 30
注意由于全局变量 c,是在调用函数之后,才定义的,在执行函数时,变量还没有定义,所以程序会报错!4) 全局变量命名的建议如果局部变量和全局变量的名字相同,在局部变量下面会有一个虚线为了避免局部变量和全局变量出现混淆,在定义全局变量时,有些公司会有一些开发要求,例如:全局变量名前应该增加 g_ 或者 gl_ 的前缀
提示:具体的要求格式,各公司要求可能会有些差异
函数进阶01. 函数参数和返回值的作用函数根据 有没有参数 以及 有没有返回值,可以 相互组合,一共有 4 种 组合形式无参数,无返回值无参数,有返回值有参数,无返回值有参数,有返回值
定义函数时,是否接收参数,或者是否返回结果,是根据 实际的功能需求 来决定的!
如果函数 内部处理的数据不确定,就可以将外界的数据以参数传递到函数内部如果希望一个函数 执行完成后,向外界汇报执行结果,就可以增加函数的返回值02. 函数的返回值 进阶在程序开发中,有时候,会希望 一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理返回值 是函数 完成工作后,最后 给调用者的 一个结果在函数中使用 return 关键字可以返回结果调用函数一方,可以 使用变量 来 接收 函数的返回结果
问题:一个函数执行后能否返回多个结果?提示:如果一个函数返回的是元组,括号可以省略
技巧在 Python 中,可以 将一个元组 使用 赋值语句 同时赋值给 多个变量注意:变量的数量需要和元组中的元素数量保持一致下面的就不需要记住索引,但是变量的个数要个函数返回的元素的个数保持一致result = temp, wetness = measure()
面试题 —— 交换两个数字题目要求有两个整数变量 a = 6, b = 100不使用其他变量,交换两个变量的值解法 1 —— 使用其他变量# 解法 1 - 使用临时变量
c = b
b = a
a = c
解法 2 —— 不使用临时变量# 解法 2 - 不使用临时变量
a = a + b
b = a - b
a = a - b
解法 3 —— Python 专有,利用元组a, b = b, a
03. 函数的参数 进阶3.1. 不可变和可变的参数
问题 1:在函数内部,针对参数使用 赋值语句,会不会影响调用函数时传递的 实参变量? —— 不会!
无论传递的参数是 可变 还是 不可变
只要 针对参数 使用 赋值语句,会在 函数内部 修改 局部变量的引用,不会影响到 外部变量的引用
问题 2:如果传递的参数是 可变类型,在函数内部,使用 方法 修改了数据的内容,同样会影响到外部的数据
面试题 —— +=在 python 中,列表变量调用 += 本质上是在执行列表变量的 extend 方法,不会修改变量的引用,就会改变全局变量3.2 缺省参数定义函数时,可以给 某个参数 指定一个默认值,具有默认值的参数就叫做 缺省参数调用函数时,如果没有传入 缺省参数 的值,则在函数内部使用定义函数时指定的 参数默认值函数的缺省参数,将常见的值设置为参数的缺省值,从而 简化函数的调用例如:对列表排序的方法指定函数的缺省参数在参数后使用赋值语句,可以指定参数的缺省值def print_info(name, gender=True):
gender_text = "男生"
if not gender:
gender_text = "女生"
print("%s 是 %s" % (name, gender_text))
提示缺省参数,需要使用 最常见的值 作为默认值!如果一个参数的值 不能确定,则不应该设置默认值,具体的数值在调用函数时,由外界传递!缺省参数的注意事项1) 缺省参数的定义位置必须保证 带有默认值的缺省参数 在参数列表末尾所以,以下定义是错误的!def print_info(name, gender=True, title):
2) 调用带有多个缺省参数的函数在 调用函数时,如果有 多个缺省参数,需要指定参数名,这样解释器才能够知道参数的对应关系!def print_info(name, title="", gender=True)
3.3 多值参数(知道)定义支持多值参数的函数 有时可能需要 一个函数 能够处理的参数 个数 是不确定的,这个时候,就可以使用 多值参数
python 中有 两种 多值参数:
参数名前增加 一个 * 可以接收 元组参数名前增加 两个 * 可以接收 字典 一般在给多值参数命名时,习惯使用以下两个名字
*args —— 存放 元组 参数,前面有一个 ***kwargs —— 存放 字典 参数,前面有两个 * args 是 arguments 的缩写,有变量的含义
kw 是 keyword 的缩写,kwargs 可以记忆 键值对参数 def demo(num, *args, **kwargs):
print(num)
print(args)
print(kwargs)
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)
04. 函数的递归
函数调用自身的 编程技巧 称为递归
4.1 递归函数的特点特点一个函数 内部 调用自己
函数内部可以调用其他函数,当然在函数内部也可以调用自己代码特点函数内部的 代码 是相同的,只是针对 参数 不同,处理的结果不同当 参数满足一个条件 时,函数不再执行
这个非常重要,通常被称为递归的出口,否则 会出现死循环!示例代码def sum_numbers(num):
print(num)
# 递归的出口很重要,否则会出现死循环
if num == 1:
return
sum_numbers(num - 1)
sum_numbers(3)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ufqMa578-1591928644331)(media/14993074876434/002_%E9%80%92%E5%BD%92%E8%B0%83%E7%94%A8%E7%A4%BA%E6%84%8F%E5%9B%BEI.png)]4.2 递归案例 —— 计算数字累加需求定义一个函数 sum_numbers能够接收一个 num 的整数参数计算 1 + 2 + … 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))
提示:递归是一个 编程技巧,初次接触递归会感觉有些吃力!在处理 不确定的循环条件时,格外的有用,例如:遍历整个文件目录的结构
面向对象(OOP)基本概念面向对象编程 —— Object Oriented Programming 简写 OOP目标了解 面向对象 基本概念01. 面向对象基本概念我们之前学习的编程方式就是 面向过程 的面相过程 和 面相对象,是两种不同的 编程方式对比 面向过程 的特点,可以更好地了解什么是 面向对象1.1 过程和函数(科普)过程 是早期的一个编程概念过程 类似于函数,只能执行,但是没有返回值函数 不仅能执行,还可以返回结果1.2 面相过程 和 面相对象 基本概念1) 面相过程 —— 怎么做?把完成某一个需求的 所有步骤 从头到尾 逐步实现根据开发需求,将某些 功能独立 的代码 封装 成一个又一个 函数最后完成的代码,就是顺序地调用 不同的函数特点注重 步骤与过程,不注重职责分工如果需求复杂,代码会变得很复杂开发复杂项目,没有固定的套路,开发难度很大!2) 面向对象 —— 谁来做?
相比较函数,面向对象 是 更大 的 封装,根据 职责 在 一个对象中 封装 多个方法
在完成某一个需求前,首先确定 职责 —— 要做的事情(方法)根据 职责 确定不同的 对象,在 对象 内部封装不同的 方法(多个)最后完成的代码,就是顺序地让 不同的对象 调用 不同的方法特点注重 对象和职责,不同的对象承担不同的职责更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的固定套路需要在面向过程基础上,再学习一些面向对象的语法类和对象01. 类和对象的概念类 和 对象 是 面向对象编程的 两个 核心概念1.1 类类 是对一群具有 相同 特征 或者 行为 的事物的一个统称,是抽象的,不能直接使用
特征 被称为 属性行为 被称为 方法类 就相当于制造飞机时的图纸,是一个 模板,是 负责创建对象的1.2 对象对象 是 由类创建出来的一个具体存在,可以直接使用由 哪一个类 创建出来的 对象,就拥有在 哪一个类 中定义的:
属性方法对象 就相当于用 图纸 制造 的飞机
在程序开发中,应该 先有类,再有对象
02. 类和对象的关系类是模板,对象 是根据 类 这个模板创建出来的,应该 先有类,再有对象类 只有一个,而 对象 可以有很多个
不同的对象 之间 属性 可能会各不相同类 中定义了什么 属性和方法,对象 中就有什么属性和方法,不可能多,也不可能少03. 类的设计在使用面相对象开发前,应该首先分析需求,确定一下,程序中需要包含哪些类!在程序开发中,要设计一个类,通常需要满足一下三个要素:类名 这类事物的名字,满足大驼峰命名法属性 这类事物具有什么样的特征方法 这类事物具有什么样的行为大驼峰命名法CapWords每一个单词的首字母大写单词与单词之间没有下划线3.1 类名的确定名词提炼法 分析 整个业务流程,出现的 名词,通常就是找到的类3.2 属性和方法的确定对 对象的特征描述,通常可以定义成 属性对象具有的行为(动词),通常可以定义成 方法
提示:需求中没有涉及的属性或者方法在设计类时,不需要考虑
练习 1需求小明 今年 18 岁,身高 1.75,每天早上 跑 完步,会去 吃 东西小美 今年 17 岁,身高 1.65,小美不跑步,小美喜欢 吃 东西设计“人” 类 小明和小美是对象面相对象基础语法目标dir 内置函数定义简单的类(只包含方法)方法中的 self 参数初始化方法内置方法和属性01. dir 内置函数(知道)在 Python 中 对象几乎是无所不在的,我们之前学习的 变量、数据、函数 都是对象在 Python 中可以使用以下两个方法验证:在 标识符 / 数据 后输入一个 .,然后按下 TAB 键,iPython 会提示该对象能够调用的 方法列表使用内置函数 dir 传入 标识符 / 数据,可以查看对象内的 所有属性及方法提示 __方法名__ 格式的方法是 Python 提供的 内置方法 / 属性,稍后会给大家介绍一些常用的 内置方法 / 属性序号方法名类型作用01__new__方法创建对象时,会被 自动 调用02__init__方法对象被初始化时,会被 自动 调用03__del__方法对象被从内存中销毁前,会被 自动 调用04__str__方法返回对象的描述信息,print 函数输出使用提示 利用好 dir() 函数,在学习时很多内容就不需要死记硬背了02. 定义简单的类(只包含方法)
面向对象 是 更大 的 封装,在 一个类中 封装 多个方法,这样 通过这个类创建出来的对象,就可以直接调用这些方法了!
2.1 定义只包含方法的类在 Python 中要定义一个只包含方法的类,语法格式如下:class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self, 参数列表):
pass
方法 的定义格式和之前学习过的函数 几乎一样区别在于第一个参数必须是 self,大家暂时先记住,稍后介绍 self
注意:类名 的 命名规则 要符合 大驼峰命名法
2.2 创建对象当一个类定义完成之后,要使用这个类来创建对象,语法格式如下:对象变量 = 类名()
2.3 第一个面向对象程序需求小猫 爱 吃 鱼,小猫 要 喝 水分析定义一个猫类 Cat定义两个方法 eat 和 drink按照需求 —— 不需要定义属性class Cat:
"""这是一个猫类"""
def eat(self):
print("小猫爱吃鱼")
def drink(self):
print("小猫在喝水")
tom = Cat()
tom.drink()
tom.eat()
引用概念的强调
在面向对象开发中,引用的概念是同样适用的!
在 Python 中使用类 创建对象之后,tom 变量中 仍然记录的是 对象在内存中的地址也就是 tom 变量 引用 了 新建的猫对象使用 print 输出 对象变量,默认情况下,是能够输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)
提示:在计算机中,通常使用 十六进制 表示 内存地址
十进制 和 十六进制 都是用来表达数字的,只是表示的方式不一样十进制 和 十六进制 的数字之间可以来回转换%d 可以以 10 进制 输出数字%x 可以以 16 进制 输出数字案例进阶 —— 使用 Cat 类再创建一个对象lazy_cat = Cat()
lazy_cat.eat()
lazy_cat.drink()
提问:tom 和 lazy_cat 是同一个对象吗? 不是!
03. 方法中的 self 参数3.1 案例改造 —— 给对象增加属性在 Python 中,要 给对象设置属性,非常的容易,但是不推荐使用
因为:对象属性的封装应该封装在类的内部只需要在 类的外部的代码 中直接通过 . 设置一个属性即可
注意:这种方式虽然简单,但是不推荐使用!
tom.name = "Tom"
...
lazy_cat.name = "大懒猫"
3.2 使用 self 在方法内部输出每一只猫的名字
由 哪一个对象 调用的方法,方法内的 self 就是 哪一个对象的引用
在类封装的方法内部,self 就表示 当前调用方法的对象自己
调用方法时,程序员不需要传递 self 参数
在方法内部
可以通过 self. 访问对象的属性也可以通过 self. 调用其他的对象方法 在 类的外部,通过 变量名. 访问对象的 属性和方法
在 类封装的方法中,通过 self. 访问对象的 属性和方法 04. 初始化方法4.1 之前代码存在的问题 —— 在类的外部给对象增加属性将案例代码进行调整,先调用方法 再设置属性,观察一下执行效果tom = Cat()
tom.drink()
tom.eat()
tom.name = "Tom"
print(tom)
程序执行报错如下:AttributeError: 'Cat' object has no attribute 'name'
属性错误:'Cat' 对象没有 'name' 属性
提示在日常开发中,不推荐在 类的外部 给对象增加属性
如果在运行时,没有找到属性,程序会报错对象应该包含有哪些属性,应该 封装在类的内部4.2 初始化方法当使用 类名() 创建对象时,会 自动 执行以下操作:
为对象在内存中 分配空间 —— 创建对象为对象的属性 设置初始值 —— 初始化方法(init)这个 初始化方法 就是 __init__ 方法,__init__ 是对象的内置方法
__init__ 方法是 专门 用来定义一个类 具有哪些属性的方法!
在 Cat 中增加 __init__ 方法,验证该方法在创建对象时会被自动调用class Cat:
"""这是一个猫类"""
def __init__(self):
print("初始化方法")
4.3 在初始化方法内部定义属性在 __init__ 方法内部使用 self.属性名 = 属性的初始值 就可以 定义属性定义属性之后,再使用 Cat 类创建的对象,都会拥有该属性class Cat:
def __init__(self):
print("这是一个初始化方法")
# 定义用 Cat 类创建的猫对象都有一个 name 的属性
self.name = "Tom"
def eat(self):
print("%s 爱吃鱼" % self.name)
# 使用类名()创建对象的时候,会自动调用初始化方法 __init__
tom = Cat()
tom.eat()
4.4 改造初始化方法 —— 初始化的同时设置初始值在开发中,如果希望在 创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行 改造
把希望设置的属性值,定义成 __init__ 方法的参数在方法内部使用 self.属性 = 形参 接收外部传递的参数在创建对象时,使用 类名(属性1, 属性2...) 调用class Cat:
def __init__(self, name):
print("初始化方法 %s" % name)
self.name = name
...
tom = Cat("Tom")
...
lazy_cat = Cat("大懒猫")
...
05. 内置方法和属性序号方法名类型作用01__del__方法对象被从内存中销毁前,会被 自动 调用02__str__方法返回对象的描述信息,print 函数输出使用5.1 __del__ 方法(知道) 在 Python 中
当使用 类名() 创建对象时,为对象 分配完空间后,自动 调用 __init__ 方法当一个 对象被从内存中销毁 前,会 自动 调用 __del__ 方法 应用场景
__init__ 改造初始化方法,可以让创建对象更加灵活__del__ 如果希望在对象被销毁前,再做一些事情,可以考虑一下 __del__ 方法 生命周期
一个对象从调用 类名() 创建,生命周期开始一个对象的 __del__ 方法一旦被调用,生命周期结束在对象的生命周期内,可以访问对象属性,或者让对象调用方法class Cat:
def __init__(self, new_name):
self.name = new_name
print("%s 来了" % self.name)
def __del__(self):
print("%s 去了" % self.name)
# tom 是一个全局变量
tom = Cat("Tom")
print(tom.name)
# del 关键字可以删除一个对象
del tom
print("-" * 50)
5.2 __str__ 方法在 Python 中,使用 print 输出 对象变量,默认情况下,会输出这个变量 引用的对象 是 由哪一个类创建的对象,以及 在内存中的地址(十六进制表示)如果在开发中,希望使用 print 输出 对象变量 时,能够打印 自定义的内容,就可以利用 __str__ 这个内置方法了希望在控制台打印出我们希望看到的内容的时候可以用
注意:__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)
02. 身份运算符身份运算符用于 比较 两个对象的 内存地址 是否一致 —— 是否是对同一个对象的引用在 Python 中针对 None 比较时,建议使用 is 判断运算符描述实例isis 是判断两个标识符是不是引用同一个对象x is y,类似 id(x) == id(y)is notis not 是判断两个标识符是不是引用不同对象x is not y,类似 id(a) != id(b)is 与 == 区别:is 用于判断 两个变量 引用对象是否为同一个== 用于判断 引用变量的值 是否相等>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> b is a
False
>>> b == a
True
私有属性和私有方法01. 应用场景及定义方式应用场景在实际开发中,对象 的 某些属性或方法 可能只希望 在对象的内部被使用,而 不希望在外部被访问到私有属性 就是 对象 不希望公开的 属性私有方法 就是 对象 不希望公开的 方法定义方式在 定义属性或方法时,在 属性名或者方法名前 增加 两个下划线,定义的就是 私有 属性或方法class Women:
def __init__(self, name):
self.name = name
# 不要问女生的年龄
self.__age = 18
def __secret(self):
print("我的年龄是 %d" % self.__age)
xiaofang = Women("小芳")
# 私有属性,外部不能直接访问
# print(xiaofang.__age)
# 私有方法,外部不能直接调用
# xiaofang.__secret()
02. 伪私有属性和私有方法
提示:在日常开发中,不要使用这种方式,访问对象的 私有属性 或 私有方法
Python 中,并没有 真正意义 的 私有在给 属性、方法 命名时,实际是对 名称 做了一些特殊处理,使得外界无法访问到处理方式:在 名称 前面加上 _类名 => _类名__名称# 私有属性,外部不能直接访问到
print(xiaofang._Women__age)
# 私有方法,外部不能直接调用
xiaofang._Women__secret()
单例目标单例设计模式__new__ 方法Python 中的单例01. 单例设计模式 设计模式
设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案使用 设计模式 是为了可重用代码、让代码更容易被他人理解、保证代码可靠性 单例设计模式
目的 —— 让 类 创建的对象,在系统中 只有 唯一的一个实例每一次执行 类名() 返回的对象,内存地址是相同的单例设计模式的应用场景音乐播放 对象回收站 对象打印机 对象……02. __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)
03. Python 中的单例单例 —— 让 类 创建的对象,在系统中 只有 唯一的一个实例
定义一个 类属性,初始值是 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)
多态目标多态面向对象三大特性封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中
定义类的准则继承 实现代码的重用,相同的代码不需要重复的编写
设计类的技巧子类针对自己特有的需求,编写特定的代码多态 不同的 子类对象 调用相同的 父类方法,产生不同的执行结果
多态 可以 增加代码的灵活度以 继承 和 重写父类方法 为前提是调用方法的技巧,不会影响到类的内部设计多态案例演练需求在 Dog 类中封装方法 game
普通狗只是简单的玩耍定义 XiaoTianDog 继承自 Dog,并且重写 game 方法
哮天犬需要在天上玩耍定义 Person 类,并且封装一个 和狗玩 的方法
在方法内部,直接让 狗对象 调用 game 方法案例小结Person 类中只需要让 狗对象 调用 game 方法,而不关心具体是 什么狗
game 方法是在 Dog 父类中定义的在程序执行时,传入不同的 狗对象 实参,就会产生不同的执行效果
多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!
class Dog(object):
def __init__(self, name):
self.name = name
def game(self):
print("%s 蹦蹦跳跳的玩耍..." % self.name)
class XiaoTianDog(Dog):
def game(self):
print("%s 飞到天上去玩耍..." % self.name)
class Person(object):
def __init__(self, name):
self.name = name
def game_with_dog(self, dog):
print("%s 和 %s 快乐的玩耍..." % (self.name, dog.name))
# 让狗玩耍
dog.game()
# 1. 创建一个狗对象
# wangcai = Dog("旺财")
wangcai = XiaoTianDog("飞天旺财")
# 2. 创建一个小明对象
xiaoming = Person("小明")
# 3. 让小明调用和狗玩的方法
xiaoming.game_with_dog(wangcai)
继承目标单继承多继承面向对象三大特性封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中继承 实现代码的重用,相同的代码不需要重复的编写多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度01. 单继承1.1 继承的概念、语法和特点继承的概念:子类 拥有 父类 的所有 方法 和 属性1) 继承的语法class 类名(父类名):
pass
子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发子类 中应该根据 职责,封装 子类特有的 属性和方法2) 专业术语Dog 类是 Animal 类的子类,Animal 类是 Dog 类的父类,Dog 类从 Animal 类继承Dog 类是 Animal 类的派生类,Animal 类是 Dog 类的基类,Dog 类从 Animal 类派生3) 继承的传递性C 类从 B 类继承,B 类又从 A 类继承那么 C 类就具有 B 类和 A 类的所有属性和方法子类 拥有 父类 以及 父类的父类 中封装的所有 属性 和 方法1.2 方法的重写子类 拥有 父类 的所有 方法 和 属性子类 继承自 父类,可以直接 享受 父类中已经封装好的方法,不需要再次开发应用场景当 父类 的方法实现不能满足子类需求时,可以对方法进行 重写(override)重写 父类方法有两种情况:覆盖 父类的方法对父类方法进行 扩展1) 覆盖父类的方法如果在开发中,父类的方法实现 和 子类的方法实现,完全不同就可以使用 覆盖 的方式,在子类中 重新编写 父类的方法实现
具体的实现方式,就相当于在 子类中 定义了一个 和父类同名的方法并且实现
重写之后,在运行时,只会调用 子类中重写的方法,而不再会调用 父类封装的方法2) 对父类方法进行 扩展如果在开发中,子类的方法实现 中 包含 父类的方法实现
父类原本封装的方法实现 是 子类方法的一部分就可以使用 扩展 的方式
在子类中 重写 父类的方法在需要的位置使用 super().父类方法 来调用父类方法的执行代码其他的位置针对子类的需求,编写 子类特有的代码实现关于 super在 Python 中 super 是一个 特殊的类super() 就是使用 super 类创建出来的对象最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现1.3 父类的 私有属性 和 私有方法子类对象 不能 在自己的方法内部,直接 访问 父类的 私有属性 或 私有方法子类对象 可以通过 父类 的 公有方法 间接 访问到 私有属性 或 私有方法
私有属性、方法 是对象的隐私,不对外公开,外界 以及 子类 都不能直接访问私有属性、方法 通常用于做一些内部的事情02. 多继承概念子类 可以拥有 多个父类,并且具有 所有父类 的 属性 和 方法例如:孩子 会继承自己 父亲 和 母亲 的 特性语法class 子类名(父类名1, 父类名2...)
pass
2.1 多继承的使用注意事项问题的提出如果 不同的父类 中存在 同名的方法,子类对象 在调用方法时,会调用 哪一个父类中的方法呢?
提示:开发时,应该尽量避免这种容易产生混淆的情况! —— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承
Python 中的 MRO —— 方法搜索顺序Python 中针对 类 提供了一个 内置属性 __mro__ 可以查看 方法 搜索顺序MRO 是 method resolution order,主要用于 在多继承时判断 方法、属性 的调用 路径print(C.__mro__)
输出结果(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
在搜索方法时,是按照 __mro__ 的输出结果 从左至右 的顺序查找的如果在当前类中 找到方法,就直接执行,不再搜索如果 没有找到,就查找下一个类 中是否有对应的方法,如果找到,就直接执行,不再搜索如果找到最后一个类,还没有找到方法,程序报错2.2 新式类与旧式(经典)类
object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看
新式类:以 object 为基类的类,推荐使用
经典类:不以 object 为基类的类,不推荐使用
在 Python 3.x 中定义类时,如果没有指定父类,会 默认使用 object 作为该类的 基类 —— Python 3.x 中定义的类都是 新式类
在 Python 2.x 中定义类时,如果没有指定父类,则不会以 object 作为 基类
新式类 和 经典类 在多继承时 —— 会影响到方法的搜索顺序
为了保证编写的代码能够同时在 Python 2.x 和 Python 3.x 运行!今后在定义类时,如果没有父类,建议统一继承自 objectclass 类名(object):
pass
类属性和类方法目标类的结构类属性和实例属性类方法和静态方法01. 类的结构1.1 术语 —— 实例使用面相对象开发,第 1 步 是设计 类使用 类名() 创建对象,创建对象 的动作有两步:
在内存中为对象 分配空间
调用初始化方法 __init__ 为 对象初始化对象创建后,内存 中就有了一个对象的 实实在在 的存在 —— 实例因此,通常也会把:创建出来的 对象 叫做 类 的 实例创建对象的 动作 叫做 实例化对象的属性 叫做 实例属性对象调用的方法 叫做 实例方法在程序执行时:对象各自拥有自己的 实例属性调用对象方法,可以通过 self.
访问自己的属性调用自己的方法结论每一个对象 都有自己 独立的内存空间,保存各自不同的属性多个对象的方法,在内存中只有一份,在调用方法时,需要把对象的引用 传递到方法内部1.2 类是一个特殊的对象
Python 中 一切皆对象:
class AAA: 定义的类属于 类对象obj1 = AAA() 属于 实例对象在程序运行时,类 同样 会被加载到内存在 Python 中,类 是一个特殊的对象 —— 类对象在程序运行时,类对象 在内存中 只有一份,使用 一个类 可以创建出 很多个对象实例除了封装 实例 的 属性 和 方法外,类对象 还可以拥有自己的 属性 和 方法
类属性类方法通过 类名. 的方式可以 访问类的属性 或者 调用类的方法02. 类属性和实例属性2.1 概念和使用类属性 就是给 类对象 中定义的 属性通常用来记录 与这个类相关 的特征类属性 不会用于记录 具体对象的特征示例需求定义一个 工具类每件工具都有自己的 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)
2.2 属性的获取机制(科普)注意如果使用 对象.类属性 = 值 赋值语句,只会 给对象添加一个属性,而不会影响到 类属性的值03. 类方法和静态方法3.1 类方法类属性 就是针对 类对象 定义的属性
使用 赋值语句 在 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)
在类方法内部,可以直接使用 cls 访问 类属性 或者 调用类方法
3.2 静态方法语法如下@staticmethod
def 静态方法名():
pass
静态方法 需要用 修饰器 @staticmethod 来标识,告诉解释器这是一个静态方法通过 类名. 调用 静态方法class Dog(object):
# 狗对象计数
dog_count = 0
@staticmethod
def run():
# 不需要访问实例属性也不需要访问类属性的方法
print("狗在跑...")
def __init__(self, name):
self.name = name
3.3 方法综合案例需求设计一个 Game 类属性:
定义一个 类属性 top_score 记录游戏的 历史最高分定义一个 实例属性 player_name 记录 当前游戏的玩家姓名方法:
静态方法 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()
异常目标异常的概念捕获异常异常的传递抛出异常01. 异常的概念程序在运行时,如果 Python 解释器 遇到 到一个错误,会停止程序的执行,并且提示一些错误信息,这就是 异常程序停止执行并且提示错误信息 这个动作,我们通常称之为:抛出(raise)异常
程序开发时,很难将 所有的特殊情况 都处理的面面俱到,通过 异常捕获 可以针对突发事件做集中的处理,从而保证程序的 稳定性和健壮性
02. 捕获异常2.1 简单的捕获异常语法在程序开发中,如果 对某些代码的执行不能确定是否正确,可以增加 try(尝试) 来 捕获异常捕获异常最简单的语法格式:try:
尝试执行的代码
except:
出现错误的处理
try 尝试,下方编写要尝试代码,不确定是否能够正常执行的代码except 如果不是,下方编写尝试失败的代码简单异常捕获演练 —— 要求用户输入整数try:
# 提示用户输入一个数字
num = int(input("请输入数字:"))
except:
print("请输入正确的数字")
2.2 错误类型捕获try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except (错误类型2, 错误类型3):
# 针对错误类型2 和 3,对应的代码处理
pass
except Exception as result:
print("未知错误 %s" % result)
当 Python 解释器 抛出异常 时,最后一行错误信息的第一个单词,就是错误类型异常类型捕获演练 —— 要求用户输入整数需求提示用户输入一个整数使用 8 除以用户输入的整数并且输出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)
2.3 异常捕获完整语法在实际开发中,为了能够处理复杂的异常情况,完整的异常语法如下:
提示:
有关完整语法的应用场景,在后续学习中,结合实际的案例会更好理解现在先对这个语法结构有个印象即可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("执行完成,但是不保证正确")
03. 异常的传递异常的传递 —— 当 函数/方法 执行 出现异常,会 将异常传递 给 函数/方法 的 调用一方如果 传递到主程序,仍然 没有异常处理,程序才会被终止
提示
在开发中,可以在主函数中增加 异常捕获而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的 异常捕获 中这样就不需要在代码中,增加大量的 异常捕获,能够保证代码的整洁需求定义函数 demo1() 提示用户输入一个整数并且返回定义函数 demo2() 调用 demo1()在主程序中调用 demo2()def demo1():
return int(input("请输入一个整数:"))
def demo2():
return demo1()
try:
print(demo2())
except ValueError:
print("请输入正确的整数")
except Exception as result:
print("未知错误 %s" % result)
04. 抛出 raise 异常4.1 应用场景在开发中,除了 代码执行出错 Python 解释器会 抛出 异常之外还可以根据 应用程序 特有的业务需求 主动抛出异常示例提示用户 输入密码,如果 长度少于 8,抛出 异常注意当前函数 只负责 提示用户输入密码,如果 密码长度不正确,需要其他的函数进行额外处理因此可以 抛出异常,由其他需要处理的函数 捕获异常4.2 抛出异常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)
模块和包目标01. 模块1.1 模块的概念
模块是 Python 程序架构的一个核心概念
每一个以扩展名 py 结尾的 Python 源代码文件都是一个 模块模块名 同样也是一个 标识符,需要符合标识符的命名规则在模块中定义的 全局变量 、函数、类 都是提供给外界直接使用的 工具模块 就好比是 工具包,要想使用这个工具包中的工具,就需要先 导入 这个模块1.2 模块的两种导入方式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 *
注意
这种方式不推荐使用,因为函数重名并没有任何的提示,出现问题不好排查
1.3 模块的搜索顺序[扩展]Python 的解释器在 导入模块 时,会:搜索 当前目录 指定模块名的文件,如果有就直接导入如果没有,再搜索 系统目录
在开发时,给文件起名,不要和 系统的模块文件 重名
Python 中每一个模块都有一个内置属性 __file__ 可以 查看模块 的 完整路径示例import random
# 生成一个 0~10 的数字
rand = random.randint(0, 10)
print(rand)
注意:如果当前目录下,存在一个 random.py 的文件,程序就无法正常执行了!
这个时候,Python 的解释器会 加载当前目录 下的 random.py 而不会加载 系统的 random 模块1.4 原则 —— 每一个文件都应该是可以被导入的一个 独立的 Python 文件 就是一个 模块在导入文件时,文件中 所有没有任何缩进的代码 都会被执行一遍! 非常重要!!!!!实际开发场景在实际开发中,每一个模块都是独立开发的,大多都有专人负责开发人员 通常会在 模块下方 增加一些测试代码
仅在模块内使用,而被导入到其他文件中不需要执行__name__ 属性
__name__ 属性可以做到,测试模块的代码 只在测试情况下被运行,而在 被导入时不会被执行!__name__ 是 Python 的一个内置属性,记录着一个 字符串如果 是被其他文件导入的,__name__ 就是 模块名如果 是当前执行的程序 __name__ 是 __main__在很多 Python 文件中都会看到以下格式的代码:# 导入模块
# 定义全局变量
# 定义类
# 定义函数
# 在代码的最下方
def main():
# ...
pass
# 根据 __name__ 判断是否执行下方代码
if __name__ == "__main__":
main()
02. 包(Package)概念包 是一个 包含多个模块 的 特殊目录目录下有一个 特殊的文件 __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
03. 发布模块如果希望自己开发的模块,分享 给其他人,可以按照以下步骤操作3.1 制作发布压缩包步骤1) 创建 setup.pysetup.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"])
有关字典参数的详细信息,可以参阅官方网站:https://docs.python.org/2/distutils/apiref.html2) 构建模块$ python3 setup.py build
3) 生成发布压缩包$ python3 setup.py sdist
注意:要制作哪个版本的模块,就使用哪个版本的解释器执行!
3.2 安装模块$ tar -zxvf hm_message-1.0.tar.gz
$ sudo python3 setup.py install
卸载模块直接从安装目录下,把安装模块的 目录 删除就可以$ cd /usr/local/lib/python3.5/dist-packages/
$ sudo rm -r hm_message*
3.3 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
在 Mac 下安装 iPython$ sudo pip install ipython
在 Linux 下安装 iPython$ sudo apt install ipython
$ sudo apt install ipython3
文件目标文件的概念文件的基本操作文件/文件夹的常用操作文本文件的编码方式01. 文件的概念1.1 文件的概念和作用计算机的 文件,就是存储在某种 长期储存设备 上的一段 数据长期存储设备包括:硬盘、U 盘、移动硬盘、光盘…文件的作用将数据长期保存下来,在需要的时候使用1.2 文件的存储方式在计算机中,文件是以 二进制 的方式保存在磁盘上的文本文件和二进制文件 文本文件
可以使用 文本编辑软件 查看本质上还是二进制文件例如:python 的源程序 二进制文件
保存的内容 不是给人直接阅读的,而是 提供给其他软件使用的例如:图片文件、音频文件、视频文件等等二进制文件不能使用 文本编辑软件 查看02. 文件的基本操作2.1 操作文件的套路在 计算机 中要操作文件的套路非常固定,一共包含三个步骤:打开文件读、写文件
读 将文件内容读入内存写 将内存内容写入文件关闭文件2.2 操作文件的函数/方法在 Python 中要操作文件需要记住 1 个函数和 3 个方法序号函数/方法说明01open打开文件,并且返回文件操作对象02read将文件内容读取到内存03write将指定内容写入文件04close关闭文件open 函数负责打开文件,并且返回文件对象read/write/close 三个方法都需要通过 文件对象 来调用2.3 read 方法 —— 读取文件open 函数的第一个参数是要打开的文件名(文件名区分大小写)
如果文件 存在,返回 文件操作对象如果文件 不存在,会 抛出异常read 方法可以一次性 读入 并 返回 文件的 所有内容close 方法负责 关闭文件
如果 忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问注意:read 方法执行后,会把 文件指针 移动到 文件的末尾# 1. 打开 - 文件名需要注意大小写
file = open("README")
# 2. 读取
text = file.read()
print(text)
# 3. 关闭
file.close()
提示在开发中,通常会先编写 打开 和 关闭 的代码,再编写中间针对文件的 读/写 操作!文件指针(知道)文件指针 标记 从哪个位置开始读取数据第一次打开 文件时,通常 文件指针会指向文件的开始位置当执行了 read 方法后,文件指针 会移动到 读取内容的末尾
默认情况下会移动到 文件末尾思考如果执行了一次 read 方法,读取了所有内容,那么再次调用 read 方法,还能够获得到内容吗?答案不能第一次读取之后,文件指针移动到了文件末尾,再次调用不会读取到任何的内容2.4 打开文件的方式open 函数默认以 只读方式 打开文件,并且返回文件对象语法如下:f = open("文件名", "访问方式")
访问方式说明r以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常w以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件a以追加方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入r+以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常w+以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件a+以读写方式打开文件。如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入提示频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以 只读、只写 的方式来操作文件写入文件示例# 打开文件
f = open("README", "w")
f.write("hello python!\n")
f.write("今天天气真好")
# 关闭文件
f.close()
2.5 按行读取文件内容read 方法默认会把文件的 所有内容 一次性读取到内存如果文件太大,对内存的占用会非常严重readline 方法readline 方法可以一次读取一行内容方法执行后,会把 文件指针 移动到下一行,准备再次读取读取大文件的正确姿势# 打开文件
file = open("README")
while True:
# 读取一行内容
text = file.readline()
# 判断是否读到内容
if not text:
break
# 每读取一行的末尾已经有了一个 `\n`
print(text, end="")
# 关闭文件
file.close()
2.6 文件读写案例 —— 复制文件目标用代码的方式,来实现文件复制过程小文件复制打开一个已有文件,读取完整内容,并写入到另外一个文件# 1. 打开文件
file_read = open("README")
file_write = open("README[复件]", "w")
# 2. 读取并写入文件
text = file_read.read()
file_write.write(text)
# 3. 关闭文件
file_read.close()
file_write.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()
03. 文件/目录的常用管理操作在 终端 / 文件浏览器、 中可以执行常规的 文件 / 目录 管理操作,例如:
创建、重命名、删除、改变路径、查看目录内容、……在 Python 中,如果希望通过程序实现上述功能,需要导入 os 模块文件操作序号方法名说明示例01rename重命名文件os.rename(源文件名, 目标文件名)02remove删除文件os.remove(文件名)目录操作序号方法名说明示例01listdir目录列表os.listdir(目录名)02mkdir创建目录os.mkdir(目录名)03rmdir删除目录os.rmdir(目录名)04getcwd获取当前目录os.getcwd()05chdir修改工作目录os.chdir(目标目录)06path.isdir判断是否是文件os.path.isdir(文件路径)
提示:文件或者目录操作都支持 相对路径 和 绝对路径
04. 文本文件的编码格式(科普)文本文件存储的内容是基于 字符编码 的文件,常见的编码有 ASCII 编码,UNICODE 编码等
Python 2.x 默认使用 ASCII 编码格式Python 3.x 默认使用 UTF-8 编码格式
4.1 ASCII 编码和 UNICODE 编码ASCII 编码计算机中只有 256 个 ASCII 字符一个 ASCII 在内存中占用 1 个字节 的空间
8 个 0/1 的排列组合方式一共有 256 种,也就是 2 ** 8UTF-8 编码格式计算机中使用 1~6 个字节 来表示一个 UTF-8 字符,涵盖了 地球上几乎所有地区的文字大多数汉字会使用 3 个字节 表示UTF-8 是 UNICODE 编码的一种编码格式4.2 Ptyhon 2.x 中如何使用中文
Python 2.x 默认使用 ASCII 编码格式Python 3.x 默认使用 UTF-8 编码格式
在 Python 2.x 文件的 第一行 增加以下代码,解释器会以 utf-8 编码来处理 python 文件# *-* coding:utf8 *-*
这方式是官方推荐使用的!
也可以使用# coding=utf8
unicode 字符串在 Python 2.x 中,即使指定了文件使用 UTF-8 的编码格式,但是在遍历字符串时,仍然会 以字节为单位遍历 字符串要能够 正确的遍历字符串,在定义字符串时,需要 在字符串的引号前,增加一个小写字母 u,告诉解释器这是一个 unicode 字符串(使用 UTF-8 编码格式的字符串)(UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式)# *-* coding:utf8 *-*
# 在字符串前,增加一个 `u` 表示这个字符串是一个 utf8 字符串
hello_str = u"你好世界"
print(hello_str)
for c in hello_str:
print(c)
eval 函数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
案例 - 计算器需求提示用户输入一个 加减乘除混合运算返回计算结果input_str = input("请输入一个算术题:")
print(eval(input_str))
不要滥用 eval
在开发时千万不要使用 eval 直接转换 input 的结果!!!! 用户可以自己调用os里面的命令!!!
__import__('os').system('ls')
等价代码import os
os.system("终端命令")
执行成功,返回 0执行失败,返回错误信息
在上一课中,我们已经了解了Python语言并安装了运行Python程序所需的环境,相信大家已经迫不及待的想开始自己的Python编程之旅了。首先我们来看看应该在哪里编写我们的Python程序。编写代码的工具交互式环境我们打开Windows的“命令提示符”工具,输入命令python然后回车就可以进入到Python的交互式环境中。所谓交互式环境,就是我们输入一行代码回车,代码马上会被执行,如果代码有产出结果,那么结果会被显示在窗口中。例如:Python 3.7.6
Type "help", "copyright", "credits" or "license" for more information.
>>> 2 * 3
6
>>> 2 + 3
5提示:使用macOS系统的用户需要打开“终端”工具,输入python3进入交互式环境。 如果希望退出交互式环境,可以在交互式环境中输入quit(),如下所示。>>> quit()更好的交互式环境 - IPythonPython默认的交互式环境用户体验并不怎么好,我们可以用IPython来替换掉它,因为IPython提供了更为强大的编辑和交互功能。我们可以使用Python的包管理工具pip来安装IPython,如下所示。pip install ipython温馨提示:在使用上面的命令安装IPython之前,可以先通过pip config set global.index-url https://pypi.doubanio.com/simple命令将pip的下载源修改为国内的豆瓣网,否则下载安装的过程可能会非常的缓慢。 可以使用下面的命令启动IPython,进入交互式环境。ipython文本编辑器 - Visual Studio CodeVisual Studio Code(通常简称为VSCode)是一个由微软开发能够在Windows、 Linux和macOS等操作系统上运行的代码编辑神器。它支持语法高亮、自动补全、多点编辑、运行调试等一系列便捷功能,而且能够支持多种编程语言。如果大家要选择一款高级文本编辑工具,强烈建议使用VSCode。关于VSCode的下载、安装和使用,推荐大家阅读一篇名为《VScode安装使用》的文章。集成开发环境 - PyCharm如果用Python开发商业项目,我们推荐大家使用更为专业的工具PyCharm。PyCharm是由捷克一家名为JetBrains的公司开发的用于Python项目开发的集成开发环境(IDE)。所谓集成开发环境,通常是指工具中提供了编写代码、运行代码、调试代码、分析代码、版本控制等一系列功能,因此特别适合商业项目的开发。在JetBrains的官方网站上提供了PyCharm的下载链接,其中社区版(Community)是免费的但功能相对弱小(其实已经足够强大了),专业版(Professional)功能非常强大,但需要按年或月付费使用,新用户可以试用30天时间。运行PyCharm,可以看到如下图所示的欢迎界面,可以选择“New Project”来创建一个新的项目。创建项目的时候需要指定项目的路径并创建运行项目的”虚拟环境“,如下图所示。项目创建好以后会出现如下图所示的画面,我们可以通过在项目文件夹上点击鼠标右键,选择“New”菜单下的“Python File”来创建一个Python文件,创建好的Python文件会自动打开进入可编辑的状态。写好代码后,可以在编辑代码的窗口点击鼠标右键,选择“Run”菜单项来运行代码,下面的“Run”窗口会显示代码的执行结果,如下图所示。PyCharm常用的快捷键如下表所示,我们也可以在“File”菜单的“Settings”中定制PyCharm的快捷键(macOS系统是在“PyCharm”菜单的“Preferences”中对快捷键进行设置)。表1. PyCharm常用快捷说明:使用macOS系统,可以将上面的ctrl键换成command键,在macOS系统上,可以使用ctrl + space组合键来获得万能提示,在Windows系统上不能使用该快捷键,因为它跟Windows默认的切换输入法的快捷键是冲突的,需要重新设置。 hello, world按照行业惯例,我们学习任何一门编程语言写的第一个程序都是输出hello, world,因为这段代码是伟大的丹尼斯·里奇(C语言之父,和肯·汤普森一起开发了Unix操作系统)和布莱恩·柯尼汉(awk语言的发明者)在他们的不朽著作The C Programming Language中写的第一段代码。print('hello, world')运行程序如果不使用PyCharm这样的集成开发环境,我们可以将上面的代码命名为hello.py,对于Windows操作系统,可以在你保存代码的目录下先按住键盘上的shift键再点击鼠标右键,这时候鼠标右键菜单中会出现“命令提示符”选项,点击该选项就可以打开“命令提示符”工具,我们输入下面的命令。python hello.py提醒:我们也可以在任意位置打开“命令提示符”,然后将需要执行的Python代码通过拖拽的方式拖入到“命令提示符”中,这样相当于指定了文件的绝对路径来运行该文件中的Python代码。再次提醒,macOS系统要通过python3命令来运行该程序。 你可以尝试将上面程序单引号中的hello, world换成其他内容;你也可以尝试着多写几个这样的语句,看看会运行出怎样的结果。需要提醒大家,上面代码中的print('hello, world')就是一条完整的语句,我们用Python写程序,最好每一行代码中只有一条语句。虽然使用;分隔符可以将多个语句写在一行代码中,但是最好不要这样做,因为代码会变得非常难看。注释你的代码注释是编程语言的一个重要组成部分,用于在源代码中解释代码的作用从而增强程序的可读性。当然,我们也可以将源代码中暂时不需要运行的代码段通过注释来去掉,这样当你需要重新使用这些代码的时候,去掉注释符号就可以了。简单的说,注释会让代码更容易看懂但不会影响程序的执行结果。Python中有两种形式的注释:单行注释:以#和空格开头,可以注释掉从#开始后面一整行的内容。多行注释:三个引号开头,三个引号结尾,通常用于添加多行说明性内容。"""
第一个Python程序 - hello, world
Version: 0.1
Author: 骆昊
"""
# print('hello, world')
print("你好,世界!")总结到这里,我们已经把第一个Python程序运行起来了,是不是很有成就感?只要你坚持学习下去,再过一段时间,我们就可以用Python制作小游戏、编写爬虫程序、完成办公自动化操作等。写程序本身就是一件很酷的事情,在未来编程就像英语一样,对很多人来说或都是必须要掌握的技能。温馨提示:如果喜欢本专栏,请不要吝惜你的点赞。可以在B站获取本课程配套的视频,地址:Python速成教程零基础快速上手。

我要回帖

更多关于 编写一个python程序,输出如下语句 的文章