一、计算机的三大组件
一、计算机包含有较多的硬件,但是一个程序要运行,有三个核心的硬件,分别是:
- CPU
中央处理器,是一块超大规模的集成电路
负责处理数据/计算 - 内存
临时存储数据(断电之后,数据会消失)
速度快
空间小
价格高 - 硬盘
永久存储数据
速度慢
空间大
价格便宜
二、程序执行的原理
1.程序要运行前,程序是保存在硬盘中的
2.当要运行一个程序时候
- 操作系统会首先让CPU把程序 复制到内存中
- CPU执行内存中的程序代码
程序要执行,首先要被加载到内存中
2.1Python程序执行原理
- 操作系统会首先让CPU把Python解释器的程序复制到内存中
- Python解释器根据语法规则,从上向下让CPU翻译Python程序中的代码
- CPU负责执行翻译完成的代码
三、思考
QQ这个程序是怎么保存用户的QQ号码和密码的?
答案:
1.在内存为QQ号码和QQ密码各自分配一块空间
- 在QQ程序结束之前,这两块空间是由QQ程序负责管理的,其他任何程序都不允许使用
- 在QQ自己使用完成之前,这两块空间始终都只负责保存QQ号码和QQ密码
2.使用一个别名标记QQ号码和QQ密码在内存中的未知
二、变量
一、变量赋值
- 每个变量在内存中创建,都包含变量的标识,名称和数据这些信息
- 每个变量在使用前必须赋值,变量赋值以后该变量才会创建
- 等号(=)用来给变量赋值,等号(=)运算符左边是一个变量名,右边是存储在变量中的值
二、变量的类型
Python中的变量赋值不需要类型声明
数据类型可以分为数字型和非数字型
- 数字型:
- 整型 - int
- 浮点型 - float
- 布尔型 - bool -> True Flase
- 复数型 - 主要用于科学计算,例如平面场问题、电感问题、波动问题
- 非数字型:
- 字符串
- 列表
- 元组
- 字典
提示:在Python2.x,整数根据保存数值的长度还分为:int(整型) long(长整数)
三、不同类型的变量直接的计算
- 数字型变量之间可以直接计算 : 如果变量是bool型,在计算时True对应的数字是1,False是0
- 字符串变量之间使用+拼接字符串得到一个新的字符串
四、变量的输入
input实现键盘的输入:
- 在Python中可以使用input函数从键盘等待用户的输入
- 用户输入的任何内容Python都认为是一个字符串
- 字符串变量 = input(“提示信息:”)
五、变量的格式化输出
- %被称为格式化操作符,专门用于处理字符串中的格式
- %和不同字符连用,不同类型的数据需要使用不同的格式化字符
% s | 字符串 |
---|---|
%d | 有符号十进制整数,%06d表示输出的整数显示位数,不足的补0 |
%f | 浮点数,%.02f表示小数点后只显示两位 |
%% | 输出% |
例子:
# 定义字符串name,输出我的名字叫做小明,请多多指教
name = "小明"
print("我得名字叫%s,请多多关照" % name)
# 定义整数变量,student输出我的学号是000001
student = 1
print("物品的学号%06d" % student)
# 定义小数price,weight,money,输出苹果单价9.00元/斤,购买了5.00斤,需要支付45.00元
price = 8.5
weight = 7.5
money = price * weight
print("苹果单价%.2f,购买了%.2f,需要支付%.2f" % (price, weight, money))
# 定义一个scale,输出数据比例是10.005
sclae = 0.25
print("输出的比例是 %.2f%%" % (sclae * 100))
a = "小美"
print("我的名字叫做%s" % a)
六、标识符的命名
- 标识符就是程序员定义的变量名、函数名(名字需要见名之意)
- 标识符可以由字母、下划线和数字组成,不能以数字开头,不能与关键字重名
七、变量的命名规则
- 命名规则可以视为一种惯例,并无绝对与强制,目的视为了增加代码的识别和可读性
- 定义变量时,为了保证代码格式,=左右应该各保留一个空格
- 在Python中,如果变量名需要由两个或多个单词组成时,可以由以下命名方式
- 每个单词都使用小写字母
- 单词与单词之间使用下划线_连接
- 例如:first_name last_number qq_number qq_password
八、关键字
关键字就是在python内部已经使用的标识符,关键字具有特殊的功能和含义,开发者不允许定义和关键字相同的名字的标识符
通过以下命令可以查看python中的关键字:
import keyword
print(keyword.kwlist)
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
三、循环判断语句
一、判断语句(if语句)
1.if语句的基本语法:
if 要判断的条件:
条件成立时,要做的事情
......
注意:代码缩进为一个tab键,或者4个空格
·在Python开发中,Tab和空格不要混淆
二.else处理条件不满足的情况
if 要判断的条件:
条件成立时,要做的事情
......
else:
条件不成立时,要做的事情
......
三.逻辑运算
- 在程序开发中,通常在判断条件时,会需要同时判断多个条件
- 只有多个条件按都满足,才能执行后续代码,这个时候需要时使用逻辑运算符
- 逻辑运算符可以把多个条件按照逻辑进行连接,变成更复杂的条件
- python中的逻辑运算符包括:and/or/not三种
案例1:
定义一个整数变量age,编写代码判断年龄是否正确,要求人的年龄0-120岁
age = int(input("请输入您的年龄"))
if age >= 0 and age <=120:
print("在范围内")
else:
print("年龄不在范围内")
案例2:
定义两个整数变量p_score、p_score,编写代码判断成绩,要求只有一门成绩>60就算及格
p_score=80
s_score=75
if p_socre or s_score>60:
print("及格")
else:
print("考试失败,继续努力")
案例3:
定义一个布尔型变量employee,编写代码判断是否时本公司员工
employee=True
if not employee:
print("非本公司员工")
else:
print("是本公司员工")
四、if语句进阶
2.关于elif
- 在开发中,使用if可以判断条件
- 使用else可以处理条件不成绩的情况
- 但是,如果希望在增加一些条件,条件不同,需要执行的代码也不同时,就可以使用elif
if 条件1:
条件1满足,执行的代码
......
elif 条件2:
条件2满足时,执行的代码
elif 条件3:
条件3满足时,执行的代码
else:
以上条件都不满足时,执行的代码
....
对比逻辑运算符代码:
if 条件1 and 条件2:
条件1满足 并且 条件2满足 执行的代码
...
四·二、if的嵌套
elif的应用场景是:同时判断多个条件,所有条件都是平级的
- 在开发中,使用if进行条件判断,如果希望在条件成立的执行语句中再增加条件判断,就可以使用if嵌套
- if的嵌套的语法格式:除了缩进之外和之前没有区别
语法格式如下:
if 条件1:
条件1满足执行的代码
....
if 条件1 基础上的条件2:
条件2满足时,执行的代码
....
# 条件2不满足的处理
else:
条件2不满足时,执行的代码
# 条件1不满足的处理
else:
条件1不满足时,执行的代码
.....
案例1:
#定义布尔型变量 has_ticket 表示是否有车票
has_ticket = True
#定义整型变量 knife_length 表示刀的长度,单位:厘米
knife_length =10
#首先检查是否有车票,如果有,才允许进行 安检
if has_ticket == True:
print("有门票,可以进入安检")
else:
#安检时,需要检查刀的长度,判断是否超过 20 厘米
#如果超过 20 厘米,提示刀的长度,不允许上车
if knife_length > 20:
print("刀超过20厘米,不允许上车")
#如果不超过 20 厘米,安检通过
else:
print("安检通过")
#如果没有车票,不允许进门
else:
print("没有门票,不允许进门")
案例2:综合应用 ----- 剪刀石头布
#从控制台输入要出的拳 —— 石头(1)/剪刀(2)/布(3)
#电脑随机出拳
import random
user = int(input("输入您要出的拳头"))
computer = random.randint(1,3) # 1<= n <= 3
if (user == 1 and computer == 2) or (user ==2 and computer == 3) or (user==3 and computer == 1):
print("电脑输了")
elif user == computer:
print("此局为平局")
else:
print("玩家输了")
五、while循环的基本使用
循环的作用就是让 指定的代码 重复的执行,while 循环最常用的应用场景就是让执行的代码按照指定的次数重复执行
while的基本语法:
初始条件设置 -- 通常是重复执行的计数器
while 条件(判断 计数器 是否达到 目标次数):
条件满足时,做的事情1
条件满足时,做的事情2
条件满足时,做的事情3
.......
处理条件(计数器+1)
案例1:
# 1.设置计数器
i = 0
while i<3:
# 打印helloworld
print("helloworld")
# 计数器+1
i = i+1
print("i的值是=%d" % i)
六、赋值运算符
注意:赋值运算符中间不能使用空格
运算符 – 描述 | 实例 |
---|---|
+= 加法赋值运算符 | c+=a 等效于 c= c+a |
+= 加法赋值运算符 | c-=a 等效于 c= c-a |
+= 加法赋值运算符 | c=a 等效于 c= ca |
+= 加法赋值运算符 | c/=a 等效于 c= c/a |
+= 加法赋值运算符 | c%=a 等效于 c= c%a |
+= 加法赋值运算符 | c**=a 等效于 c= c**a |
七、循环运算
案例1:
计算1-100之间所有数字的和:
# 计算0-100之间所有数字的累加求和结果
result = 0
# 1.定义一个整数的变量记录循环的次数
i = 0
# 2.开始循环
while i <= 100:
print('i', i)
result += i
i += 1
print("0-100之间的结果求和%d" %result)
案例2:
使用一行代码实现1+...+100
sum1 = sum([i for i in range(1, 101, 1)])
print(sum1)
八、break和continue
break和continue是专门在循环中是的关键字,只针对当前所在循环有效
- break:某一条件满足时,退出循环,不再执行后续重复代码,如下i==3的时候退出循环
i = 0
while i < 10:
if i == 3:
break
print(i)
i += 1
print("over")
- continue:某一条件满足时,退出这一次循环,不执行后续重复的代码,如下例子:i==3的时候退出这次循环,也就是不打印i=3
i = 0
while i <= 10:
# continue某一条件满足时,不执行后续重复的代码
# 语句中断循环中的迭代,如果出现了指定的条件,然后继续循环中的下一个迭代。
if i == 3:
# 注意在循环中,如果使用continue这个关键字
# 在使用关键字之前,需要确认循环的计数是否修改
# 否则可能会导致死循环
i += 1
continue
print(i)
i += 1
print("over")
九、print打印的扩展知识
- 在默认的情况下,print函数输出内容之后
print("1")
print("2")
- 如果不希望末尾增加换行,可以在print函数内容的后面增加 ,end="",其中 ,end="" 表示控制台输出内容结束之后,不会换行
print("1", end="")
print("2", end="")
输出结果:
- 其中""中间可以指定print函数输出内容之后继续希望显示的内容
print("A", end="B")
十、字符串的转义字符
- \t在控制台输出一个制表符,协助在输出文本时垂直方向保持对齐
- \n在控制台输出一个换行符
制表符的功能是在不使用表格的情况下在垂直方向按列对齐文本
转义字符 | 描述 |
---|---|
\ | 反斜杠符号 |
’ | 单引号 |
" | 双引号 |
\n | 换行 |
\t | 横向制表符 |
\r | 回车 |
十、循环嵌套
while的嵌套就是: while里面还有while:
while 条件1:
条件满足时,做的事情1
条件满足时,做的事情1
.......
while 条件2:
条件满足时,做的事情1
条件满足时,做的事情1
......
处理条件1
案例:
# 实现九九乘法表
row = 1
while row <= 9:
col = 1
while col <= row:
# print("*", end="")
print("%d*%d=%d" % (col, row, (col * row)), end="\t")
col += 1
print("")
row += 1
四、函数
1.函数的作用:在开发程序时,使用函数可以提高编写的效率以及代码的重用
2.函数的定义:
# 函数名称的命名应该符合标识符的命名规则
# 函数的命名应该符合标识符的命名规则:
# 可以由字母、下划线和数字组成
# 不能以数字开头
# 不能与关键字重名
def 函数名():
函数封装的代码
......
3.函数的演练
# 注意:定义好的函数之后,只表示这个函数封装了一段代码而已,如果不主动调用函数,函数是不会主动执行的
def say_helloworld():
print("helloworld")
say_helloworld()
4.函数的文档注释
- 在开发中,如果希望给函数添加注释,应该在函数的下方,使用连续的三队引号
- 在连续的三队引号之间编写对函数的说明文字
- 在函数调用的位置,使用快捷键ctrl+j可以查看函数的说明信息
注意:因为函数相对比较独立,函数定义的上方,应该和其他的代码(包括注释)保留两行空行
5.形参与实参
-
形参:定义函数时,小括号中的参数,是用来接收参数用的,在函数内部作为变量使用
-
实参:调用函数时,小括号中的参数,是用来把数据传递到函数内部用的
6.函数的返回值 -
在程序开发中,有时候希望一个函数执行结束后,告诉调用者一个结果,以便调用者针对具体的结果做后续的处理
-
返回值 是函数完成工作后,最后 给调用者的一个结果
-
在函数中使用 return 关键字可以返回结果
-
调用函数一方,可以 使用变量来接收 函数的返回结果
-
注意: return 表示返回,后续的代码都不会被执行
五、列表、元组、字典、字符串
一、列表
1.List(列表)用[]定义,列表的索引是从0~n-1,索引就是列表中的位置编号
2.列表的方法:
3.列表的循环遍历
name_list = ["张三", "李四", "王五", "王五", "张三"]
"""
顺序的从列表中依次获取数据,每一次循环过程中,数据都会保存在my_name这个变量中,
在循环体内部可以访问到当前这一次获取到的数据
for my_name in 列表变量:
print("我的名字叫做%s" % name_list)
"""
for my_name in name_list:
print("我的名字叫做%s" % my_name)
二、元组
1.元组(Tuple)与列表相似,不同之处在于元组的元素不能修改 ,元组用()定义
三、字典
1.dictionary(字典)是除列表以外python之中最灵活的数据类型,字典用{}定义
2.字典与列表的区别
-
列表是有序的对象集合
-
字典是无序的对象集合
3.字典使用 键值对存储数据,键值对之间使用 , 分割 -
键key是索引
-
值value是数据
-
键和值之间使用:来分割
-
在一个字典里面键必须是唯一的
-
值可以是任意数据类型,但是键只能使用 字符串、数字 或者 元组
4.字典的基本操作
xiaoming_dict = {"name": "小明"}
# 1.取值
print(xiaoming_dict["name"])
# 在取值的时候,如果指定的key不存在,程序会报错!
# print(xiaoming_dict["name123"])
# 2.增加/修改
# 如果key不存在,会增加键值对
xiaoming_dict["age"] = 18
# 如果key存在,会修改已存在的键值对
xiaoming_dict["name"] = "小小明"
# 3.删除
xiaoming_dict.pop("name")
# 在删除指定键值对的时候,如果指定的key不存在,程序会报错
# xiaoming_dict.pop("name123")
print(xiaoming_dict)
5.字典的其他操作
xiaoming_dict = {"name": "小明",
"age": 18}
# 1.统计键值对数量
print(len(xiaoming_dict))
# 2.合并字典
temp_dict = {"height": 1.75}
xiaoming_dict.update(temp_dict)
print(xiaoming_dict)
# 注意:如果被合并的字典中包含已经存在的键值对,会覆盖原有的键值对
# temp_dict = {"height": 1.75,"age":20}
# 3.清空字典
xiaoming_dict.clear()
print(xiaoming_dict)
6.字典的循环遍历
xiaoming_dict = {"name": "小明",
"qq": "185345",
"phone": "15954123"}
# 迭代遍历字典
# 变量k是每一次循环中,获取到的键值对的key
for k in xiaoming_dict:
print(k, xiaoming_dict[k])
打印结果:
phone 15954123
qq 185345
name 小明
7.应用场景
card_list = [
{"name": "张三",
"qq": "12345",
"phone": "110"},
{"name": "李四",
"qq": "54987",
"phone": "10086"}
]
# 列表是有序的集合,输出的时候是按顺序输出
for card_info in card_list:
print(card_info)
打印结果:
{'name': '张三', 'phone': '110', 'qq': '12345'}
{'name': '李四', 'phone': '10086', 'qq': '54987'}
8.字典的注意事项
d = {}
d["name"] = "xiaoming"
print(d)
d[1] = "整数"
print(d)
d[(1,)] = "元组"
print(d)
# 字典的key只能使用不可变类型的数据,可变类型数据包括列表字典
# 列表不能作为键值对的key
# d[[1,2,3,]] = "列表"
# 不能使用字典作为键值对的key
# d[{"n":"xxx"}] = "字典"
四、字符串
1.字符串是一串字符,是编程语言中,表示文本的数据类型
2.Python中可以使用一堆双引号"或者一对’定义一个字符串
如果字符串内部需要使用",可以使用’定义字符串
如果字符串内部需要使用’,可以使用"定义字符串
3.字符串切片
- 字符串[开始索引:结束索引:步长]
- 指定区间属于左闭右开,从起始位开始,到结束位的前一位结束(不包含结束位本身)
num_str = "0123456789"
# 1.截取从2-5位置的字符串
num1 = num_str[2:6]
print(num1)
# 2.截取从2-末尾的字符串
num2 = num_str[2:]
print(num2)
# 3.截取从开始到 -5位置的字符串
num3 = num_str[0:6]
print(num3)
# 4.截取完整的字符串
num4 = num_str[:]
print(num4)
# 5.从开始位置,每个一个字符截取字符串
num5 = num_str[::2]
print(num5)
# 6.从索引1开始,每隔一个取一个
num6 = num_str[1::2]
print(num6)
# 7.截取从2-末尾-1的字符串
num7 = num_str[2:-1]
print(num7)
# 8.截取字符串末尾两个字符
num8 = num_str[-2:]
print(num8)
# 9.字符串的逆序(面试题)
num9 = num_str[::-1]
# num9 = num_str[-1::-1]
print(num9)
六、变量的进阶
一、可变和不可变类型
不可变类型:内存中的数据不允许被修改,变量的值是可以被修改的,只是内存中的数据不能被修改
- 数字类型:int bool float complex long(2.x)
- 字符串:str
- 元组:tuple
a与b的内存是一样的,因为数据2在内存中是不可变得
a = 2
b = 2
print(id(a))
print(id(b))
打印结果:
1805512528
1805512528
可变类型:内存中的数据可以被修改,下面以列表为例子
- 列表:list
- 字典:dict
通过该例子,我们可以发现当我们通过列表进行修改得时候其内存地址并不会发生变化
当对列表再次赋值的时候,列表的内存地址发生了变化
list = [1,2,3]
print(id(list))
list.pop(2)
print(id(list))
list = [4,5,6]
print(id(list))
打印结果:
2437440290440
2437440290440
2437440290248
注意:
- 可变类型的数据变化,是通过方法来实现的
- 如果给一个可变类型的变量,赋值了一个新的数据,引用会被修改
变量不再对之前的数据引用
变量改为对新赋值的数据引用
- 字典的key只能使用不可变类型
二、局部变量和全局变量的理解
- 局部变量:是在函数内部定义的变量,只能在函数内部使用
- 全局变量:是在函数外部定义的变量(没有定义在某一函数内),所有的函数内部都可以使用这个变量
# 全局变量
num = 20
def demo1():
# 定义一个局部变量
# 出生:执行了下方的代码,才会被创建
# 死亡:函数执行完成之后
# 局部变量是在函数内部定义的变量,只能在函数内部使用
# 在函数内部定义的变量,不能再其他位置使用
num = 10
print("在demo1函数内部的变量是 %d " % num)
def demo2():
print("在demo2函数内部的变量是 %d " % num)
pass
demo1()
demo2()
2.注意:函数执行时,需要处理变量时会:
- 首先会查找函数内部是否存在指定名称的局部变量,如果有直接使用
- 如果没有,查找函数外部是否存在指定名称的全局变量,如果有直接使用
- 如果还没有,程序则报错
# 全局变量
num = 10
def demo1():
# 希望修改全局变量的值
# 在python中,不允许直接修改全局变量的值
# 如果使用赋值语句,会在函数内部,定义一个局部变量
num = 100
print("demo1 %d " % num)
def demo2():
print("demo2 %d " % num)
demo1()
demo2()
3.真正的修改全局变量的值,用global声明以下变量即可
# 全局变量
num = 10
def demo1():
# 希望修改全局变量的值 -- 使用global声明一下变量即可
# global关键字会告诉解释器后面的变量是一个全局变量
# 在使用赋值语句时,就不会创建局部变量
global num
num = 100
print("demo1 %d " % num)
def demo2():
print("demo2 %d " % num)
demo1()
demo2()
print(num)
4.全局变量命名的建议
为了全局变量和局部变量出现混淆,在定义全局变量的时候,我们可以在全局变量的名字加g_或者gl_的前缀
七、函数的返回值和参数的进阶
一、函数参数和函数返回值的作用
定义一个函数是否要返回值,以及是否要传参数,要根据自己的需求而定
函数根据没有参数以及没有返回值,相互结合之后又以下四种情况:
无参数 无返回值
无参数 有返回值
有参数 无返回值
有参数 有返回值
二、函数的返回值进阶 — 利用元组返回多个值
def measure():
"""测量温度和湿度"""
print("测量开始....")
temp = 39
weight = 50
print("测量结束")
# 元组可以包含多个数据,因此可以使用元组让函数一次返回多个值
# return (temp, weight) -- 如果函数返回的类型是元组,小括号可以省略
return temp, weight
# result保存的一个元组类型
result = measure()
print(result)
# 如果需要单独的处理温度或者湿度 -- 不方便
print(result[0])
print(result[1])
print('--')
# 如果函数返回的类型是元组,同时希望单独的处理元组中的元素
# 可以使用多个变量,一次接收函数的返回结果
# 注意:使用多个变量接收结果时,变量的个数应该和元组中元素的个数保持一致
gl_temp, gl_wetness = measure()
print(gl_temp)
print(gl_wetness)
三、延伸:交换两个变量的值,如:a=6,b=100交换其值
# 面试题题目要求:有两个整数a=6,b=100
# 不使用其他变量,交换两个变量
a = 6
b = 100
# 解法一:使用其他变量
c = a
a = b
b = c
print(a, b)
# 解法二:不使用临时变量
a = a + b
b = a - b
a = a - b
print(a, b)
# 解法三:python专有,利用元组
# a, b = (b, a)
# 等号右边是一个元组,只是把小括号省略了
a, b = b, a
print(a, b)
四、函数的参数 (可变和不可变参数)
1.函数内部赋值不会影响到外部的实参,通过方法修改其值会改变外部实参
def demo(num, num_list):
print("函数内部的代码")
# 在函数内部,针对参数使用赋值语句,不hi修改到外部的实参变量
num = 10
num_list = [1, 2, 3]
print("num %d" % num)
print("numlist %s" % num_list)
print("函数执行完成")
global_num = 100
global_list = [10, 20, 30]
demo(global_num, global_list)
print(global_num, global_list)
2.在函数内部使用方法修改可变参数会影响外部实参
def demo(num_list):
print("函数内部的代码")
# 使用方法修改列表的内容
num_list.append(9)
print(num_list)
print("函数执行完成")
global_list = [1, 2, 3]
demo(global_list)
print(global_list)
3.可变类型的+=,num_list += num_list本质上是调用列表的
def demo(num, num_list):
print("函数开始")
# num = num + num
num += num
# num_list = num_list + num_list
# 列表变量使用 + 不会做相加在赋值的操作
# 本质上是在调用列表的extend方法
# num_list.extend(num_list)
num_list += num_list
print(num)
print(num_list)
print("函数完成")
gl_num = 9
gl_list = [1, 2, 3]
demo(gl_num, gl_list)
print(gl_num)
4.列表的排序方法明确缺省参数的概念以及作用(提示:缺省参数也就是形参默认有值的)
如下:列表的升序与降序 ~ 传参
global_num_list = [6, 3, 4]
# 默认升序,因为升序的应用场景多
global_num_list.sort()
print(global_num_list)
# 只有当需要降序排序的时,才需要传递'reverse'参数
global_num_list.sort(reverse=True)
print(global_num_list)
5.缺省参数
指定参数为缺省参数,直接在参数名后面加上=值就好了
缺省参数的注意事项:
(1)缺省参数的定义位置:必须保证带有默认值的缺省参数在参数列表的末尾
(2)调用带有多个缺省参数的函数:在调用的时候如果有多个缺省参数,需要指定参数名,这样解释器才能够指定对应关系
def print_info(name, gender):
"""
:param name: 班上同学的姓名
:param gender:True男生 False女生
"""
gender_text = "男生"
if not gender:
gender_text = "女生"
print(" %s 是 %s " % (name, gender_text))
# 提示:在指定缺省参数的默认值时,应该使用最常见的值作为默认值!
# 如果一个参数的值不能确定,则不应该设置默认值,具体的数据在调用函数时,由外界传递
print_info("小明", gender=True)
# 打印结果: 小明是男生
6.多值参数
- 有时候可能需要一个函数能够处理的参数个数是不确定的,这个时候就可以使用多值参数
- Python中有两种多值参数:
参数名前增加一个 * 可以接收元组
参数名前增加两个 * 可以接收字典
一般在多值参数命名时,习惯使用下下面的两个名字
*args(arguments的缩写,有变量的含义),存放元组,参数前有一个*
**kwargs(kw是单词keywords的缩写),存放字典参数,前面有两个*
演练1:
def demo(num, *nums, **person):
print(num)
print(nums)
print(person)
demo(1)
demo(1, 2, 3, 4)
demo(1, 3, name="小明", age=18)
打印结果:
1
()
{}
1
(2, 3, 4)
{}
1
(3,)
{'name': '小明', 'age': 18}
演练2:
需求:定义一个函数sum_number,可以接收的任意多个整数
功能要求:将传递的所有数字累加并且返回累加的结果
def num_number(*args):
num = 0
print(args)
# 循环遍历
for n in args:
#num = num + n
num += n
return num
# 1.def num_number(args):
# 1.result = num_number((1, 2, 3, 4))
result = num_number(1, 2, 3, 4)
print(result)
7.元组和字典的拆包(拆包语法:简化了元组变量和字典变量的传递)
在调用带有多指参数的函数时,如果希望:
- 将一个元组变量,直接传递给args,在传值的实参前面加上一个*
- 将一个字典变量,直接传递给kwargs,在传值的实参前面加上两个*
def demo(*args, **kwargs):
print(args)
print(kwargs)
# 元组变量/字典变量
gl_num = (1, 2, 3)
gl_dict = {"name": "小明", "age": 18}
# 拆包语法
# 简化元组变量/字典变量的传递
demo(*gl_num, **gl_dict)
# 非拆包语法
demo(1, 2, 3, name="小明", age=18)
四、函数的递归(函数调用自身的编程技巧就叫做递归)
代码的特点:
(1)函数内部的代码是相同的,只是针对参数不同,处理的结果不同
(2)当参数满足一个条件时,函数不再执行(这个通常成为递归的出口,很重要,如果没有会出现死循环)
演练1:
def sum_number(num):
print(num)
if num == 1:
return
# 自己调用自己
sum_number(num - 1)
sum_number(3)
演练2:
定义一个函数sum_number
能够接收一个num的整数参数
计算1+2+…+num的结果
def sum_number(num):
# 1.出口
if num == 1:
return 1
# 1+2+..+(num-2)+(num-1)+(num)
# 2.数字的累加 num+(1..num-1)
# 数字的累加num + (1..num-1)
# 假设sum_numbers能够正确的处理1..num-1
temp = sum_number(num - 1)
# 两个数字的相加
return num + temp
result = sum_number(3)
print(result)
递归求和的图示:
八、面向对象
一、面向对象概念基础以及类和对象
1.面向对象编程(Object Oriented Programming)简写:OOP
相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法
1.在完成某一个需求前,首先确定的职责 -- 要做的事情
2.根据职责确定不同的对象,在对象内部封装不同的方法(多个)
3.最后完成的代码,就是顺序的让不同的对象调用不同的方法
2.类和对象(类和对象是面向对象编程的 两个核心概念)
- 类:是一对具有相同特征或行为的事务的一个统称,是抽象的,不能直接使用
特征:被称为属性
行为:被称为方法 - 对象:是由类创建出来的一个具体的存在,可以直接使用,由哪个类创建出来,就拥有在哪一个类的定义,也就是拥有类的属性和方法
3.类和对象的关系 - 类是模板,对象是根据类这个模板创造出来的,应该先有类,再有模板
- 类只有一个,而对象可以由很多个,对象之间可以设置不同的属性
- 类中定义了什么属性和方法,对象中就有什么属性和方法,不可能多,也不可能少
4.类的设计:要满足三大要素(类名、属性、方法)
- 类名:这类事务的名字,要满足大驼峰命名法,每一个单词的首字母大写,单词与单词之间没有下划线
- 属性:这类事务具有什么特征
- 方法:这类事务具有什么样的行为
二、面向对象的基础语法
1.dir内置函数
提示:__方法名__格式的方法是Python提供的*内置方法/属性
__ new__ | 创建对象时,会被自动调用 |
---|---|
__ init__ | 对象初始化时,会被自动调用 |
__ del__ | 对象被从内存中销毁前,会被自动调用 |
__ str__ | 返回对象的描述信息,print函数输出使用 |
2.面向对象是更大的封装,在一个类中封装多个方法,这样通过这个类创建出来的对象,就可以直接调用这些方法了
3.定义只包含方法的类,格式如下:
# 类名要符合大驼峰命名法
class 类名:
def 方法1(self, 参数列表):
pass
def 方法2(self,参数列表):
pass
注意:类名的命名规则要符合大驼峰命名法
4.创建对象
当一个类定义完成之后,要是有这个类来创建对象,语法格式如下:
对象变量=类名()
5.写一个简单的面向对象的程序
class Baby:
"""这是一个孩子对象"""
def smile(self):
print("小孩(baby) 爱哭")
def play(self):
print("小孩(baby) 爱玩")
smallBaby = Baby()
smallBaby.play()
smallBaby.smile()
6.引用概念的强调
在计算机中,通常使用十六进制表示内存地址
十进制和十六进制 都是用来表达数字的,只是表示方式不一样
十进制和十六进制的数字之间可以来回转换
%d可以 以 10进制 输出数字
%x可以 以 16进制 输出数字
从图片中,可以看出smallBaby的对象的类是:Baby,object代表对象类型,输出的是十六进制地址。
提示:相同的类可以创建多个对象
7.方法中的self参数
由哪一个对象调用的方法,方法内的self就是哪一个对象的调用
在类封装的方法内部,self就表示当前调用方法的对象自己。调用方法时,程序员不需要传递self参数。
在方法内部
- 可以通过.self访问对象的属性
- 也可以通过self.调用其他的对象方法
8.初始化方法
8.1、当使用类名()创建对象时,会自动执行以下操作:
- 为对象在内存中 分配空间 – 创建对象
- 为对象的属性 设置初始值 – 初始化方法(init)
8.2、这个初始化方法就是__init__ 方法,__ init__ 是对象的内置方法
__init__方法是 专门 用来定义一个类 具有哪些属性的方法!在类中增加__init__方法,验证该方法在创建对象时会被自动调用
8.3、在初始化方法内部定义属性
- 在__init__ 方法内部使用self.属性名 = 属性的初始值就可以定义属性
- 定义属性之后,在使用Cat类创建的对象,都会拥有该属性
class Baby:
def __init__(self):
print("初始化方法")
self.name = 'jack'
def smile(self):
print("我的名字叫%s" % self.name)
smallBaby = Baby()
print("%s" % smallBaby.name)
打印结果:
初始化方法
jack
8.4、改造初始化方法——初始化的同时设置初始值
- 把希望设置的属性值,定义成__init__方法的参数
- 在方法内部使用self.属性 = 形参 接收外部传递的参数
- 在创建对象时,使用类名(属性1,属性2…)调用
class Baby:
def __init__(self,new_name):
print("初始化方法")
self.name = new_name
small_baby = Baby("jack")
print(small_baby.name)
9.内置方法和属性
_ _del _ _ | 对象被从内存中销毁前,会被自动调用 |
---|---|
_ _ str _ _ | 返回对象的描述信息,print函数输出使用 |
9.1 _ _del__方法
在Python中
- 当使用类名()创建对象时,为对象分配完空间后,自动调用__init__方法
- 当一个对象被从内存中销毁前,会自动调用__del__方法
应用场景
- __init __ 改变初始化方法,可以让创建对象更加灵活
- __ del __ 如果希望在对象被销毁前,在做一些事情,可以考虑一下__del__方法
生命周期
- 一个对象从调用类名()创建,生命周期开始
- 一个对象del方法一旦被调用,生命周期结束
- 在对象的生命周期内,可以访问对象属性,或者让对象调用方法
class Baby:
def __init__(self,new_name):
print("初始化方法")
def __del__(self):
print("对象销毁的方法")
smallBaby = Baby("Jack")
9.2 _ _str__方法
- 在Python中,使用print输出对象变量,默认情况下,会输出这个变量,默认情况下,会输出这个变量是由哪一个累创建的对象,以及在内存中的地址(十六进制表示)
- 如果在开发中,希望使用 print 输出 对象变量 时,能够打印 自定义的内容,就可以利用 str 这个内置方法了
注意:__ str__ 方法必须返回一个字符串
三、私有属性和私有方法
3.1、定义方式
在定义属性或方法时,在属性名或者方法名前增加两个下划线,定义的就是私有属性或方法,self.__age = 18就是私有属性,而self.age=18就不是私有属性,同样def __secreate(self)是私有方法,def secreate(self):不是私有方法
class Woman:
def __init__(self,name):
self.name = name
# 不要问女生的年龄
self.__age = 18
def __screate(self):
print("我的年龄是%d" % self.__age)
xiaofang = Woman("小芳")
# 私有属性,外部不能直接访问
# print(xiaofang.__age)
# 私有方法,外部不能直接调用
# xiaofang.__secret()
3.2、伪私有属性和私有方法
在日常开发中,不要使用这种方式,访问对象的私有属性或私有方法
在Python中,并没有真正意义的私有:
- 在给属性、方法命名时,实际是对名称做了一些特殊处理,使得外界无法访问到
- 处理方式:在调用的属性名或者方法名称前面加上__类名 => _ 类名__ _ 名称
class Women:
def __init__(self, name):
self.name = name
# 不要问女生的年龄
self.__age = 18
def __secret(self):
print("我的年龄是 %d" % self.__age)
xiaofang = Women("小芳")
# 私有属性,外部不能直接访问(加上`_Women`就可以了)
# print(xiaofang._ Women__age)
# 私有方法,外部不能直接调用(加上`_Women`就可以了)
# xiaofang._Women__secret()
四、单继承和多继承
4.1面向对象三大特性:
封装:根据指责将属性和方法封装到一个抽象的类中
继承:实现代码的重用,相同的代码不需要重复的编写
多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
4.2单继承
4.2.1继承的概念语法和特点:
(1)继承的概念:子类拥有父类的所有方法和属性
(2)继承的语法如下:
- 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
- 子类中应该根据职责,封装子类特有的属性和方法
class 类名(父类名):
pass
(3)继承的传递性(子类拥有父类 以及 父类中封装的所有属性和方法)
C类从B类继承,B类又从A类继承,那么C类就具有B类和A类所有属性和方法
4.2.2方法的重写(1.覆盖父类的方法 2.对父类方法进行扩展)
- 子类拥有父类的所有方法和属性
- 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
应用场景(当父类的方法实现不能满足子类需求时,可以对方法进行重写(override))
覆盖父类的方法:
具体实现方式,就相当于在子类中定义了一个和父类同名的方法并且实现
class Animal():
def sleep(self):
print("睡觉")
def brank(self):
print("叫")
class Dog(Animal):
def brank(self):
print("狗叫")
dog = Dog()
dog.brank()
打印结果:
狗叫
4.3对父类方法进行 扩展
如果想在重写了父类的方法之后还想调用父类的方法,那么我们就可以使用 **super().方法名()**来在重写父类方法的基础上来增加自己的代码
扩展:在Python 2.x 时,如果需要调用父类的方法,还可以使用 父类名.方法(self),目前在 Python 3.x 还支持这种方式( 不推荐使用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改)
4.4父类的 私有属性 和 私有方法
子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
私有属性、方法通常用于做一些内部的事情
class Animal():
def __init__(self):
self.name = "小黄"
self.__age = 10
def sleep(self):
print("睡觉")
def __brak(self):
print("动物叫")
class Dog(Animal):
def test(self):
# 可以访问共有的属性
print(self.name)
# 不可以访问私有的属性
print(self.__age)
# 可以调用共有的方法
self.sleep()
# 不可以调用私有的方法
self.__brak()
dog = Dog()
dog.test()
提示:在每一个类的方法里面可以访问自己的私有属性和私有方法,如下:
class Animal():
def __init__(self):
self.name = "小黄"
self.__age = 10
def sleep(self):
print("睡觉")
def __brank(self):
print("动物叫")
4.5、多继承
4.5.1概念
子类可以拥有多个父类,并且具有所有父类的属性和方法
class 子类名(父类名1,父类名2...)
pass
如下的例子(对象c既可以调用test1,也可以调用test2)
class A:
def test1(self):
print("打印test1")
class B:
def test2(self):
print("打印test2")
class C(A, B):
pass
c = C()
c.test1()
c.test2()
打印结果:
打印test1
打印test2
当 class C(A,B): 改为class C(B,A):打印结果又会不同,具体的选择打印哪一个是根据 mro 可以查看 方法 搜索顺序,看后面的解释
提示:开发时,应该尽量避免这种容易产生混淆的情况! —— 如果 父类之间 存在 同名的属性或者方法,应该 尽量避免 使用多继承
4.5.2Python中的MRO — 方法搜索顺序(知道)
当在c调用 test() 方法的时候,会按照上面的打印顺序来查找test() 方法,如果找到最后一个类,还没有找到方法,程序报错
MRO 是 method resolution order,主要用于 在多继承时判断 方法、属性 的调用 路径
4.5.3拓展:新式类与旧式(经典)类
object 是 Python 为所有对象提供的 基类,提供有一些内置的属性和方法,可以使用 dir 函数查看,也就是把类的对象放到 dir里面,如 dir(对象)
新式类:以object为基类的类,推荐使用
经典类:不以object为基类的类,不推荐使用
在Python3.x中定义类时,如果没有指定父类,会默认使用object作为该类的基类 — Python3.x中定义的类都是新式类
在Python2.x中定义类时,如果没有指定父类,则不会以object基类
为保证编写的代码能够同时在Python2.x和Python3.x运行
今后在定义类时,如果没有父类,建议统一继承自object
class 类名(object):
pass
五、多态
多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
- 多态可以增加代码的灵活度
- 以继承和重写父类方法为前提
- 是调用方法的技巧,不会影响到类的内部设计
class Car(object):
def __init__(self, name):
self.name = name
def run(self):
print("%s 简单的在路上跑" % self.name)
class Pickup(Car):
def run(self):
print("%s 在跑的时候可以进行拉货" % self.name)
class Person(object):
def __init__(self, name):
self.name = name
def drive(self, car):
print("%s 开着 %s 去拉货" % (self.name, car.name))
# 让狗玩耍
car.run()
# 1. 创建一个汽车对象
# small_car = Car("小汽车")
pickup = Pickup("皮卡")
# 2. 创建一个Jack对象
Jack = Person("Jack")
# 3. 让Jack调用drive的方法
Jack.drive(pickup)
六、类属性、类方法、静态方法
6.1.类属性就是给类对象中定义的属性
6.2.类属性不会用于记录具体对象的特征
类属性的创建:在类的下面使用赋值语句,等号左边是类属性的名字,右边是类属性的初始值;使用的是类名.属性名
class Tool(object):
# 使用赋值语句,定义类属性,记录创建工具对象的总数
count = 0
def __init__(self,name):
# 针对类熟悉做一个计数+1
Tool.count += 1
self.name = name
tool = Tool("斧头")
too2 = Tool("镰刀")
print("工具的数量是%d" % Tool.count)
输出结果如下:
工具的数量是2
6.3.类方法
类属性就是针对类对象定义的属性:
- 使用赋值语句在class关键字下方可以定义类属性
- 类属性用于记录与这个类相关的特征
类方法就是针对类对象定义的方法
- 在类方法内部可以直接访问类属性或者调用其他的类方法
类方法需要用修饰器@classmethod来标识,告诉解释器这是一个类方法
类方法的第一个参数应该是cls
由哪一个类调用的方法,方法内的cls就是哪一个类的饮用
这个参数和实例方法的第一个参数是self类似
提示:使用其他名称也可以,习惯使用cls
通过类名.调用类方法,调用方法时,不需要传递cls参数
在方法内部
可以通过cls.访问类的属性
也可以通过cls.调用其他的类方法
在类方法内部,可以直接使用cls访问类属性或者调用类方法
类方法语法如下:
@classmethod
def 类方法名(cls):
pass
类方法的使用案例
class Person(object):
name = ""
@classmethod
def run(cls):
print("%s 会跑" % cls.name)
Person.name = "小米"
Person.run()
打印结果:
小米 会跑
6.4.静态方法
在开发时,如果需要在类中封装一个方法,这个方法:
既不需要访问实例属性或者调用实例方法
也不需要访问类属性或者调用类方法
语法如下:
@staticmethod
def 静态方法名():
pass
静态方法需要用修饰器@staticmethod来标识,告诉解释器这是一个静态方法
通过类名.调用静态方法
class Baby(object):
@staticmethod
def cry():
# 不需要访问实例属性也不需要访问类属性的方法
print("小孩在哭...")
Baby.cry()
综合案例:
需求:(1)设计一个Game类
(2)属性:
定义一个 类属性 top_score 记录游戏的 历史最高分
定义一个 实例属性 player_name 记录 当前游戏的玩家姓名
(3)方法:
静态方法 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("现实历史最高分")
# 实例方法
def start_game(self):
print("开始游戏")
# 实例属性
def __init__(self, play_name):
self.play_name = play_name
# 使用类名.修改历史最高分
Game.top_score = 10000
# 1. 查看游戏帮助
Game.show_help()
# 2. 查看游戏最高分
Game.show_top_score()
# 3. 创建游戏对象,开始游戏
game = Game("二郎神")
game.start_game()
# 4. 游戏结束,查看游戏最高分
Game.show_top_score()
打印结果:
游戏帮助
现实历史最高分
开始游戏
现实历史最高分
6.4.总结
- 实例方法 —— 方法内部需要访问 实例属性
实例方法 内部可以使用 类名. 访问类属性 - 类方法 —— 方法内部 只 需要访问 类属性
- 静态方法 —— 方法内部,不需要访问 实例属性 和 类属性
七、单例模式
7.1使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性
7.2单例设计模式:
目的 — 让类创建的对象,在系统中只有唯一的一个实例
每一次执行
八、异常
8.1异常的概念
8.1.1程序在运行时,如果Python解释器遇到一个错误,会停止程序的执行,并且提示一些错误,这就是异常
8.1.2程序停止执行并且提示报错信息这个动作,我们通常称之为:抛出(raise)异常
程序开发时,很难将 所有的特殊情况 都处理的面面俱到,通过 异常捕获 可以针对突发事件做集中的处理,从而保证程序的 稳定性和健壮性
8.2捕获异常
8.2.1简单的捕获异常语法
- 在程序开发中,如果对某些代码的执行不能确定是否正确,可以增加try(尝试)来捕获异常
except:如果try里面的代码出现错误,就会走except下面的代码,并且整个程序正常执行
捕获异常最简单的语法格式:
try:
尝试执行的代码
except:
出现错误的处理
8.2.2错误类型捕获
在程序执行时,可能会遇到不同类型的异常,并且需要针对不同类型的异常,做出不同的响应,这个时候,就需要捕获错误类型了
try:
# 尝试执行的代码
pass
except 错误类型1:
# 针对错误类型1,对应的代码处理
pass
except (错误类型2, 错误类型3):
# 针对错误类型2 和 3,对应的代码处理
pass
except Exception as result:
print("未知错误 %s" % result)
当Python解释器抛出异常时,最后一行错误信息的第一个单词就是错误类型
8.3异常类型捕获演练 — 要求用户输入整数
需求:提示用户输入一个整数
使用8除以用户输入的整数并且输出
try:
num = int(input("请输入整数:"))
result = 8/num
print(result)
except ValueError:
print("请输出正确的整数")
except Exception as result:
print("错误信息是%s" % result)
print("#" * 50)
8.4捕获未知错误
- 在开发时,要预判到所有可能出现的错误,还是有一定的难度的,如果希望程序无论出现任何错误,都不会因为Python解释器抛出异常而被终止,可以增加一个except,语法如下:result是错误信息
except Exception as result:
print("未知错误%s" % result)
8.5异常捕获完整语法
在实际开发中,为了能够处理复杂的异常情况,完整的异常语法如下:
else只有在没有异常时才会执行的代码
finally无论是否有异常,都会执行的代码
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("无论是否有异常,都会执行的代码")
8.6异常的传递
异常的传递 — 当函数/方法执行出现异常,会将异常传递给函数/方法的调用一方
如果传递到主程序,仍然没有一场处理,程序才会终止
提示:
在开发中,可以在主函数中增加异常捕获
而在主函数中调用的其他函数,只要出现异常,都会传递到主函数的异常捕获中
这样就不需要在代码中,增加大量的异常捕获,能够保证代码的整洁
示例
def demo1():
return int(input("请输入一个整数:"))
def demo2():
return demo1()
try:
print(demo2())
except ValueError:
print("请输入正确的整数")
except Exception as result:
print("未知错误%s" % result)
8.7抛出raise异常
Python中提供了一个Exception异常类
在开发时,如果满足特定业务需求时,需要抛出异常可以:
创建一个Exception的对象
使用raise关键字抛出异常对象
#创建异常对象
ex = Exception("异常提示信息")
raise ex
需求:
定义 input_password 函数,提示用户输入密码
如果用户输入长度 < 8,抛出异常
如果用户输入长度 >=8,返回输入的密码
def input_password():
# 1.提示用户输入密码
password = input("请输入密码")
# 2.密码大于8返回密码
if len(password) > 8:
return password
# 3.密码长度不够,需要抛出异常
# 1>创建异常对象 - 使用异常的错误信息字符串作为参数
ex = Exception("密码长度不够")
raise ex
try:
print(input_password())
except Exception as result:
print("错误信息是:%s" % result)
9.模块和包
9.1模块的概念:模块是Python程序架构的一个核心概念
- 每一个扩展名以py结尾的Python源代码文件都是一个模块
- 模块名同样也是一个标识符,需要符合标识符的命名规则
- 在模块中定义的全局变量函数、函数、类都是提供给外界直接使用的工具
- 模块就好比是工具包,要想使用这个工具包中的工具,就先导入这个模块
9.2模块的两种导入方式
(1)import导入(不推荐使用)
import 模块名1,模块名2
提示:在导入模块时,每个导入应该独占一行
import 模块名1
import 模块名2
使用as制定模块的别名(如果模块的名字太长,可以使用as制定模块的名称,以方便在代码中使用),模块名要符合大驼峰命名法
import 模块名1 as 模块别名
(2)from…import导入
如果希望从某一个模块中,导入部分工具,就可以使用from…import方式
# 从 模块 导入 某一个工具
from 模块名1 import 工具名
提示:如果两个模块,存在同名的函数,那么后导入模块的函数,会覆盖掉导入的函数
开发时import代码应该统一写在代码的顶部,更容易及时发现冲突
一旦发现冲突,可以使用as关键字给其中一个工具起一个别名
(3)from…import*
提示:这种方式不推荐使用,因为函数重名并没有任何的提示,出现问题不好排查
# 从 模块 导入 所有工具
from 模块名1 import *
9.3模块的搜索顺序
开发时,给文件起名,不要和系统的模块文件重名
Python中每一个模块都有一个内置属性__file__可以查看模块的完整路径
Python的解释器在导入模块时,会:
搜索当前目录指定模块名的文件,如果有就直接导入
如果没有,在搜索系统目录
9.4__name__
我们在开发一个模块的时候,可能在模块最下面会写一些测试代码,在其他模块里面测试自己开发模块的时候,测试的代码也会被执行,如果去避免测试的代码执行呢?
__name__属性可以做到,测试模块的代码只在测试情况下被运行,而在被导入时不会被执行
- __name __ 是Python的一个内置属性,记录着一个字符串
- 如果是被其他文件导入的,__name__就是模块名
- 如果是当前执行的程序__name__ 是__main__
def test():
print("我是来测试的")
if __name__ == '__main__':
test()
9.4包
包的概念:
包是一个包含多个模块的特殊目录
目录下有一个特殊的文件__init__.py
十、文件操作
10.1文件的概念和作用
计算机的文件,就是存储在某种长期存储设备上的一段数据
长期存储设备包括:硬盘、U盘、移动硬盘、光盘…
文件的作用:将数据长期保存下来,在需要的时候使用
10.2文件的存储方式
在计算机中,文件是以二进制的方式保存在磁盘上的
文件分为:文本文件和二进制文件
- 文本文件
可以使用 文本编辑软件 查看
本质上还是二进制文件
例如:python 的源程序
- 二进制文件
保存的内容 不是给人直接阅读的,而是 提供给其他软件使用的
例如:图片文件、音频文件、视频文件等等
二进制文件不能使用 文本编辑软件 查看
10.3文件的基本操作
操作文件的流程
打开文件
读写文件
读:将文件内容读入内存
写:将内存内容写入文件
关闭文件
10.4操作文件的函数/方法
open | 打开文件,并且返回文件操作对象 |
---|---|
read | 将文件内容读取到内存 |
write | 将指定内容写到文件 |
close | 关闭文件 |
open函数负责打开文件,并且返回文件对象
read/write/close三个方法都需要通过文件对象来调用
10.5read文件 — 读取文件
- open函数的第一个参数是要打开的文件名(文件名区分大小写)
- read方法可以一次性读入并返回文件的所有内容
- close方法负责关闭文件(如果忘记关闭文件,会造成系统资源消耗,而且会影响到后续对文件的访问)
注意:read方法执行后,会把文件指针移动到文件的末尾
# 提示:在开发中,通常会先编写打开和关闭的代码,再编写中间针对文件的读/写的操作
# 1.打开 -文件名需要注意大小写
file = open("TestText")
# 2.读取文件内容
text = file.read()
print(text)
# 3.关闭文件
file.close()
10.6文件指针
文件指针标记从哪个位置开始读取数据
第一次打开文件时候,通常文件指针会指向文件的开始位置
当执行了read方法后,文件指针会移动到读取文件的末尾,比如:如果执行了一次 read 方法,读取了所有内容,那么再次调用 read 方法,文件指针已经在文件的末尾了,再读取的内容是空的。
10.7打开文件的方式
open函数默认以只读方式®打开文件,并且返回文件对象
语法如下:
file = open("文件名","访问方式") # 文件名需要注意大小写
提示:频繁的移动文件指针,会影响文件的读写效率,开发中更多的时候会以只读、只写的方式来操作文件
访问方式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头,这是默认模式。如果文件不存在,抛出异常 |
w | 以只写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a | 以追加方式打开文件。如果文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
r+ | 以读写方式打开文件。文件的指针将会放在文件的开头。如果文件不存在,抛出异常 |
w+ | 以读写方式打开文件。如果文件存在会被覆盖。如果文件不存在,创建新文件 |
a+ | 以读写方式打开文件,如果该文件已存在,文件指针将会放在文件的结尾。如果文件不存在,创建新文件进行写入 |
写入文件示例
# 打开文件
file = open("TestText", "w")
file.write("hello python !")
# 关闭文件
file.close()
10.7按行读取文件内容
read方法默认会把文件的所有内容一次性读取到内存,如果文件太大,对内存的占用会非常严重
readline方法(读取文件的一行数据),在读取大文件的时候很方便,逐行读取
- readline方法可以一次读取一行内容
- 方法执行后,会把文件指针移动到下一行,准备再次读取
# 打开文件
file = open("TestText")
while True:
# 读取一行内容
text = file.readline()
# 判断是否读到内容
if not text:
break
# 每读取一行的末尾已经有了一个'\n'
print(text,end="")
file.close()
案例1:小文件复制
# 1、打开文件
file_read = open("TestText","r")
file_write = open("TestTextWrite","w")
# 2.读取文件内容
text = file_read.read()
file_write.write(text)
# 3.关闭文件
file_read.close()
file_write.close()
案例2:大文件复制
# 1、打开文件
file_read = open("TestText","r")
file_write = open("TestTextWrite","w")
while True:
# 2.读取文件内容
text = file_read.read()
# 没有内容就跳出循环
if not text:
break
file_write.write(text)
# 3.关闭文件
file_read.close()
file_write.close()
10.8文件/目录的常用管理操作
在终端/文件浏览器中可以执行常规的文件/目录管理操作,例如:
创建、重命名、删除、改变路径、查看目录内容…
在Python中,如果希望通过程序实现上述功能,需要导入os模块
方法名 | 说明 示例 |
---|---|
rename | 重命名文件 os.rename(源文件名,目标文件名) |
remove | 删除文件 os.remove(文件名) |
11.内建函数eval
11.1eval概念
注意:在开发时千万不要使用eval直接转换input的结果