2023年7月30日星期日

python基本语法

python基本语法

python基本语法整合

记录了远古时期学习python基本语法和几个容器的笔记,大多数是代码附注释。可能比较适合从有c++语言基础学习python

python字符串

"""
字符串,以数据容器的视角
老字符串无法修改
"""
my_str = "Wo ai hakurei reimu"
value = my_str[3]
value = my_str[-2]

# my_str[2] = "1" err字符串无法修改

# index查找子字符串
pos1 = my_str.index("ai")
print(f"ai 's position is in {pos1}")

# replace(str1, str2)
# 将1子字符串全部删掉,换成2子字符串
# 注意返回值是一个新的字符串需要接受
my_str2 = my_str.replace("hakurei", "kirisame")
print(my_str2)

# split(分隔字符串)
# 类似strtok,按照指定的分隔字符串,将字符串划分为多个字符串,并存入列表对象中,
# 字符串本身不变,但是得到一个列表对象
my_list = my_str.split(" ")
print(my_list)

# 字符串规整 strip(str)
# 默认去除前后空格
my_str3 = "     ite as d "
new_mystr = my_str3.strip()
print(new_mystr)
my_str3 = "112     ite as d 222"
new_mystr = my_str3.strip("12 ")  # 1 / 2 / (空格)的所有子串
print(new_mystr)

# count
# len

python函数

# 多返回值,使用逗号隔开
def test_return_func():
    return 1, 2


x, y = test_return_func()
print(f"multi return {x} {y}")


# 函数参数种类
# 根据使用方式的不同分为
# 位置参数 根据函数定义的参数位置(经常用的那种)
# 关键字参数 函数调用时通过"键=值"的形式,可以让函数更加清晰,消除了参数的顺序要求
def user_info(name, age, gender):
    print(f"你的名字是{name},年龄是{age},性别是{gender}")


# 关键字传参(可以不按照顺序)
user_info(age=20, name="博丽灵梦", gender="girl")
# 可以和位置参数混用,但是位置参数必须在前,且匹配参数顺序
user_info("博丽灵梦", age=20, gender="girl")


# 缺省参数
# 类似c++参数都是有默认值的
# 同样,缺省项在定义时要放到最后面
def return_func2(name="博丽灵梦"):
    print(f"{name}")


return_func2("雾雨魔理沙")
return_func2()


# 不定长(可变)参数
# 位置传递和关键字传递
# 位置传递:穿进的所有参数都会被args变量收集,他会根据穿进参数的位置合并为一个元组,args是元组类型
def user_info(*args):  # 星号是关键字,表示args可以接受的参数数量是无限的
    print(args)


user_info("博丽灵梦", "雾雨魔理沙")


# 关键字传递,两个星号,数量不受限,需要键=值的形式,并组成字典
def user_info(**kwargs):
    print(kwargs)


user_info(name="hakurei", nick="miaow")  # key不需要引号


# 函数作为参数传递
# 计算逻辑的传递
def cmp_main(func):
    print(func(1, 5))


def cmp_func1(x, y):
    return x < y


def cmp_func2(x, y):
    return x > y


print("调用第一个")
cmp_main(cmp_func1)
print("调用第二个")
cmp_main(cmp_func2)

# lambda匿名函数
# 在函数的定义中
# def 关键字可以定义带有名称的函数
# lambda关键字,可以定义匿名函数 (无名称)
# 有名称的函数,可以基于名称重复使用
# 无名称的匿名函数,只可临时使用一次。


# 匿名函数定义
"""
匿名函数定义语法:
lambda 传入参数: 函数体(一行代码)
lambda 是关键字,表示定义匿名函数
传入参数表示匿名函数的形式参数,如:xy表示接收2个形式参数
函数体,就是函数的执行逻辑,要注意:只能写一行,无法写多行代码
"""
print("尝试lambda函数")
cmp_main(lambda x, y: x > y) # 和c++相比,def能直接写进函数里面,所以py中的lambda函数用于临时用途就可以了

python列表

可以简单理解为stl中的vector容器,不过list具有混装的特性

"""
Some test for list container
容纳多个元素2**63 - 1
可以容纳不同类型的元素(混装)
数据是有序存储待(有下标序号)
允许重复数据存在
可以修改(增删改)
"""
# 1.1 查找某特定元素在列表中出现待第一个下标
a = list()
my_list = [1, 5, "8964"]
pos_1 = my_list.index(5)
print(pos_1)

# 1.2 不存在待值会报错
# pos_2 = my_list.index("xijingping")

# 2.1 修改下标值待值
my_list[0] = 7
print(f"after modify {my_list}")

# 3.1 插入到指定的下标位置
my_list.insert(1, "xi")
print(f"after insert{my_list}")

# 3.2 追加一个元素
my_list.append("so")
print(f"after append {my_list}")

# 3.3 追加一批元素
my_list.extend([1, 23])
print(f"after extend {my_list}")

# 4.1 del关键字,元素删除
my_list = [1, 5, "8964"]
del my_list[2]
print(my_list)

# 4.2 pop方法,移除并且接受
my_list = [1, 5, "8964"]
receive = my_list.pop(2)
print(f"{my_list},{receive}")

# 4.3 remove方法,移除第一个匹配项
my_list = [1, 5, "89", "64", "89"]
my_list.remove("89")
print(f"remove {my_list}")

# 4.4 clear 清空列表
my_list.clear()
print(my_list)

# 5.1 统计某个元素出现多少次count
my_list = [1, 2, 3, 4, 5, 1, 2, 1]
count = my_list.count(1)
print(count)

# 6.1 len(size)全部元素数量
print(f"size is {len(my_list)}")

#  example
# num = 0
# age_list = [21, 25, 21, 23, 22, 20]
# print(f"序号{num},此时列表为{age_list}")
# num += 1
# num = 0
# age_list = [21, 25, 21, 23, 22, 20]

# age_list.append(31)
# print(f"序号{num},此时列表为{age_list}")
# num += 1
# age_list.extend([29, 33, 30])
# print(f"序号{num},此时列表为{age_list}")
# num += 1
# receive = age_list.pop(0)
# print(f"序号{num},此时列表为{age_list}->{receive}")
# num += 1
# receive = age_list.pop()
# print(f"序号{num},此时列表为{age_list}->{receive}")
# num += 1
# print(f"序号{num},此时列表为{age_list}->{age_list.index(31)}")

# 遍历
# while循环
index = 0
while index < len(my_list):
    print(my_list[index])
    index += 1
# for循环
for eke in my_list:
    print(eke)

python元组

"""
元组
不可以被修改
可以封装多个、不同类型的元素在内
虽然元组本身不能修改,但是如果有一个元素是list,那么这个list可以修改
使用小括号定义
a = ()
a = turple()
"""

# 1 定义
my_turple = (1, 2, "123")
my_turple2 = ()
print(f"{type(my_turple2)} , {my_turple}")
## 特殊的,定义单个元素的元组对象时
my_turple3 = "123"  # 这里自动格式化,加括号会自动消失,但即使加了括号也就是显示那个唯一的元素
# 不能修改my_turple = ()
print(f"{type(my_turple3)}")
print(f"{type(my_turple)}")
my_turple3 = ("123",)
# 单个元素元组加括号
print(f"{type(my_turple3)}")
# 其他方法也有index count len while for循环
# 虽然元组本身不能修改,但是如果有一个元素是list,那么这个list可以修改
tur = (1, 2, [1, 3])
print(tur)
tur[2][0] = "123"
print(tur)

python set

python中的dict底层是用哈希表实现的,类似unorderer_set

"""
set
去重处理,并且内容无序
使用花括号
空集合set()
"""

# 定义
my_set = {"2", "1", "我是灵梦"}
# my_set2 = {}
my_set2 = set()
print(f"{my_set} {type(my_set2)}")

# 不支持下标索引访问,所以序列就不包含set
# 可以修改
# .add添加新元素
my_set.add("雾雨魔理沙")
print(my_set)
my_set.add("雾雨魔理沙")  # 会去重
print(my_set)

# .remove将指定元素从集合内删除
my_set.remove("1")
print(my_set)

# .pop随机取出一元素

# .clear清空
my_set.clear()
print(my_set is None)  # false

# 取出两个元素的差集
# 集合1.difference(集合2) 得到一个新集合,集合1有但是集合2没有

# plus:消除差集,.difference_update
# 在集合1中消除元素以成为.difference(集合2),即删除与集合2相同的元素

# set1.union(set2)将集合1和集合2组合。返回新集合,1和2不变

# 统计集合元素数量,len()

# 遍历
# 不支持下标索引,不支持while,但支持for循环
my_set = {1, 2, 3}
for ele in my_set:
    print(ele, end=",")

python dict

python中的dict底层是用哈希表实现的,类似unordered_map
为一个键值对应一个值

"""
字典:字->含义  key->value  
使用花括号,存储元素是键值对
"""
my_dict = {"博丽灵梦": "th1", "雾雨魔理沙": "th2", "爱莲": "th3"}
# 定义空字典
my_dict2 = {}
my_dict2 = dict()
# 定义重复key字典
# 会被之后定义的元素覆盖

# 无序,没有下标索引
# 使用[key]
print(my_dict["博丽灵梦"])

# 新增元素
# 语法:
# 字典[key] = value,字典被修改,新增了元素

# 更新元素
# 语法:
# 字典[key] = value, 字典被修改,元素被更新

# 删除元素pop(key)返回key对应的value并删掉

# 清空元素clear

# 获取全部的key, dict.keys()->列表

# 遍历字典,
# 通过获取全部的key来for循环key
# 直接对字典进行for循环 for key in my_dict:

# 统计字典元素数量len()

# example

python 数据容器

# 这里是数据容器通用的方法

# len元素个数(键值对也是一个元素)


# max 最大元素(字典,最大value对应的key)
# min 最小元素

# 类型转换
# 容器转列表
my_list = [1, 2, 3, 4, 5]
my_turple = (1, 2, 3, 4, 5)
my_string = "12345"
my_set = {1, 2, 3, 4, 5}
my_dict = {"key1": 1, "key2": 2, "key3": 3}  # 除了转字符串是键值对完整的形式,其他都是key字符串

print(list(my_list))
print(list(my_turple))
print(list(my_string))
print(list(my_set))
print(list(my_dict))


print(tuple(my_list))
print(tuple(my_turple))
print(tuple(my_string))
print(tuple(my_set))
print(tuple(my_dict))

print(str(my_turple))
print(str(my_list))
print(str(my_string))
print(str(my_set))
print(str(my_dict))

# set
# 无转dict方式

# 通用排序
# sorted(容器, reverse=False)
my_list = [3, 1, 2, 5, 4]
sorted_list = sorted(my_list)
print(sorted_list)  # 排序结果会变成列表对象
sorted_list = sorted(my_list, reverse=True)
print(sorted_list)

同时需要注意的是,在遍历容器用for item in items:,这里的item不能修改只能访问,如果要修改可以用
for nu in range(len(items)):间接修改items[nu]

python 序列容器

# 数据容器(序列)的切片操作
# 序列:内容连续,有序,可使用下标索引,如列表,元组,字符串
# 切片:从一个序列中,取出一个子序列
# 语法:序列[起始下标:结束下标:步长]类似正则,但是冒号.每个空都能留空(到结束)
# 步长:取元素的间隔,如果是1则为1个1个取,2则为间隔1个取
# 如果步长为负数

my_list = ["hakurei reimu", "kirisame marisa", "izamu sakuya", "hunko youmu"]
print(
    my_list[-1:0:-1]  # range(unlike dot ,  ,)
)  # ['hunko youmu', 'izamu sakuya', 'kirisame marisa'],右边逻辑上均为开区间(不包括)

# 切片操作不会影响序列本身,而是复制一个新的序列
my_str = "9876543210"
# 整体倒序,切片取出
result1 = my_str[::-1][4:7]
print(result1)
# 切片取出,然后反转
result2 = my_str[3:6][::-1]
print(result2)
# split分隔,replace
result3 = my_str.split("7")[1]
result3 = result3.split("3")[0]
print(result3[::-1])

python 模块

这个就类似于c++的多文件开发,但是与之不同,python的导包更方便,不用额外写makefile或者cmakelist

"""
什么是模块
Python 模块(Module),
是一个 Python 文件,以 .py 结尾
模块能定义函数,类和变量,模块里也能包含可执行的代码
模块的作用: python中有很多各种不同的模块,每一个模块都可以帮助我
们快速的实现一些功能,比如实现和时间相关的功能就可以使用time模块
我们可以认为一个模块就是一个工具包,每一个工具包中都有各种不同的
工具供我们使用进而实现各种不同的功能.
大白话:模块就是一个Python文件,里面有类、函数、变量等,我们可以
拿过来用(导入模块去使用)
"""

"""
模块的导入方式
模块在使用前需要先导入 导入的语法如下
[from 模块名] import [模块 类 变量 函数] [as 别名]

常用的组合形式如:
import模块名
from 模块名 import 类、变量、方法等
from 模块名import*
import 模块名as别名
from 模块名 import 功能名 as 别名

基本语法:
import 模块名
import 模块名1,模块名2
模块名.功能名()

案例:导入time模块
# 导入时间模块
import time
print("开始"
# 让程序睡眠1秒(阻塞)
time.sleep(1)
print("结束")
"""

import time

time.sleep(2)


"""
from 模块 import 功能名
功能名()
例如只用time模块的sleep方法,其他不用
"""
from time import sleep
sleep(1)

"""
设置别名
"""
from time import sleep as sl

print("xi")
sl(2)
print("gou")

"""
自定义模块和使用
了解__main__变量作用

Python中已经帮我们实现了很多的模块,不过有时候我们需要一些个性化的模块,这里就可以通过自定义模块实现,也就是自己制作一个模块
案例:新建一个Python文件,命名为my_modulel.py,并定义test函数
"""
import myexmodule

myexmodule.ex_kira("a")
myexmodule.ex_nya("hi")
# 同名from import的方法会是最后一个导入的方法


"""
__main__
在写模块时,可能会测试一些模块,
如exmodule.py中会有ex_kira("a")对模块进行测试
但我不希望在之后调用时出现
我们调用时的文件的__name__会被赋值为__main__
可用此判断是否是main文件

__all__
如果一个模块文件中有__all__ 变量,当使用from xxx import *导入时,只能导入这个列表中的元素
"""
from myexmodule import *

# 没有ex_waste 了
'''
python包
如果python模块过多,可包为一个包,帮助我们管理这些模块
什么是Python包
从物理上看,包就是一个文件夹,在该文件夹下包含了一个 __init__.py 文件,该文件夹可用于包含多个模块文件
从逻辑上看,包的本质依然是模块
'''
#创建一个包
#导入自定义的包中的模块,并使用
import my_package.my_module1
import my_package.my_module2
my_package.my_module1.info_print1()
my_package.my_module2.info_print2()

# from my_package import my_module1
# from my_package import my_module2
my_module1.info_print1()
#my_module2.info_print2()

from my_package.my_modulel import info_print1
from my_package.my_module2 import info_print2
info_print1()
info_print2()


"""
#通过__all__变量,控制import *
__init__.py 本来是空的,但是当想控制导入的模块时,__all__列表,元素是模块的名字
"""

"""
安装第三方包
pip
"""

from my_utils.file_util import *
from my_utils.str_util import *

str1 = "12345"
print(str_reserve(str1))
print(substr(str1, 1, 3))
print_file_info("./testfile2.txt")  # here is main file's path

append_to_file("./testfile2.txt", "12345")
print_file_info("./testfile2.txt")

在本次实验中用到的两个py文件

# my_utils/file_util.py
__all__ = ["str_reserve", "substr"]
def str_reserve(s):
    return s[-1::-1]

def substr(s, x, y):
    return s[x:y]
# my_utils/str_util.py
__all__ = ["print_file_info", "append_to_file"]
def print_file_info(file_name):
    f = None
    try:
        f = open(file_name, "r", encoding="utf-8")
        print(f.read())
    except:
        print("This file is not existed")
    finally:
        if not f is None:
            f.close

def append_to_file(file_name, data):
    f = open(file_name, "a", encoding="utf-8")
    f.write(data)
    f.close()
# myexmodule.py
__all__ = ["ex_kira", "ex_nya"]
def ex_kira(_char):
    print(f"kira~{_char}")

def ex_nya(_miaow):
    for cnt in range(0, 3):
        print(f"nya!{_miaow}")
# new test
if __name__ == "__main__":
    ex_kira("test:kira")
    ex_nya("test:nya")

def ex_waste():
    return 1

python 文件

# 文件的编码
# 规则集合,内容和二进制相互转化的逻辑

# 打开关闭读写
# 文件的读取
# open 函数(打开或新建)
# name,mode, encoding
# mode= 只读,写入,追加 r w a模式后加一个b表示以二进制方式
# encoding = 'UTF-8'


import time


f = open("./testfile.txt", "r", encoding="UTF-8")  # 此时的 f 是 open 函数的文件对象
# encoding 参数在函数定义中并不在第三位,因此需要按关键字传参
print(type(f))

"""
读操作方法
第一次read/readline会记录读到哪,下一次读操作会继续
文件对象.read(num)
num表示要从文件中读取的数据的长度,单位字符/字节,缺省表示读取文件中所有的数据
博丽灵梦喜欢魔理沙
博丽灵梦   喜欢魔理沙
Hakurei Reimu like Marisa
Haku rei Reimu like Marisa
"""
# print(f.read(4))
# print("-----")
# print(f.read())


"""
.readlines()
按照行的方式把整个文件中的内容进行一次性读取,并且返回一个列表,每一行的数据为一个元素(字符串)
封装到列表
"""
# content = f.readlines()  # 带最后的\n。可能要使用字符串规整strip清除空白字符(不过之后都是读二进制就是了)
# print(content)

"""
readline()
一次读取一行
"""
# line1 = f.readline()
# line2 = f.readline()
# print(f"{line1}{line2}")

"""
for循环读取文件行,line最后一个回车,for一个最后回车
"""
for line in f:
    print(f"{line}")


"""
文件关闭
f.close()
"""
f.close()

"""
with open 操作
通过在with open的语句块中对文件进行操作
可以在操作完成后自动关闭close文件,避免遗忘掉close方法
"""
with open("./testfile2.txt", "r") as f2:
    my_tuple = f2.readlines()
    print(my_tuple)
# time.sleep(20) python竟然是seconds为单位而不是mile seconds

# example
# 统计itheima数量
cnt = 0
f = open("./testfile3.txt", "r", encoding="UTF-8")
for line in f:
    cnt += line.count("itheima")
print(f"字符串itheima共出现{cnt}次")
f.close()


# 文件写入操作
# 打开文件
# 文件写入f.write("hello world")
# 内容刷新f.flush()
"""
直接调用write,内容并未真正写入文件,而是会积攒在程序的内存中,称之为缓冲区
当调用flush的时候,内容会真正写入文件
这样做是避免频繁的操作硬盘,导致效率下降(攒一堆,一次性写磁盘)
"""
f = open("./testfile4.txt", "w", encoding="utf-8")
f.write("HelloWorld")
f.flush()

# 文件的追加 a mode


"""
文件夹相关
import os
my_list = os.listdir(".") # 打印所有文件和文件夹
print(my_list)
os.chdir('myh_utils')# 切换当前工作目录
"""

python 异常

"""
当检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”
也就是我们常说的BUG
"""

"""
基本捕获
try:
    可能发生错误的代码
except:
    如果出现异常执行的代码
"""
try:
    f = open("./missingfile.txt", "r", encoding="utf-8")
except:
    print("missing file,改为w模式打开")
    f = open("./missingfile.txt", "w")

"""
捕获指定异常
try:
    可能异常代码
except 异常类型:
"""
try:
    a += 1
except NameError as e:  # 只捕获NameError异常
    print(f"name error->{e}")

"""
捕获多个类型异常
或,一旦出现则跳出
当捕获多个异常时,可以把要捕获的异常类型的名字,放到except 后,并使用元组的方式进行书写
try:
print(1/0)
except(NameError, ZeroDivisionError
print('ZeroDivision错误...')
"""

"""
捕获所有异常
"""
try:
    1 / 0
    b += 1
    open("aasd.txt", "r")
except Exception as e:
    print(type(e))
else:
    # 没有异常执行
    print("no err")
finally:
    # 有无异常都要执行
    print("finally")


# 异常的传递性
def func1():
    print("func1 开始执行")
    num = 1 / 0
    # 肯定有异常,除以0的异常
    print("func1 结束执行")


# 定义一个无异常的方法,调用上面的方法
def func2():
    print("func2 开始执行")
    func1()
    print("func2 结束执行")


# 定义一个方法,调用上面的方法
def main():
    try:
        func2()
    except Exception as e:
        print(f"出现异常了,异常的信息是: {e}")


main()

除此之外,我也经常使用raise Exception("出了什么错")来手动报错

0 评论:

发表评论