​python基础语法学习实践

 一、序言

学习python常用基础语法知识,通过实践+记录笔记加深理解。

二、python基础

2.1变量名 命名规范

变量名 :

(1)要遵循标识符的规则

(2)见名知意

(3)命名习惯

        驼峰命名法:

                -大驼峰,每一个单词的首字母都大写MyName

                -小驼峰,第一个单词的首字母小写,其余单词首字母大写 myName

        下划线连接

                单词与单词之间使用下划线连接,python主要使用这一种

2.1.1标识符:

用户编程时使用的名字,用于给变量、函数、类等命名。

2.1.2标识符规则

(1)由数字,字母,下划线组成

(2)不能使用数字开头

(3)不能使用python内置关键字

(4)严格区分大小写

(5)不建议使用中文

2.2数据类型

2.2.1查看变量数据类型

(1)使用type(变量)函数

(2)使用print()来打印输出到控制台查看

2.3数据类型转换

(1)将一种数据类型转换为另一种数据类型

        原数据是什么类型,要转换成什么类型

语法格式:

变量 = 要转换为的类型(原数据)

说明:数据类型转换,不会改变原数据的类型,是生成一个新数据

数据类型转换
函数 说明注意
int(x)将x转换为一个整数x是字符串时必须是整数类型字符串
float(x)将x转换成一个浮点数(小数)x是字符串时,只要是数字类型字符串即可
str(x)将x转换为字符串对任意类型x都可以转换字符串类型
tuple(s)将序列s转换为一个元组
list(s)将序列s转换为一个列表

2.4交互运行python代码

进行小的代码验证,每行代码都会有一个执行结果

2.5格式化输出

2.6转义字符

将两个字符进行转义,表示一个特殊的字符

(1)\n 表示换行

(2)\t表示制表符(Tab键)

三、逻辑控制语句

3.1if语句的基本结构

(1)单独的if语句,就是 如果条件成立,做什么事

语法格式:

if 判断条件:
    判断条件成立,执行的代码

3.2if else结构

语法格式:

# if else 如果... 否则 ...
if 判断条件:
    判断条件成立,执行代码
else:
    判断条件不成立,执行的代码

3.3if elif else结构

语法格式:

# if elif else 如果 ... 如果 ... 否则 ...
if 判断条件1:
    判断条件1成立,执行的代码
elif 判断条件2: # 判断条件1不成立才会执行判断条件2
    判断条件2成立,执行的代码
elif ...:
    pass
else:
    以上判断条件都不成立,才会执行的代码

3.4debug打断点

选中需要调试的代码执行debug,然后按F8

3.5if嵌套

在一个if(elif else)语句中嵌套另一个if(elif else)

判断条件存在递进关系才会使用,只有第一个条件成立,才会判断第二个条件

语法格式:

if 判断条件1:
    判断条件1成立,执行的代码
    if 判断条件2:
        判断条件2成立,执行的代码
    else:
        判断条件2不成立,执行的代码
else:
    判断条件1不成立,执行的代码

3.6while & for循环

3.6.1while语句基本语法

应用场景:让执行的代码按照指定的次数重复执行

初始条件设置 # 通常是重复执行的计数器

while 条件:# 判断计数器是否达到目标次数
    条件满足时,做事情1
    条件满足时,做事情2
    条件满足时,做事情N
    
    处理条件(计数器+1)

3.6.2死循环 & 无限循环

(1)死循环和无限循环 在程序执行上面看起来一样,都是代码一直执行不能停止

(2)死循环:是由于写代码 出现的bug

(3)无限循环:是代码需求编码

(4)无限循环中,一般会存在一个if判断语句 ,当这个判断语句的条件成立,执行break语句来终止循环

(5)关键字 break:当程序代码执行遇到break,break所在的循环就会被终止执行

(6)关键字continue:当程序代码执行遇到continue,continue后续的代码不执行,但是会继续下一次循环

while True:
    xxxx
    xxxx
    ....
    xxxx
    if xxxx:
        break
    xxxx

3.6.3for循环

for 循环也称为是for遍历,也可以指定次数的循环

遍历:是从容器中将数据逐个取出的过程

容器:字符串、列表、元组、字典

# for循环遍历字符串

for 变量 in 字符串:
    重复执行代码

# 字符串中存在多少个字符,代码就执行多少次
# 每次循环会从字符串中取出一个字符保存到前边的变量中
# for和in都是关键字

3.6.4for指定次数的循环 

for 变量 in range(n): # n就是要循环的次数
    重复执行的代码

# range(n) 可以生成[0,n)的整数的序列,不包含n

四、容器(数据序列)

容器:字符串str,列表list,元组tuple,字典dict,集合set

4.1字符串

使用引号(单引号、双引号、三引号)引起来的内容就是字符串

str1 = 'hello world'
str2 = "hello world"
str3 = """hello world"""
str4 = '''hello world'''
print(type(str1),type(str2),type(str3),type(str4))
# 字符串含有单引号就用双引号定义反之亦然
str5="i'm 小明"
print(f"str5={str5}")
# 转义字符处理
str6 = 'i\'m 小明'
print(f"str6={str6}")

4.1.1下标(索引)

(1)下标(索引),是数据在容器(字符串、列表、元组)中的位置,编号

(2)一般来说,使用的是正数下标从0开始

(3)作用:可以通过下标获取具体位置的数据:容器[下标]

python支持负数下标
0123456正数下标
abcdefg字符串
-7-6-5-4-3-2-1负数下标

4.1.2切片

切片可以一次性获取容器中多个数据,多个数据之间存在一定的规律,数据的下标是等差数列

语法:容器[start:end:step]

(1)start 表示开始位置的下标

(2)end表示结束位置的下标,但是end所对应的下标位置的数据是不能取到的

(3)step步长,表示相邻两个坐标之间的差值

4.1.3字符串的查找find()

语法:字符串.find(sub_str) #在字符串中查找是否存在sub_dtr这样的字符串

4.1.4字符串的替换replace()

语法:字符串.replace(old,new,count) # 将字符串中的old字符串替换为new字符串

-count一般不写,表示全部替换,可以指定替换的次数

4.1.5字符串的拆分split()

字符串.split(sep) #将字符串按照指定的字符串sep进行分隔
data = 'hello python and itcast and itheima'
list=data.split()
print(f"按照空白字符分隔{list}")
data = 'hello python\tand itcast and\nitheima'
list=data.split('and')
print(f"按照and字符分隔{list}")

4.1.6字符串的连接join

字符串.join(容器) # 容器一般是列表,将字符串插入到列表相邻的两个数据之间,组成新字符串

list = ['hello', 'python', 'and', 'itcast', 'and', 'itheima']
str1=' '.join(list)
print(f"使用空格连接字符串{str1}")
str2=','.join(list)
print(f"使用,连接字符串{str2}")

4.2列表list

列表是python中使用最频繁的数据类型,在其他语言中叫数组,专门用来存储一组数据

(1)列表,list,使用[]

(2)列表可以存放任意多个数据

(3)列表中可以存放任意类型的数据

(4)列表中数据之间使用逗号隔开

# 方式1,使用类实列化方式定义列表
# 定义空列表 变量=list()
list1=list()
print(type(list1))
# 定义非空列表,也称为类型转换,list(可迭代类型),可迭代类型:能够使用for循环
# 将容器中的每一个数据都作为列表中一个数据进行保存
list2=list('abcd')
print(list2)
# 方式2直接只用[]定义列表list
# 定义空列表
list3=[]
# 定义非空列表
list4=[1,3,18,'hello',False]
print(f"list4={list4}")

注:列表是容器所以也支持下标和切片

4.2.1列表查询方法index()

(1)index()这个方法的作用和字符串中的find()的作用一样

(2)列表中没有find()方法,但字符串中有find() & inde()

4.2.2列表查询方法count()

列表.count(数据) # 统计,指定数据在列表中出现的次数

4.2.3列表的增(添加数据)append()

列表.append(数据)  # 向列表的尾部添加数据

# 返回 none,所以不用 变量=列表.append()

# 直接在原列表添加数据,不会生成新的列表

4.2.4列表删除数据pop()

列表.pop(index) # 根据下标删除列表中的数据

-index不写,默认删除最后一个

-返回,删除的数据

4.2.5列表修改数据

想要修改列表中的数据,直接是所有下标即可

列表[下标]=新数据

4.2.6列表的反转reverse()

(1)字符串 反转 字符串[::-1]

(2)列表反转

        列表[::-1] #得到一个新的列表,原列表不会改动

        列表.reverse() 直接修改原列表的数据

4.2.7列表的排序

 (1)前提:列表中的数据要一样

列表.sort() # 升序,从小到大,直到在原列表中进行排序

列表.sort(reversed=True) # 降序,从大到小,直到在原列表中进行排序

4.2.8列表的嵌套

(1)列表的嵌套就是指列表中数据都是列表

4.3元组tuple()

(1)元组 tuple,使用()定义:tuple()

(2)元组和列表非常相似,都可以存储多个数据,都可以存储任意类型的数据

(3)区别就是,元组中的数据不能修改,列表中可以修改

(4)因为元组中数据不能修改,所以只能查询,如index、count。支持下标和切片

(5)元组,主要用于传参和返回值

说明:语法上支持类实例化方式定义空元组但不用,没有意义,空元组没有数据不支持修改。

通常直接使用小括号定义元组。

4.4字典dict

定义:

(1)字典 dict,使用{}表示

(2)字典是由键key值value对组成的,key:value

(3)一个键值对是一组数据,多个键值对之间使用逗号隔开

(4)在一个字典中主要使用字符串类型,可以是数字

(5)字典中没有下标

4.4.1字典的增加和修改

(1)字典['键'] =  值

# 键 存在,修改

# 键不存在,添加

4.4.2字典的删除方法

(1)字典.pop(键)

说明:在字典数据中根据给出的键删除对应的值

4.2.3字典的查询

(1)根据字典的键,获取对应的值

(2)方法一:

字典[键]  # 键 不存在,会报错

(3)方法二:

字典.get(键)  # 键不存在,返回None

4.2.4字典的遍历

(1)遍历字典的键

方式1:

for 变量 in 字典:

        print(变量)

方式2:

for 变量 in 字典.keys():  # 字典.keys() 可以获取字典所有的键

        print(变量)

(2)遍历字典的值

for 变量 字典.valus():  # 字典.valus() 可以获取字典中所有的值

        print(变量)

(3)遍历字典的键和值

for 变量1,变量2 in 字典.itmes():  #  字典.itmes() 获取都是字典的键值对

print(变量)

# 类实例化方式定义字典
dict1 = dict()
# 直接使用{}定义字典
dict2 = {}
# 使用{}定义非空字典
dict3 = {"name":"鲁班","age":18,"height":1.72,"isMen":True}
print(f"非空字典数据为dict3={dict3}")
#获取字典的键
for k in dict3:
    print(k)
print('-'*30)
for k in dict3.keys():
    print(k)
print('-'*30)
# 获取字典的值
for value in dict3.values():
    print(value)
print('-'*30)
# 获取字典的键值对
for k,v in dict3.items():
    print(f"获取字典键值对为{k}:{v}")

4.5集合set

(1)集合 set,{数据1,数据2,...,数据n}

(2)集合中数据是不能重复的,没有重复的数据

(3)应用:主要对列表进行去重操作

将列表转换为集合可以达到去重要求,再将集合转换为列表。

(4)可以使用2个容器。从A容器拿到数据看在不在B容器里,不在就放进去,达到去重

五、函数

定义:

(1)函数定义,就是给多行代码起名字的过程

(2)函数的定义需要使用关键字 def 

def 函数名():
    函数中的代码
# 处于def缩进中的代码均属于这个函数
# 函数名要满足标识符的规则
# 函数定义不会执行函数中的代码,想要执行需要调用函数

函数调用:

(1)函数调用,就是使用多行代码的过程

(2)语法:函数名()

5.1函数基础

5.1.1参数

参数:在函数定义的时候,在括号中写入变量,这个变量就称为是函数的参数,形式参数(形参)

在函数调用的时候,可以给定义时候的形参传递具体的数据值,供其使用。实际参数(实参)

即:在函数调用的时候,会将函数的实际值传递给形参

好处:可以让函数更加通用,函数中的数据值不是固定的,是调用的时候,实际传递的

5.1.2函数的嵌套使用

在一个函数中调用另一个函数。

(1)代码从上到下执行

(2)函数定义不会执行函数中的代码

(3)函数调用会进入函数中执行函数中的代码

(4)函数中的代码执行结束,会回到调用的地方继续向下执行

"""
定义名为test01的函数,打印当前函数的名称
定义名为test02的函数,打印当前函数的名称,并调用test01
在main代码中调用test02
"""
def test01():
    print(1)
    print("这是第一个函数")
    print('func01')

def test02():
    print(2)
    print("这是第二个函数")
    print('func02')
    test01()

print(5)
test02()
print(6)

# 5 2 1 6

5.1.3函数的返回值

返回值:函数执行的结果

(1)在一个函数中,想要返回一个数据(想要有返回值),需要使用return关键字

(2)为什么需要返回值?因为在函数中可能通过各种代码,得到的数据结果,想要在函数外部使用,就需要使用返回值

(3)如果函数有返回值,一般在调用的时候会使用变量来接收(保存)返回值,以便后续使用

(4)return关键字作用

        -将一个数据值返回到调用的地方

        -函数遇到return会结束函数的执行

(5)return关键字只能用在函数中

(6)如果一个函数没有写return,可以认为返回值是None

"""
需求:设计一个函数用于获取两个数中的较大数,数据来自于函数的参数。
实现思路分析
1、定义一个函数,例如get_max()
2、为函数定义两个参数,用于接收两个数字
3、使用判断语句分两种情况对两个数字的大小关系进行处理
4、准备测试数据,调用函数
"""
def get_max(a,b):
    if a > b:
        return a
    else:
        return b

# 调用函数get_max()
num = get_max(10,20)
print(f"较大的数是:{num}")

5.2模块和包

模块的概念:

1、在python中每一个以.py结尾的python代码文件都是一个模块

2、模块名同样也是一个 标识符 需要符合标识符的命名规则

3、在模块中定义的 全局变量 函数 类 都是提供给外界直接使用的 工具

4、模块就好比是工具包,要想使用这个工具包中的工具就需要先导入模块

模块的导入方式:

(1)import 模块名 # 模块名就是代码文件名,不要.py

# 使用模块中的功能

模块名.功能名 # 功能可以是变量、函数、类

多用于导入系统中的常用的模块和功能

(2)from 模块名 import 功能名 # 导入指定的功能

# 使用

功能名()

多用于导入自己书写的或者第三方的模块

快捷键:在要导入的功能名上使用快捷键 Alt Enter

5.2.1__name__变量

1.导入模块的时候,会执行模块中的代码

2.作用:如果在导入模块的时候,模块中的部分代码不想被执行,可以使用__name__来解决

3.__name__变量,是python解释器内置的变量(变量的值是自动维护的),每个代码文件中都有这个变量

3.1在模块中直接右键运行代码文件,__name__变量的值是 '__main__'

3.2如果是被导入运行代码文件__name__变量的值是模块名(文件名)

例如:

if __name__ == '__main__'

        # 在这个if的缩进中书写的代码,导入的时候不会被执行

5.2.2模块的导入顺序

(1)在导入模块的时候,会先从代码所在的目录进行导入

(2)如果没有找到,会去python系统的目录查找导入

(3)如果还没找到就报错

注:自定义的代码文件名不要和要导入的系统模块文件名一样

5.2.3包package

包:将多个模块放在一个目录中集中管理,并在这个目录中创建一个__init__.py文件(可以什么都不写),就是一个包

包的导入:

方式一

import 包名.模块名

使用

包名.模块名.工具名

方式二

from 包名 import 模块名

使用

模块名.工具名

方式三

from 包名.模块名 import 工具名

使用

直接使用工具名

5.3变量类型

5.3.1变量引用

引用:

(1)定义变量的时候,变量和数据都会在内存开辟空间

(2)变量所对应的内存空间中存储的是数据所在内存地址(平时理解为将数据存储到变量中)

(3)变量中保存数据的地址,就称为是引用

(4)python中所有数据的传递,传递的都是引用(即地址)

(5)赋值运算符 =  会改变变量的引用,只有 = 可以修改变量的引用

(6)可以使用id(变量) 函数,查看变量的引用

5.3.2可变类型和不可变类型

根据内存中的数据是否允许修改,将数据类型分为可变类型与不可变类型

简单理解:不使用等号能不能修改数据值

可变类型:可以修改

列表list

字典dict

集合set

不可变类型:不允许修改

数字类型int float  bool

字符串str

元组tuple

5.3.3局部变量和全局变量

根据变量定义的位置将变量分为局部变量和全局变量

5.3.3.1局部变量

(1)在函数内部定义的变量,称为局部变量

(2)特点

局部变量:只能在当前函数内部使用

可以在不同函数内定义名字相同的局部变量

(3)生命周期(使用范围)

在函数执行(调用)的时候被创建,函数执行结束被销毁(删除)

(4)形参可以认为是局部变量

(5)如果想要在函数外部使用局部变量的值,使用return返回

def func1():
    num = 10 # 局部变量
    print(num)

def func2():
    num = 20
    print(num)

if __name__ == '__main__':
    func1() # 10
    func2() # 20
5.3.3.2全局变量

1、在函数外部定义的变量

2、特点

(1)全局变量可以在任意函数内访问(读取)

(2)想要在函数内部修改全局变量的引用,需要使用global关键字声明(使用global关键字可以声明为全局变量)

(3)如果在函数内部出现和全局变量名字相同的局部变量,在函数内部使用的是局部变量

3、生命周期

(1)代码执行时候创建,执行结束销毁

# 定义全局变量
global_num = 10

def func1():
    print(global_num)

def func2():
    global_num = 20 # 定义局部变量
    print(global_num)

def func3():
    global global_num
    global_num = 30
    print(global_num)

if __name__ == '__main__':
    func1() # 10
    func2() # 20
    func3() # 30 修改了全局变量,值修改为30
    func1() # 30

5.4函数进阶-高级函数

函数返回多个数据值

return关键字的两个作用

(1)返回数据值

(2)结束函数的运行

函数中如果想要返回多个数据值,一般是组成元组进行返回

5.4.1函数传参的方式

是指如何将实参的值传递给形参

(1)位置传参

按照形参的顺序将实参的值传递给形参

(2)关键字传参

在函数调用的时候,指定将实参传递给哪个形参

(3)混合使用

位置参数必须写在关键字参数的前边,关键字参数必须放在位置参数的后边。

同一个形参只能接收一个实参值(不能即使用位置传参和关键字传参给同一个形参传参)

def show_info(name,age):
    print(f"name:{name},age:{age}")

# 位置传参
show_info('鲁班',18)

# 关键字传参
show_info(age=18,name='貂蝉')

# 混合使用
show_info('王昭君',age=14)

5.4.2缺省参数(默认参数)

定义:在函数定义的时候,给形参一个默认的数据值,这个参数就是缺省参数(默认参数)

特点:在函数调用的时候,缺省参数可以不用传递实参值

(1)如果不传实参值,使用的就是默认值

(2)如果传递实参值,使用就是传递的实参值

注:缺省参数必须写在普通参数的后边

"""
定义show_info 参数:姓名、年龄、性别
将年龄设置为默认参数,性别设置为默认 保密
"""
# parameter形参,argument实参
def show_info(name,age=18,sex='保密'):
    print(name,age,sex)

# 调用
show_info('项羽',18,'男')
# 诸葛亮
show_info('诸葛亮')
# 鲁班 20
show_info('鲁班',20)
# 女娲 女
show_info('女娲',sex='女')

5.4.3多值参数(可变参数/不定长参数)

1、在定义函数的时候,不确定在调用的时候,实参有多少个,此时可以使用多指参数

2、在普通的参数前边加上一个* 这个参数就变为多值参数

3、这个参数可以接收任意多个位置传参的数据,类型 元组

4、这个形参一般写作args(arguments)即*args

5.4.4参数顺序

# 普通,缺省,多值

def 函数名(普通,缺省,*args)

        pass

"""
定义一个函数my_sum,作用:可以对任意多个数字进行求和计算
"""
from TestDemo.可变与不可变类型 import my_tuple


def my_sum(*args):
    num = 0
    for i in args:
        num +=i
    return num
print(my_sum()) # 0
print(my_sum(1)) # 1
print(my_sum(1,2)) # 3
print(my_sum(1,2,3)) # 6

my_tuples = (1,2,3,4,5)
# 需要对元组中的所有数据使用my_sum进行求和
# 想要把列表(元组)中的数据作为位置参数进行传递,
# 只需要在列表(元组)前边加上一个*进行拆包即可
print(my_sum(*my_tuples)) # 15

5.4.5匿名函数

定义:使用lambda关键字定义的表达式

语法:lambda 参数,参数:一行代码 # 只能实现简单的功能,只能写一行代码

# 匿名函数一般不直接使用,作为函数的参数使用

"""
定义匿名函数,可以对两个数字进行求和
"""
# 匿名函数也可以调用
func = lambda a,b:a+b # 将匿名函数地址保存到变量func中,所以func就代指函数
print(func(1,2))
# 给定一组列表数据根据年龄排序
# user_list 是一个列表,其中包含三个字典元素
user_list = [
    {'name':'鲁班','age':30},
    {'name':'张飞','age':18},
    {'name':'项羽','age':20}
]
"""
user_list.sort() #只能对数字,字符串排序
想要对列表中的字典排序,需要key形参指定根据字典中的什么键排序
列表.sort(key=lambda x:x['键'])
"""
print(f"原数据:{user_list}")
user_list.sort(key=lambda x:x['age'])
print(user_list)

六、面向对象

了解面向过程:根据需求,将某些独立功能封装成一个又一个函数,最后完成的代码就是顺序地调用不同的函数

面向对象概念:相比较函数,面向对象是更大的封装,根据职责在一个对象中封装多个方法,根据职责确定不同的对象,在对象内部封装不同的方法。

面向对象核心:类和对象

6.1类和对象

类:是对具有相同特征或者行为的事物的一个统称,是抽象的不能直接使用

        指代多个事物

        代码中类是由关键字class定义

对象:是由类创建出来的一个具体存在的事物,可以直接使用

        指代一个具体事物

        代码中使用类去创建(创建过程叫实列化)

6.1.1类的构成

(1)类名:多个事物起一个名字,满足标识符规则,见名知意,类名满足大驼峰命名法(所有单词的首字母大写)

(2)属性(事物的特征)

(3)方法(事物的行为)

6.1.2面向对象代码的步骤

(1)设计类(找类的三要素)

(2)定义类

(3)创建对象(实例化对象)

(4)由对象调用类中方法

6.1.3面向对象基本语法

(1)定义类

# 1定义类使用关键字class
class 类名:
    # 在class的缩进中定义类 的属性和方法
    def 方法名(self): # 方法本质是函数
        pass
    
# 2创建对象(实例化对象)
"""
在代码中 类名()就是创建对象。一般使用变量将创建的对象保存起来
"""
变量 = 类名() # 一般将这个变量称为对象,本质:变量中保存的是对象的引用地址

# 3调用类中方法
# 由类创建的对象可以调用类中的方法
对象.方法名()

6.2属性和方法

6.2.1self参数

(1)从函数的语法来看,self是形参,名字可以是任意的变量名,只是习惯叫self

(2)特殊点:self是一个普通的参数,按照函数的语法,在调用的时候必须传递实参值,原因是python解释器自动将调用这个方法的对象作为参数传递给self。谁调用函数self就是谁。

所以self就是调用这个方法的对象。

class Cat:
    def eat(self): # self是调用这个方法的对象
        """吃鱼的方法"""
        print(f'self:{id(self)}')
        print('小猫爱吃鱼')

# 创建对象
tom = Cat()
print(f"tom :{id(tom)}")
# 通过对象调用类中的方法
tom.eat() # tom调用,self就是tom

blue_cat =Cat()
print(f'blue:{id(blue_cat)}')
blue_cat.eat() # blue_cat调用,self就是blue_cat

# 运行输出
tom :2030543059904
self:2030543059904
小猫爱吃鱼
blue:2030543059856
self:2030543059856
小猫爱吃鱼


6.2.2属性的使用

属性:表示事物的特征,可以给对象添加属性或者获取对象的属性值

给对象添加属性值:

对象.属性名=属性值 # 添加或者修改

获取对象的属性值:

对象.属性名

在方法中操作属性(self是对象)

self.属性名=属性值

self.属性名

例如类外部添加类属性:

class Cat:
    def eat(self): # self是调用这个方法的对象
        """吃鱼的方法"""
        print(f'self:{id(self)}')
        print('小猫爱吃鱼')
        print(f"小猫{self.name}爱吃鱼...")

# 创建对象
tom = Cat()
# 通过对象调用类中的方法
print(f"tom :{id(tom)}")
# 给Tom对象添加name属性
tom.name = '汤姆'
print(tom.name)
tom.eat()

blue_cat =Cat()
print(f'blue:{id(blue_cat)}')
blue_cat.name = '蓝猫'
blue_cat.eat()

6.2.3魔法方法

类内部添加属性:

在python中存在一类方法,以两个下划线开头,两个下划线结尾,在满足某个条件的情况下,会自动调用,这一类方法称为魔法方法---因为会自动调用

魔法方法:

(1)什么情况下会自动调用(自动调用的时机)?

(2)应用场景?

(3)注意事项?

6.2.3.1初始化方法__init__

(1)调用时机:在创建对象之后,会自动调用yinyon

(2)应用场景:初始化对象,给对象添加属性

(3)注意事项:

        不要写错

        如果属性是会变化的,则可以将这个属性的值作为参数传递,在创建对象的时候,必须传递实参值

#name属性不变:
class Cat:
    def __init__(self):
        print('我是init方法,我被调用了') # 断言
        self.name = '汤姆'

    def eat(self):
        print(f"小猫{self.name}爱吃鱼...")

# init方法创建对象之后会自动调用
#blue = Cat()
blue_cat = Cat()
blue_cat.eat()

black_cat = Cat()
black_cat.eat()

------------------------
我是init方法,我被调用了
小猫汤姆爱吃鱼...
我是init方法,我被调用了
小猫汤姆爱吃鱼...

# name属性值变化就参数化

class Cat:
    def __init__(self,name):
        print('我是init方法,我被调用了') # 断言
        self.name = name

    def eat(self):
        print(f"小猫{self.name}爱吃鱼...")

# init方法创建对象之后会自动调用
#blue = Cat()
blue_cat = Cat('蓝猫')
blue_cat.eat()

black_cat = Cat('黑猫')
black_cat.eat()

---------------------------
我是init方法,我被调用了
小猫蓝猫爱吃鱼...
我是init方法,我被调用了
小猫黑猫爱吃鱼...
6.2.3.2__str__方法

(1)调用时机:

        使用print(对象) 打印对象的时候,会自动调用

        如果没有定义__str__方法,默认打印的是对象的引用地址

        如果定义__str__方法,打印的是方法的返回值

(2)应用场景

        使用print(对象) 打印输出对象的属性信息

(3)注意事项

        必须返回一个字符串

"""
定义Cat类,包含属性name和age,打印对象的时候,可以输出对象的姓名和年龄
类名:Cat
属性:name,age
方法:__str__,__init__
"""
class Cat:
    def __init__(self,name,age):
        self.name =name # 添加name属性
        self.age = age # 添加age属性

    def __str__(self): # 一般不使用print,直接return返回
        return f"姓名:{self.name},年龄:{self.age}"

# 创建对象
tom = Cat('汤姆',3)
print(tom)

-----------------------------
姓名:汤姆,年龄:3

6.3面向对象三大特征

(1)封装:根据需求将属性和方法封装到一个抽象的类中。

(2)继承:实现代码的重用,相同的代码不需要反复的编写

(3)多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

6.3.1封装-登录模拟举例

需求:进入某web项目登录页面,输入用户名、密码、验证码之后登录系统

类的设计:

类名:LoginPage

属性:用户名username、密码password、验证码verify_code

方法:login

class LoginPage:
    """登录页面"""
    def __init__(self,username,password,code):
        self.username = username # 用户名
        self.password = password # 密码
        self.verify_code = code # 验证码
        
    def login(self):
        print(f"1.输入用户名:{self.username}")
        print(f"2.输入密码:{self.password}")
        print(f"3.输入验证码:{self.verify_code}")
        print(f"4.点击登录")

if __name__ == '__main__':
    admin = LoginPage('admin','123456','8888')
    admin.login()
--------------------------------
1.输入用户名:admin
2.输入密码:123456
3.输入验证码:8888
4.点击登录

6.3.2继承

说明:如果多个类中存在相同的代码逻辑,则可以考虑将相同逻辑的代码抽取封装到父类中,再通过继承关系,直接实例化子类对象并调用父类中的方法使用即可,进而可以避免反复编写相同逻辑 的代码

注:在继承关系中,子类可以拥有父类的所有方法和属性

# 语法
# class 类A(object)
# class 类A

class 类A: # 默认继承object类,object类是python中最原始的类
    pass
class 类B(类A): # 就是继承,类B继承类A
    pass
# 类A:父类 或 基类
# 类B:子类 或 派生类
# 子类继承父类后,子类对象可以直接使用父类中的属性和方法

继承具有传递性:C继承B,B继承A,C可以使用A中的属性和方法

对象调用方法的顺序:对象.方法名()

注:会先在自己的类中查找,找到直接使用;没有找到就去父类中查找,找到直接使用,没有找到就一直在父类的父类中查找找到直接使用,找不到就一直找直到object类中查找,找到直接使用找不到就报错!

"""
1.定义动物类,动物类有姓名和年龄属性,具有吃和睡的行为
2.定义猫类,猫类具有动物类的所有属性和方法,并且具有抓老鼠的特殊行为
3.定义狗类,狗类具有动物类的所有属性和方法,并且具有看门的特殊行为
4.定义哮天犬类,哮天犬类具有狗类的所有属性和方法,并且具有飞的特殊行为
"""
class Animal:
    """动物类"""
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def eat(self):
        """吃"""
        print(f"{self.name}:吃东西")
    def sleep(self):
        """睡"""
        print(f"{self.name}:睡觉")

class Cat(Animal):
    """猫类"""
    def catch(self):
        print(f"{self.name}:会抓老鼠...")

class Dog(Animal):
    """狗类"""
    def look_the_door(self):
        """看门"""
        print(f"{self.name}:正在看家...")
class XTQ(Dog):
    """哮天犬类"""
    def fly(self):
        """飞"""
        print(f"{self.name}:在南天门飞...")

if __name__ == '__main__':
    ani = Animal('佩奇',2)
    ani.eat()
    ani.sleep()
    cat = Cat('汤姆',4)
    cat.eat() # 调用父类Animal中的方法
    cat.sleep() # 调用父类Animal中的方法
    cat.catch() # 调用自己类中的方法
    dog = Dog('来福',6)
    dog.eat()
    dog.sleep()
    dog.look_the_door()
    xtq = XTQ('哮天犬',1000)
    xtq.eat()
    xtq.sleep()
    xtq.look_the_door()
    xtq.fly()
----------------------------------
佩奇:吃东西
佩奇:睡觉
汤姆:吃东西
汤姆:睡觉
汤姆:会抓老鼠...
来福:吃东西
来福:睡觉
来福:正在看家...
哮天犬:吃东西
哮天犬:睡觉
哮天犬:正在看家...
哮天犬:在南天门飞...
6.3.2.1重写(override)

1.什么是重写?

重写就是在子类中定义和父类中名字一样的方法

2.重写的原因?为什么重写?

父类中的代码不能满足子类对象的需要

3.重写的方式

(1)覆盖式重写

(2)扩展式重写

覆盖式:父类中的功能全部不要,直接在子类中定义和父类一样的方法接口,直接书写新的代码

扩展式:父类中的功能还需要,只是添加了新的功能

(1)先在子类中定义和父类中名字一样的方法

(2)在子类代码中使用super().方法名()调用父类中的代码

(3)书写新的功能

6.3.3多态

多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度

"""
案例:
1.在Dog类中封装方法game,行为:普通狗只是简单玩耍
2.定义哮天犬XiaoTianDog继承Dog,并重写game方法,行为:哮天犬需要在天上玩耍
3.定义person类,并且封装一个和狗玩耍的方法,在方法内部直接让狗对象调用game方法
"""
class Dog:
    def game(self):
        print('普通狗简单的玩耍...')

class XTQ(Dog):
    def game(self):
        print('哮天犬在天上玩耍...')

class Person:
    def play_with_dog(self,dog):
        """参数dog是狗类或者其子类的对象"""
        print('人和狗在玩耍...',end='')
        dog.game()

if __name__ == '__main__':
    dog1 = Dog()
    xtq = XTQ()
    jack = Person()
    jack.play_with_dog(dog1)
    jack.play_with_dog(xtq)

------------------------------------------
人和狗在玩耍...普通狗简单的玩耍...
人和狗在玩耍...哮天犬在天上玩耍...

6.4属性和方法的分类

6.4.1私有和公有

在python中,定义类的时候,可以给属性和方法设置访问权限,即规定在什么地方可以使用

(1)公有权限:直接定义的属性和方法就是公有的

特点:可以在任何地方访问和使用,只要有对象就可以访问使用

(2)私有权限:只能在类内部定义(class关键字的缩进中),只需要在属性名或者方法名前边加上两个下划线,这个方法或者属性就变成私有

特点:私有只能在当前类的内部使用,不能在类外部和子类直接使用

应用场景:一般来说,定义的属性和方法都为公有,当某个属性不想在外部直接使用定义为私有,当某个方法是内部的方法(不想在外部使用)定义为私有。

"""
案例:
定义人类,name属性,age属性(私有)
"""
class Person:
    def __init__(self,name,age):
        self.name =name
        self.__age = age # 私有属性

    def __str__(self): #公有方法,下划线是自带的
        return f"{self.name},{self.__age}"
    
    def set_age(self,age):
        """定义公有方法修改私有属性"""
        if age <0 or age >120:
            print('提供年龄信息不符合')
            return
        self.__age = age
if __name__ == '__main__':
    jack = Person('杰克',18)
    print(jack)
    jack.set_age(100)
    print(f"调用公有方法修改私有属性age:{jack}")
---------------------------
杰克,18
调用公有方法修改私有属性age:杰克,100

6.4.2对象划分

python中一切皆对象。

类对象:就是类,就是使用class定义的类

在代码执行的时候,解释器会自动的创建

作用:使用类对象创建实例对象,存储一些类的特征值(类属性)

实例对象:

(1)创建对象也称为实例化,所以由类对象(类)创建的对象称为实例对象简称实例

(2)一般来说没有特殊强调,所说的对象都是指实例对象(实例)

(3)实例对象可以保证实例的特征值(实例属性)

(4)实例就是使用 类名() 创建的对象

6.4.3属性的划分

1.实例属性

概念:是每个实例对象具有的特征(属性),每个实例对象的特征

定义:一般都是在init方法中,使用self.属性名=属性值 来定义

特征(内存):每个实例对象都会保存自己的实例属性,即内存中存在多份

访问和修改:

# 可以认为通过self,因为self就是实例对象

实例对象.属性=属性值 # 修改

实例对象.属性 # 调用

2.类属性

概念:是类对象具有的特征,是整个类的特征

定义:一般在类的内部(class缩进中),方法的外部(def的缩进外部)定义的变量

特征(内存):只有类对象保存一份,即在内存中只有一个

访问和修改:

# 即通过类名

类对象.属性=属性值 # 修改

类对象.属性 # 调用

应用场景:

代码中使用的属性基本上都是实例属性,即通过self定义

当某个属性值描述的信息是整个类的特征(这个值变动,所有的这个类的对象这个特征都会发声变化)

举例:比如定义很多个狗类对象有普通狗、哮天犬等某一天发现不属于犬科了那么所有对象都要变化。比如普通狗的名字发声变化了是不影响哮天犬的。所以就是实例。

6.4.4方法的划分

1.实例方法

使用时机:如果方法中需要使用实例属性,则这个方法必须定义为实例方法

定义:

# 直接定义的方法就是实例方法

class 类名:

        def 方法名(self):

                pass

参数:参数一般写作self,表示的是实例对象

调用:实例对象.方法名()

2.类方方法

使用时机:如果方法中不需要使用实例属性但需要使用类属性,则这个方法可以定义为类方法

定义:

# 定义类方法需要在方法名上方书写@classmethod,即使用@classmethod装饰器装饰

@classmethod

class 类名:

        def 方法名(cls):

                pass

参数:一般写作cls表示类对象即类名,同样不需要手动传递,python解释器会自动传递

调用:类名.方法名() 或者 实例对象.方法名()

3.静态方法

使用时机:方法中即不需要使用实例属性也不需要使用类属性,可以将这个方法定义为静态方法

定义:

# 定义静态方法,需要使用装饰器@staticmethod装饰方法

class 类名:

        @staticmethod

        def 方法名():

                pass

参数:静态方法对参数没有要求,一般没有不需要写

调用:类名.方法名() 或者 实例对象.方法名()

综合案例:

需求:

1.设计一个Game类

2.属性:

        定义一个rop_score类属性----记录游戏的历史最高分

        定义一个player_name实例属性----记录当前游戏的玩家姓名

3.方法:

        静态方法show_help()----显示游戏帮助信息

        类方法show_top_score()----显示历史最高分

        实例方法start_game()----开始当前玩家的游戏

                (1)使用随机数生成1-100之间数字作为本次游戏的得分

                (2)打印本次玩家的游戏得分

                (3)当前玩家分数和历史最高分比较,如果比历史最高分高就修改历史最高分。没有就不动历史最高分

4.主程序:main

(1)查看帮助信息

(2)查看历史最高分

(3)创建游戏对象开始游戏

(4)再一次开始游戏

import random

class Game:
    # 定义类属性,保存历史最高分
    top_score = 0

    def __init__(self,name):
        self.play_name = name # 实例属性

    # 静态方法
    @staticmethod
    def show_help():
        print('这是游戏的帮助信息')

    # 类方法
    @classmethod
    def show_top_score(cls):
        print(f"历史最高分为:{cls.top_score}")

    # 实例方法
    def start_game(self):
        print(f"玩家{self.play_name}开始游戏...")
        score = random.randint(1,100) # 本次游戏得分
        print(f"玩家{self.play_name}本次游戏得分为{score}")
        if score > Game.top_score:
            Game.top_score = score

if __name__ == '__main__':
    Game.show_help()
    Game.show_top_score()
    player = Game('鲁班')
    player.start_game()
    Game.show_top_score()
    player.start_game()
    Game.show_top_score()
--------------------------------------
这是游戏的帮助信息
历史最高分为:0
玩家鲁班开始游戏...
玩家鲁班本次游戏得分为90
历史最高分为:90
玩家鲁班开始游戏...
玩家鲁班本次游戏得分为17
历史最高分为:90

七、文件操作

7.1文件基本操作

7.1.1打开和关闭文件

文件的操作步骤:

(1)打开文件

(2)读写文件

(3)关闭文件(保存)

1.打开文件open()

open()函数常用参数解释:

open(file,mode='r',encoding=None) # 将硬盘中的文件加载到内存中

参数file:表示要操作的文件的名字,可以使用相对路径和绝对路径

绝对路劲:从根目录开始书写如C:/

相对路径:从当前目录开始书写的路径如./ 

参数mode:打开文件的方式

r 只读打开 read 如果文件不存在会报错

w 只写打开 write 如果文件存在会覆盖原文件

a 追加打开 append 在文件的尾部写入新的内容

参数encoding:编码格式

utf-8将一个汉字转换为3个字节的二进制

gbk将一个汉字转换为2个字节的二进制

返回值:文件对象

2.关闭文件close()

文件对象.close() # 关闭文件,如果是写文件会自动保存即将内存中的数据同步到硬盘

3.读文件read()

变量 = 文件对象.read()

返回值:返回读取到的文件内容。类型是字符串

"""
with open(file,mode,encoding) as 变量:
    pass
    
# 变量就是文件对象
使用这种方式打开文件,会自动进行关闭,不用手动书写关闭的代码。
出了with的缩进之后,文件就会自动关闭。
"""
with open('a.txt',encoding='utf-8') as f:
    buf = f.read()
    print(f"buf ={buf}")

# 普通写法
f = open('a.txt',encoding='utf-8')
data = f.read()
print(f"data={data}")
f.close()

4.写文件write()

文件对象.write()

参数:写入文件的内容。类型字符串

返回值:写入文件中的字符数,字符串的长度

# 1.打开文件
f = open('a.txt','w',encoding='utf-8')
# 2.写文件
f.write('hello python')
# 3.关闭文件
f.close()

# 追加写入
with open('a.txt','a',encoding='utf-8') as f:
    f.write('我是追加写入内容\n')

7.2json文件操作

7.2.1按行读取文件readline()

文件对象.readline() # 一次读取一行的内容,返回读取到的内容

read()和readline()如果读到文件末尾,返回的都是空字符串

with open('a.txt',encoding='utf-8') as f:
    buf = f.readline()
    print(f"buf={buf}")

7.2.2模拟读取大文件

需求:文件里面有未知的很多行内容,现需一次按行全部读取出来

with open('a.txt',encoding='utf-8') as f:
    while True:
        buf = f.readline()
        if buf == "":
            break
        else:
            print(buf,end='')




# 代码优化
with open('a.txt',encoding='utf-8') as f:
    while True:
        buf = f.readline() # 文件内容读完了,返回空字符串
        if buf: # 空字符串就是 False
            print(buf,end='')
        else:
            break

7.2.3Json语法

1.json中的数据类型

对象{}----python中字典

数组[]----python中列表

字符串,必须使用英文双引号----str

数字类型----int,float

bool类型----True False

空值----None

2.json文件,是一个对象或者是数组,对象和数组可以相互嵌套

3.json中的对象是由键值对组成的,键必须是字符串类型

4.json中的数据直接使用逗号隔开,最后一个数据后边不能加逗号

{
  "name": "鲁班",
  "age": 18,
  "isMan": true,
  "school": null,
  "link": ["听歌","看书","打野"],
  "address": {
    "country": "China",
    "city": "深圳"
  }

7.2.4读取json文件

(1)导包import json

(2)json.load(文件对象)----得到的是列表或者字典

import json

with open('person_info.json',encoding='utf-8') as f:
    buf = json.load(f)
    print(type(buf))
    print(buf)
    # 姓名
    print(buf.get('name'))
    # 城市
    print(buf.get('address').get('city'))
    # 看书
    print(buf.get('link')[1])
    

-----------------------------------
<class 'dict'>
{'name': '鲁班', 'age': 18, 'isMan': True, 'school': None, 'link': ['听歌', '看书', '打野'], 'address': {'country': 'China', 'city': '深圳'}}
鲁班
深圳
看书

7.2.5json文件的写入

(1)将python中列表或字典转换为json文件

(2)导包 import json

(3)使用json.dump(python中数据,文件对象)  # 转储转存

import json

info = {'name':'鲁班','age':18,'sex':'男'}
"""
ensure_ascii=False 直接显示中文
indent=2 写入json文件缩进2字符
"""
with open("luban_info.json",'w',encoding='utf-8')as f:
    json.dump(info,f,ensure_ascii=False,indent=2)

注:若看到某个方法中出现*那么星后面所有的参数必须使用关键字传参

八、异常处理

8.1捕获异常

异常概念:程序运行时,如果python解释器遇到一个错误,则会停止程序的执行,并且提示一些错误信息,这就是异常。

程序停止执行并且提示错误信息这个动作称为抛出异常

异常类型:错误信息描述

8.1.1捕获异常语法

try:

        pass # 尝试执行的代码

except:

        pass # 出现异常时执行的代码

说明:

try尝试,下方编写要尝试的代码,不确定是否能够正常执行的代码

except如果有异常捕获,下方编写捕获到异常,处理失败的代码
# 1.获取用户从键盘输入的数据
num = input("请输入数字:")
try:
    # 2.转换数据类型为整数
    num = int(num)
    # 3.数据转换类型正确时,输出数据内容
    print(f"[INFO]{num}")
except:
    # 4.数据转换类型错误时,提示输入正确数据
    print("[INFO]请输入正确的数据")

8.1.2捕获指定类型的异常

发生的异常可能存在多种,针对不同类型的异常解决处理的方案不一样

try:
    pass # 可能发生异常的代码
except 异常类型1:
    pass # 发生异常类型1,执行的代码
except 异常类型2:
    pass # 发生异常类型2,执行的代码
except 异常类型n:
    pass # 发生异常类型n,执行的代码

如何直到异常类型是什么类型?

例如:需求输入一个数那么久输入一个字母运行就可以看到报错类型

8.1.3捕获未知类型的异常(使用最多)

语法:

try:
    pass # 可能发生异常的代码
except Exception as e:# Exception常见异常类的父类,变量e属于异常对象,print()可以打印异常信息
    pass # 发生异常执行的代码



try:
    num = int(input('请输入一个整数数字:'))
except Exception as e:# Exception常见异常类的父类,变量e属于异常对象,print()可以打印异常信息
    print(f'发生异常,{e}') # 发生异常执行的代码

8.1.4异常捕获的完整结构

"""异常捕获的完整结构"""
try:
    pass #可能发生异常的代码
except 异常类型:
    pass #发生了指定类型的异常执行的代码
except Exception as e:
    pass #发生了其他类型的异常执行的代码
else:
    pass #没有发生异常,会执行的代码
finally:
    pass #不管是否发生异常,都会执行的代码

 8.1.5异常的传递

1.异常的传递是python中已经实现好的功能,不需要自己重新写代码实现

2.异常传递是指:在函数的嵌套调用过程中,如果发生了异常,没有进行捕获,会将这个异常传递到函数调用的地方,直到被捕获为止,如果一直没有捕获,才会报错终止执行

# 1.定义函数demo1()提示用户输入一个整数并返回
def demo1():
    num = int(input('请输入一个整数:'))
    return num
# 2.定义函数demo2()调用demo1()
def demo2():
    demo1()
# 3.在主程序中调用demo2()
if __name__ == '__main__':
    demo2()


-------------------------
请输入一个整数:a
Traceback (most recent call last):
  File "D:\study\PythonProject\TestDemo\异常传递.py", line 10, in <module>
    demo2()
  File "D:\study\PythonProject\TestDemo\异常传递.py", line 7, in demo2
    demo1()
  File "D:\study\PythonProject\TestDemo\异常传递.py", line 3, in demo1
    num = int(input('请输入一个整数:'))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'a'

例如:当输入一个字符a后运行报错:

本来是第3行报错,但报错传到第7行,又传到第10行仍没有异常处理才报错结束程序

为了简洁代码可以在最外层主函数捕获异常处理:

# 1.定义函数demo1()提示用户输入一个整数并返回
def demo1():
    num = int(input('请输入一个整数:'))
    return num
# 2.定义函数demo2()调用demo1()
def demo2():
    demo1()
# 3.在主程序中调用demo2()
if __name__ == '__main__':
    try:
        demo2()
    except Exception as e:
        print(e)


------------------------------------------
请输入一个整数:a
invalid literal for int() with base 10: 'a'

进程已结束,退出代码为 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值