Python基础学习笔记

在这里插入图片描述

参考视频和资料:2022年新版黑马程序员python教程,8天python从入门到精通,学python看这套就够了
在学习上面Python课程中整理的一些笔记,另外推荐两个学习Python的网站:Python中文指南 Python基础教程

流程控制

if 语句

在生活中经常会碰到一些因为不同条件来决定做不同的事情。比如如果明天天晴就去野营,下雨就在家看电影。 如果小明考试得了满分,奖励他一个游戏机,没有及格则要周末学习等。这类情况在python里则是用if分支语句来进行控制,此类情况的重点是要找准条件所在。

if 语句基本用法:

if 表达式:
    语句块

if … else 语句基本用法:

if 表达式:
    语句块1
else:
    语句块2

if … elif … else 语句基本用法:

if 表达式:
    语句块1
elif:
    语句块2
else:
    语句块3
#声明小明的年龄
age = int(input('请输入小明的年龄:'))

#对小明的年龄进行判断并选择不同的结果
if age>18:
    print('小明可以小量饮酒。')
else:
    print('小明禁止饮酒!')
score = int(input('请输入小明的分数(0-100):'))

if score == 100:
    print('奖励游戏机一台!')
elif score>=90:
    print('奖励自行车一台!')
elif score>=80:
    print('奖励滑冰鞋一双!')
elif score>=70:
    print('奖励习题一套!')
elif score>=60:
    print('口头鼓励!')
else:
    print('竹条炒肉一顿!')

while 循环

在生活中会一些需要重复执行的事情,比如输入银行卡的密码,连续错误三次则会锁卡。这种情形则需要用到while循环语句来解决。

while 语句的基本用法:

while 条件表达式:
    循环体
'''
用户输入用户名与密码,错误三次后锁定登录。
'''

username = '辣条'
password = '123456'

# 记录输入次数
count = 0

while count<3:
    # 循环执行代码体
    input_username = input('请输入用户名: ')
    input_pwd = input('请输入密码: ')
    if input_username==username and password==input_pwd:
        print('用户%s登录成功!'%username)
        # 如果正确,则直接结束循环
        break
    else:
        print('用户名或密码错误,请重新输入。')
        count += 1

break关键字

break关键字的作用是立即终止当前循环的执行。

# 定义外层循环的控制变量
i = 1
while i <= 9:

    # 定义内层循环的控制变量
    j = 1
    while j <= i:
        # 内层循环的print语句,不要换行,通过\t制表符进行对齐
        print(f"{j} * {i} = {j * i}\t", end='')
        j += 1

    i += 1
    print()     # print空内容,就是输出一个换行
# 定义外层循环的控制变量
i = 1
while i <= 9:
    
    # 定义内层循环的控制变量
    j = 1
    while j <= i:
        if j == i:
            # 如果两数相等则输出并换行
            print(f"{j} * {i} = {i * j}\t")
        else:
            # 如果两数不相等则输出并累加在后面
            print(f"{j} * {i} = {i * j}\t", end='')
        j += 1
    i += 1

continue关键字

continue关键字的作用是跳过当前此次循环后面的代码,直接执行下一次循环。

# 输出100以内的偶数 continue关键字
count = 0
while count<100:
    count += 1
    if count%2 != 0:
        continue
    print(count)

for 循环

除了while循环,还有一种循环结构:for循环。它与while循环的功能非常相似,但是在具体应用上还是各有不同。在明确知道循环次数时建议使用for循环,在不明确循环次数下可以使用while循环。

for 语句的基本用法:

for 迭代变量 in 对象:
    循环体
# for输出1-100
for number in range(101):
    print(number)

# for循环打印九九乘法表
# 重点:外层控制层数循环,内层控制每行内容循环
for i in range(1, 10):
    for j in range(1, i+1):
        print('%s*%s=%s'%(i, j, i*j), end=' ')
    # 控制换行
    print()

容器类型

列表(List)

  • 特点:有序、可变、可重复
  • 定义:使用方括号[]来定义一个列表,列表中的元素可以是任意类型,用逗号,分隔
  • 作用:存储多个元素,可以进行增删改查操作
  • 使用场景:适用于需要存储多个元素,并且需要对元素进行频繁操作的场景
  • 常用函数方法:
    • append():在列表末尾添加元素
    • extend():将可迭代对象中的元素添加到列表末尾
    • insert():在指定位置插入元素
    • remove():移除列表中的指定元素
    • pop():移除并返回指定位置的元素
    • index():返回指定元素的索引
    • count():返回指定元素在列表中出现的次数
    • sort():对列表进行排序
    • reverse():反转列表中的元素
  • 演示代码:
复制my_list = [1, 2, 3, 4, 5]

my_list.append(6)
print(my_list)  # [1, 2, 3, 4, 5, 6]

my_list.extend([7, 8, 9])
print(my_list)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

my_list.insert(0, 0)
print(my_list)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

my_list.remove(0)
print(my_list)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

popped_element = my_list.pop(0)
print(popped_element)  # 1
print(my_list)  # [2, 3, 4, 5, 6, 7, 8, 9]

index = my_list.index(5)
print(index)  # 3

count = my_list.count(2)
print(count)  # 1

my_list.sort()
print(my_list)  # [2, 3, 4, 5, 6, 7, 8, 9]

my_list.reverse()
print(my_list)  # [9, 8, 7, 6, 5, 4, 3, 2]

my_list = [1, 2, 3, 4, 5]

for num in my_list:
    print(num)

元组(Tuple)

  • 特点:有序、不可变、可重复
  • 定义:使用圆括号()来定义一个元组,元组中的元素可以是任意类型,用逗号,分隔
  • 作用:存储多个元素,不可修改
  • 使用场景:适用于需要存储多个元素,并且不需要对元素进行修改的场景
  • 常用函数方法:元组没有内置的修改方法,只有一些基本的操作函数,如len()index()count()
  • 演示代码:
复制my_tuple = (1, 2, 3, 4, 5)

length = len(my_tuple)
print(length)  # 5

index = my_tuple.index(3)
print(index)  # 2

count = my_tuple.count(2)
print(count)  # 1

my_tuple = (1, 2, 3, 4, 5)

for num in my_tuple:
    print(num)

集合(Set)

  • 特点:无序、可变、不重复
  • 定义:使用花括号{}来定义一个集合,集合中的元素可以是任意类型,用逗号,分隔
  • 作用:存储多个元素,去除重复元素,支持集合运算(交集、并集、差集等)
  • 使用场景:适用于需要存储多个元素,并且需要去除重复元素或进行集合运算的场景
  • 常用函数方法:
    • add():向集合中添加元素
    • update():将可迭代对象中的元素添加到集合中
    • remove():移除集合中的指定元素
    • discard():移除集合中的指定元素(如果存在)
    • pop():随机移除并返回集合中的一个元素
    • union():返回两个集合的并集
    • intersection():返回两个集合的交集
    • difference():返回两个集合的差集
    • symmetric_difference():返回两个集合的对称差集
  • 演示代码:
复制my_set = {1, 2, 3, 4, 5}

my_set.add(6)
print(my_set)  # {1, 2, 3, 4, 5, 6}

my_set.update([7, 8, 9])
print(my_set)  # {1, 2, 3, 4, 5, 6, 7, 8, 9}

my_set.remove(1)
print(my_set)  # {2, 3, 4, 5, 6, 7, 8, 9}

my_set.discard(2)
print(my_set)  # {3, 4, 5, 6, 7, 8, 9}

popped_element = my_set.pop()
print(popped_element)  # 3
print(my_set)  # {4, 5, 6, 7, 8, 9}

other_set = {4, 5, 6, 7, 8, 9, 10}

union_set = my_set.union(other_set)
print(union_set)  # {4, 5, 6, 7, 8, 9, 10}

intersection_set = my_set.intersection(other_set)
print(intersection_set)  # {4, 5, 6, 7, 8, 9}

difference_set = my_set.difference(other_set)
print(difference_set)  # set()

symmetric_difference_set = my_set.symmetric_difference(other_set)
print(symmetric_difference_set)  # {10}

my_set = {1, 2, 3, 4, 5}

for num in my_set:
    print(num)

字典(Dictionary)

  • 特点:无序、可变、键唯一
  • 定义:使用花括号{}来定义一个字典,字典中的元素是键值对,用冒号:分隔键和值,不同的键值对用逗号,分隔
  • 遍历操作:可以使用for循环来遍历字典中的键或值,或者使用items()方法来遍历键值对
  • 作用:存储键值对,通过键来访问值
  • 使用场景:适用于需要存储键值对,并且需要通过键来快速访问值的场景
  • 常用函数方法:
    • keys():返回字典中所有键的视图
    • values():返回字典中所有值的视图
    • items():返回字典中所有键值对的视图
    • get():根据键获取对应的值
    • pop():根据键移除并返回对应的值
    • popitem():随机移除并返回一个键值对
    • update():将一个字典的键值对更新到另一个字典中
  • 演示代码:
复制my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}

keys = my_dict.keys()
print(keys)  # dict_keys(['name', 'age', 'city'])

values = my_dict.values()
print(values)  # dict_values(['Alice', 25, 'New York'])

items = my_dict.items()
print(items)  # dict_items([('name', 'Alice'), ('age', 25), ('city', 'New York')])

value = my_dict.get('name')
print(value)  # Alice

popped_value = my_dict.pop('age')
print(popped_value)  # 25
print(my_dict)  # {'name': 'Alice', 'city': 'New York'}

popped_item = my_dict.popitem()
print(popped_item)  # ('city', 'New York')
print(my_dict)  # {'name': 'Alice'}

other_dict = {'age': 25, 'city': 'New York'}

my_dict.update(other_dict)
print(my_dict)  # {'name': 'Alice', 'age': 25, 'city': 'New York'}

my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}

# 遍历键
for key in my_dict:
    print(key)

# 遍历值
for value in my_dict.values():
    print(value)

# 遍历键值对
for key, value in my_dict.items():
    print(key, value)

字符串(String)

  • 特点:有序、不可变、可重复
  • 定义:使用单引号''或双引号""来定义一个字符串
  • 作用:存储文本信息
  • 使用场景:适用于需要存储和处理文本信息的场景
  • 常用函数方法:
    • len():返回字符串的长度
    • upper():将字符串转换为大写
    • lower():将字符串转换为小写
    • capitalize():将字符串的首字母转换为大写
    • title():将字符串中每个单词的首字母转换为大写
    • count():返回指定子字符串在字符串中出现的次数
    • find():返回指定子字符串在字符串中第一次出现的索引
    • replace():将字符串中的指定子字符串替换为新的字符串
    • split():将字符串按指定分隔符分割成列表
  • 演示代码:
复制my_string = "Hello, World!"

length = len(my_string)
print(length)  # 13

upper_case = my_string.upper()
print(upper_case)  # HELLO, WORLD!

lower_case = my_string.lower()
print(lower_case)  # hello, world!

capitalized = my_string.capitalize()
print(capitalized)  # Hello, world!

title_case = my_string.title()
print(title_case)  # Hello, World!

count = my_string.count('o')
print(count)  # 2

index = my_string.find('o')
print(index)  # 4

replaced = my_string.replace('World', 'Python')
print(replaced)  # Hello, Python!

splitted = my_string.split(', ')
print(splitted)  # ['Hello', 'World!']

my_string = "Hello, World!"

for char in my_string:
    print(char)

range对象

  • 特点:有序、不可变、可重复
  • 定义:使用range()函数来生成一个整数序列,可以指定起始值、结束值和步长
  • 作用:生成一个整数序列
  • 使用场景:适用于需要生成整数序列的场景
  • 常用函数方法:range对象本身并没有太多的函数方法,但可以通过转换为列表或迭代来使用
  • 演示代码:
复制my_range = range(1, 6)

my_list = list(my_range)
print(my_list)  # [1, 2, 3, 4, 5]

for num in my_range:
    print(num)

文件读写

Python 文件读写概述

Python 在文件读写操作中,会使用「内置函数」和「Pandas 库」两种方式。

先来看内置函数,包括 open()、read()、readline()、readlines()、write()、writelines()、close() 等方法,也是接下来给大家详细介绍的内容。

再看 Pandas 库,包括 read_csv()、to_csv()、read_excel()、to_excel()、read_json()、to_json() 等方法。

在使用「内置函数」的时候,思路基本上是:
1、打开文件
2、开始「读」或者「写」的操作
3、关闭文件

使用 open() 打开文件

Python 使用 open() 方法,可以根据指定文件名或标识符来打开文件。

语法格式:

file = open('filename.txt', mode = 'r', encoding="UTF-8")

获取到的 file 是一个文件对象。

Python 文件的打开模式,有如下几种,且可以组合使用:

模式描述
r以「只读」模式打开文件,如果指定文件不存在,则会报错,默认情况下文件指针指向文件开头
w以「只写」模式打开文件,如果文件不存在,则根据 filename 创建相应的文件,如果文件已存在,则会覆盖原文件
a以「追加」模式打开文件,如果文件已存在,文件指针会指向文件尾部,将内容追加在原文件后面,如果文件不存在,则会新建文件且写入内容
t以「文本文件」模式打开文件
b以「二进制」模式打开文件,主要用于打开图片、音频等非文本文件
+打开文件并允许更新(可读可写),也就是说,使用参数 w+、a+ 也是可以读入文件的,在使用的时候,需要注意区别

案例代码:
第一步,新建 hello.txt 文件,如下:

当你慢慢调整了自己看待问题的角度,
也提升了思考的深度,你竟然会发现,
你所处在的「超一线城市」其实是一个「场」。

在这个场域里头,你可以遇见无限的可能性,
每一个维度都暗含大蓝海,都有大把的机会,
你甚至运气爆棚,在某次从天而降的大机遇中,
能迅速成长为自己可能完全没法想象的人。

第二步,使用 for 循环读取文件,如下:

# 打开 hello.txt 文件,指定「只读模式」
hello = open('hello.txt', 'r')

# 使用 for 循环,将读到的内容,打印出来
num = 1
for con in hello:
    print('第 %d 行:' % num, con)
    num += 1

# 最后需要将文件关闭
hello.close()

第三步,改良,使用 read() 方法读取

# 打开 hello.txt 文件,指定「只读模式」
hello = open('hello.txt', 'r')

# 使用 read()
con = hello.read()		# 空着则默认读取全部
con = hello.read(10)	# 表示读取10个字节的数据

# 打印
print(con)

# 最后需要将文件关闭
hello.close()

拓展:

如果,我将上面的第二步和第三步,放在同一个文件中写,就会出现「文本文件指针复位」的问题。

因为我们通过 for 循环,已经让「文本文件指针」从文件的开头读到文本末尾,已经把所有内容读取,此时指针在文末位置。

如果说,再让程序执行 read() 方法,则会发现后面已经没有内容可读了,所以程序执行后,不会输出任何内容。

解决办法,调用 seek() 方法,指定偏移量为 0,来将文本文件指针「复位」即可。

你还可以通过 tell() 方法,获取文件指针的当前位置。如果此时文件指针在文末位置,获取到的其实就是整个文本的字节数,也相当是这个文件的大小了。

# 打开 hello.txt 文件,指定「只读模式」
hello = open('hello.txt', 'r')

# 使用 for 循环,将读到的内容,打印出来
num = 1
for con in hello:
    print('第 %d 行:' % num, con)
    num += 1

# 获取文件指针的位置
print(hello.tell())
    
# 将文本文件的指针,复位
hello.seek(0)

# 使用 read()
con = hello.read()
print("---- 使用 read() -----")

print(con)

# 最后需要将文件关闭
hello.close()

使用 read()、readline()、readlines() 读取数据

当文件很大的时候,单纯使用 read() 方法就很难一次性读入内存中。

可以使用 readline() 方法,从文中读取整行信息。

案例代码:

# 打开 hello.txt 文件,指定「只读模式」
hello = open('hello.txt', 'r')

# 使用 readline(),读取一行信息
con = hello.readline()
print(con)

# 最后需要将文件关闭
hello.close()

但如果想读取所有行的信息,就需要使用 readlines() 方法了

readlines() 和 read() 的区别,在于读取的「颗粒大小」,前者颗粒较大以行为单位,后者颗粒较小以字节为单位。

案例代码:

# 打开 hello.txt 文件,指定「只读模式」
hello = open('hello.txt', 'r')

# 使用 readlines(),读取全部信息
con = hello.readlines()
print(con)

# 最后需要将文件关闭
hello.close()

另外,提醒一下,读写文件的时候,经常会出现一些 IOError 错误异常,建议写在 try…finally… 异常捕获块中,养成良好的编码习惯。

比如,我们经常执行到最后,会忘记关闭文件,这就很可能会带来很多潜在的问题,可以在 finally 中,也就是程序最后会执行的部分,去关闭我们已打开的文件。

案例代码:

try:
    # 打开 hello.txt 文件,指定「只读模式」
    hello = open('helo.txt', 'r')

    # 使用 readlines(),读取全部信息
    con = hello.readlines()
    print(con)

finally:
    print('出问题了')
    # 最后需要将文件关闭
    hello.close()

使用 write()、writelines() 写入文件

还有一种更好玩儿,可以用 with…as… 语句,它天生用来防止我们忘记关闭文件。

当你引入 with 语句,它会在你访问完文件之后,根据上下文自动调用 close() 方法来关闭。

语法格式:

with expression as target :
    statements

案例代码:

with open('hello.txt') as hello :
    hello.write("I Love You")

在上面的代码中,我们在打开文件的时候,指定了 ‘w’ 模式,启动了写的操作。而且还使用了一个 write() 方法,它是用来向文件中写入指定字符串的。

在代码中操作的字符串内容,主要存储在缓冲区,我们在文件关闭前或缓冲区刷新前,可以将它写入文件。

最后,用一下 writelines() 方法,将列表中的三行数据,写到文件中。

案例代码:

# 创建一个列表
txtlist = ['Python 私教\n', 'Java 私教\n', 'C++ 私教\n']

# 写入文件
with open('hello.txt') as hello :
    hello.writelines(txtlist)

综合案例(文件备份)

"""
演示文件操作综合案例:文件备份
"""

# 打开文件得到文件对象,准备读取
fr = open("D:/bill.txt", "r", encoding="UTF-8")
# 打开文件得到文件对象,准备写入
fw = open("D:/bill.txt.bak", "w", encoding="UTF-8")
# for循环读取文件
for line in fr:
    line = line.strip()
    # 判断内容,将满足的内容写出
    if line.split(",")[4] == "测试":
        continue        # continue进入下一次循环,这一次后面的内容就跳过了
    # 将内容写出去
    fw.write(line)
    # 由于前面对内容进行了strip()的操作,所以要手动的写出换行符
    fw.write("\n")

# close2个文件对象
fr.close()
fw.close()      # 写出文件调用close()会自动flush()

异常捕获/模块/包

异常捕获

异常捕获的语法

try:
    可能会发生异常的语句
except[异常 as 别名:]
	出现异常会执行的语句
[else:]
	未出现异常时执行的语句
[finally:]
	最终都会执行的语句
# 捕获所有异常
try:
    f = open("D:/123.txt", "r", encoding="UTF-8")
except Exception as e:
    print("出现异常了")
    f = open("D:/123.txt", "w", encoding="UTF-8")
else:
    print("没有出现异常")
finally:
    print("我是finally,有没有异常我都要执行")
    f.close()

异常的传递性

"""
演示异常的传递性
"""

# 定义一个出现异常的方法
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()

导入模块

模块在使用前需要先导入

导入模块的语法

[from 模块名] import [模块 || 变量 | 函数 | *] [as 别名]

常用的组合形式

import 模块名
from 模块名 import 类、变量、方法等
from 模块名 import *
import 模块名 as 别名
from 模块名 import 功能名 as 别名

自定义模块

在Python代码文件中正常写代码即可,通过import、from关键字和导入Python内置模块一样导入即可使用

__ main __

if __ main __ == “__ main __” 表示,只有当程序是直接执行的才会进入if内部,如果是被导入的则无法进入if

def add(a, b):
    return a + b

if __name__ == '__main__':
    add(1, 2)	# 内部使用会执行, 外部导入则不会执行, 类似测试

__ all __

__ all __ 变量可以控制import * 的时候哪些功能可以被导入

__all__ = ["test_a"]

def test_a(a, b):
    return a + b	# 当被外部 * 导入时可以使用 test_a 函数

def test_b(a, b):
    return a - b	# 当被外部 * 导入时无法使用 test_b 函数, 类似private

注意事项

不同模块,同名的功能,如果都被导入,那么后导入的会覆盖先导入的(可以使用as起别名区分)

__ all __ 变量可以控制import * 的时候哪些功能可以被导入

自定义包

  • 包就是一个文件夹,里面可以存放许多Python的模块(代码文件),通过包可以将一批模块归为一类方便使用

  • 创建包会默认自动创建一个文件 __ init __,py ,通过这个文件表示这个不是普通的文件夹而是一个Python包

  • __ all __ 变量在 __ init __,py 中也可以使用,用于控制 import * 导入的内容

第三方包

安装第三方包的方式

pip install 包名称	# 比较慢, 不推荐
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple 包名称	# 使用清华大学的镜像, 推荐使用

面向对象

类的组成

类的属性,称之为:成员变量

类的行为,称之为:成员方法

注意:函数是写在类外部的,方法是定义在类内部的

类和成员方法的定义语法

class 类名称:
    成员变量
    
    def 成员方法(self, 参数列表):
        成员方法体
        
对象 = 类名称()

self 的作用

  • 表示类对象本身的意思

  • 只有通过self,成员方法才能访问类的成员变量

  • self出现在形参列表中,但是不占用参数位置,可以不用理会

构造方法

构造方法的名称:

__ init __ ,注意init前后的2个下划线符号

构造方法的作用:

  • 构造类对象的时候会自动运行
  • 构造类对象的传参会传递给构造方法,借此特性可以给成员变量赋值

注意事项:

  • 构造方法不要忘记self关键字
  • 在方法内使用成员变量需要使用self
"""
演示类的构造方法
"""
# 演示使用构造方法对成员变量进行赋值
# 构造方法的名称:__init__

class Student:

    def __init__(self, name, age ,tel):
        self.name = name
        self.age = age
        self.tel = tel
        print("Student类创建了一个类对象")

stu = Student("周杰轮", 31, "18500006666")
print(stu.name)
print(stu.age)
print(stu.tel)

魔术方法

__ init __ ,构造方法,可用于创建类对象的时候设置初始化行为

__ str __ ,用于实现类对象转字符串的行为

__ It __ ,用于2个类对象进行小于或大于比较

__ le __ ,用于2个类对象进行小于等于或大于等于比较

__ eq __ ,用于2个类对象进行相等比较

"""
演示Python内置的各类魔术方法
"""

class Student:
    def __init__(self, name, age):
        self.name = name        # 学生姓名
        self.age = age          # 学生年龄

    # __str__魔术方法
    def __str__(self):
        return f"Student类对象,name:{self.name}, age:{self.age}"

    # __lt__魔术方法
    def __lt__(self, other):
        return self.age < other.age

    # __le__魔术方法
    def __le__(self, other):
        return self.age <= other.age

    # __eq__魔术方法
    def __eq__(self, other):
        return self.age == other.age

stu1 = Student("周杰轮", 31)
stu2 = Student("林俊节", 36)
print(stu1 == stu2)

封装/继承/多态

封装

在类中提供仅供内部使用的属性和方法,而不对外开放(类对象无法使用)

封装的概念是指将现实世界事物在类中描述为属性和方法,即为封装

现实事物有部分属性和行为是不公开对使用者开放的。同样在类中描述属性和万法的时候也需要达到这个要求,就需要定义私有成员了

成员变量和成员方法的命名均以 __ 作为开头即可

类对象无法访问私有成员
类中的其它成员可以访问私有成员

"""
演示面向对象封装思想中私有成员的使用
"""

# 定义一个类,内含私有成员变量和私有成员方法
class Phone:
    __current_voltage = 0.5        # 当前手机运行电压

    def __keep_single_core(self):
        print("让CPU以单核模式运行")

    def call_by_5g(self):
        if self.__current_voltage >= 1:
            print("5g通话已开启")
        else:
            self.__keep_single_core()
            print("电量不足,无法使用5g通话,并已设置为单核运行进行省电。")

phone = Phone()
phone.call_by_5g()
继承
继承的概念

继承就是一个类,继承另外一个类的成员变量和成员方法

语法:

class(父类[, 父类2, ......, 父类N]):
    类内容体

子类构建的类对象,可以

  • 有自己的成员变量和成员方法
  • 使用父类的成员变量和成员方法
单继承和多继承

单继承:一个类继承另一个类

多继承:一个类继承多个类,按照顺序从左向右依次继承

多继承中,如果父亲有同名方法或属性,先继承的优先级要高于后继承的

pass 关键字的作用

pass 是占位语句,用于保证函数(方法)或类定义的完整性,表示无内容,空的意思

"""
演示面向对象:继承的基础语法
"""

# 演示单继承
class Phone:
    IMEI = None     # 序列号
    producer = "ITCAST" # 厂商

    def call_by_4g(self):
        print("4g通话")

class Phone2022(Phone):
    face_id = "10001"       # 面部识别ID

    def call_by_5g(self):
        print("2022年新功能:5g通话")

phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()
# 演示多继承
class NFCReader:
    nfc_type = "第五代"
    producer = "HM"

    def read_card(self):
        print("NFC读卡")

    def write_card(self):
        print("NFC写卡")

class RemoteControl:
    rc_type = "红外遥控"

    def control(self):
        print("红外遥控开启了")

class MyPhone(Phone, NFCReader, RemoteControl):
    pass

phone = MyPhone()
phone.call_by_4g()
phone.read_card()
phone.write_card()
phone.control()

print(phone.producer)

# 演示多继承下,父类成员名一致的场景
复写父类成员和调用父类成员
  • 复写表示对父类的成员属性或成员方法进行重新定义

  • 复写的语法是在子类中重新实现同名成员方法或成员属性即可

在父类中,如何调用父类成员

方式一:调用父类成员

使用成员变量:父类名.成员变量

使用成员方法:父类名.成员方法(self)

方式二:使用super()调用父类成员

使用成员变量:super().成员变量

使用成员方法:super().成员方法()

注意:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的

"""
演示面向对象:继承中
对父类成员的复写和调用
"""

class Phone:
    IMEI = None             # 序列号
    producer = "ITCAST"     # 厂商

    def call_by_5g(self):
        print("使用5g网络进行通话")

# 定义子类,复写父类成员
class MyPhone(Phone):
    producer = "ITHEIMA"        # 复写父类的成员属性

    def call_by_5g(self):
        print("开启CPU单核模式,确保通话的时候省电")
        # 方式1
        # print(f"父类的厂商是:{Phone.producer}")
        # Phone.call_by_5g(self)
        # 方式2
        print(f"父类的厂商是:{super().producer}")
        super().call_by_5g()
        print("关闭CPU单核模式,确保性能")

phone = MyPhone()
phone.call_by_5g()
print(phone.producer)

# 在子类中,调用父类成员

多态

1.什么是多态?

多态指的是,同一个行为,使用不同的对象获得不同的状态如,定义函数(方法),通过类型注解声明需要父类对象,实际传入子类对象进行工作,从而获得不同的工作状态

2.什么是抽象类(接口)

包含抽象方法的类,称之为抽象类。抽象方法是指: 没有具体实现的方法(pass)称之为抽象方法

3.抽象类的作用

多用于做顶层设计(设计标准),以便子类做具体实现。也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法并配合多态使用,获得不同的工作状态

"""
演示面向对象的多态特性以及抽象类(接口)的使用
"""

class Animal:
    def speak(self):
        pass

class Dog(Animal):
    def speak(self):
        print("汪汪汪")

class Cat(Animal):
    def speak(self):
        print("喵喵喵")

def make_noise(animal: Animal):
    """制造点噪音,需要传入Animal对象"""
    animal.speak()

# 演示多态,使用2个子类对象来调用函数
dog = Dog()
cat = Cat()

make_noise(dog)
make_noise(cat)

# 演示抽象类
class AC:
    def cool_wind(self):
        """制冷"""
        pass

    def hot_wind(self):
        """制热"""
        pass

    def swing_l_r(self):
        """左右摆风"""
        pass

class Midea_AC(AC):
    def cool_wind(self):
        print("美的空调制冷")

    def hot_wind(self):
        print("美的空调制热")

    def swing_l_r(self):
        print("美的空调左右摆风")

class GREE_AC(AC):
    def cool_wind(self):
        print("格力空调制冷")

    def hot_wind(self):
        print("格力空调制热")

    def swing_l_r(self):
        print("格力空调左右摆风")

def make_cool(ac: AC):
    ac.cool_wind()

midea_ac = Midea_AC()
gree_ac = GREE_AC()

make_cool(midea_ac)
make_cool(gree_ac)

注解

变量的类型注解

1.什么是类型注解,有什么作用?

在代码中涉及数据交互之时,对数据类型进行显式的说明,可以帮助:

  • PyCharm等开发工具对代码做类型推断协助做代码提示

  • 开发者自身做类型的备注

2.类型注解支持

  • 变量的类型注解
  • 函数(方法)的形参和返回值的类型注解

3.变量的类型注解语法

  • 语法1:变量:类型

  • 语法2:在注释中,# type: 类型

4.注意事项

类型注解只是提示性的,并非决定性的。数据类型和注解类型无法对应也不会导致错误

"""
演示变量的类型注解
"""

# 基础数据类型注解
import json
import random

# var_1: int = 10
# var_2: str = "itheima"
# var_3: bool = True
# 类对象类型注解
class Student:
    pass
stu: Student = Student()

# 基础容器类型注解
# my_list: list = [1, 2, 3]
# my_tuple: tuple = (1, 2, 3)
# my_dict: dict = {"itheima": 666}
# 容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[int, str, bool] = (1, "itheima", True)
my_dict: dict[str, int] = {"itheima": 666}
# 在注释中进行类型注解
var_1 = random.randint(1, 10)   # type: int
var_2 = json.loads('{"name": "zhangsan"}')  # type: dict[str, str]
def func():
    return 10
var_3 = func()  # type: int
# 类型注解的限制
var_4: int = "itheima"
var_5: str = 123
函数和方法类型注解

函数(方法)可以为哪里添加注解

  • 形参的类型注解
  • 返回值的类型注解

函数(方法)的类型注解语法

def 函数方法名(形参: 类型, ......, 形参: 类型) -> 返回值类型:
    pass

注意,返回值类型注解的符号使用:->

"""
演示对函数(方法)进行类型注解
"""

# 对形参进行类型注解
def add(x: int, y: int):
    return x + y

# 对返回值进行类型注解
def func(data: list) -> list:
    return data

print(func(1))
Union联合类型注解

使用Union可以定义联合类型注解

Union的使用方式:

  • 导包:from typing import Union
  • 使用:Union[类型, …, 类型]
"""
演示Union联合类型注解
"""
# 使用Union类型,必须先导包
from typing import Union

my_list: list[Union[int, str]] = [1, 2, "itheima", "itcast"]

def func(data: Union[int, str]) -> Union[int, str]:
    pass

PySpark

介绍和入门

什么是PySpark

PySpark是一个用Python编写的Spark库,用于使用Apache Spark功能运行Python应用程序,使用PySpark,我们可以在分布式集群(多个节点)上并行运行应用程序。

换句话说,PySpark是用于Apache Spark的Python API。 Apache Spark是一个分析处理引擎,用于大规模,强大的分布式数据处理和机器学习应用程序。与传统的python应用程序相比,Spark在分布式群集上处理数十亿亿万个数据的操作要快100倍。

Spark基本上是用Scala编写的,后来由于其行业适应性,它使用Py4J为Python发布了API PySpark。 Py4J是一个集成在PySpark中的Java库,它允许python动态与JVM对象交互,因此要运行PySpark,还需要将Java与Python和Apache Spark一起安装。

安装PySpark库

pip install pyspark

构建SparkContext对象作为执行入口,PySpark的功能都是从SparkContext对象作为开始

"""
演示获取PySpark的执行环境入库对象:SparkContext
并通过SparkContext对象获取当前PySpark的版本
"""

# 导包
from pyspark import SparkConf, SparkContext
# 创建SparkConf类对象
conf = SparkConf().setMaster("local[*]").setAppName("test_spark_app")

# 基于SparkConf类对象创建SparkContext对象
sc = SparkContext(conf=conf)

# 打印PySpark的运行版本
print(sc.version)

# 停止SparkContext对象的运行(停止PySpark程序)
sc.stop()

PySpark的编程模型

  • 数据输入:通过SparkContext完成数据读取
  • 数据计算:读取到的数据转换为RDD对象,调用RDD的成员方法完成计算
  • 数据输出:调用RDD的数据输出相关成员方法,将结果输出到集合、元组、字典、文本文件、数据库等

数据输入/RDD对象

RDD对象称为分布式弹性数据集,是PySpark中数据计算的载体,它可以:

  • 提供数据存储
  • 提供数据计算的各类方法
  • 数据计算的方法,返回值依旧是RDD(RDD迭代计算)

后续对数据进行各类计算操作,都是基于RDD对象进行

"""
演示通过PySpark代码加载数据,即数据输入
"""
from pyspark import SparkConf, SparkContext

conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 通过parallelize方法将Python对象加载到Spark内,成为RDD对象
rdd1 = sc.parallelize([1, 2, 3, 4, 5])	# 列表
rdd2 = sc.parallelize((1, 2, 3, 4, 5))	# 元组
rdd3 = sc.parallelize("abcdefg")		# 字符串
rdd4 = sc.parallelize({1, 2, 3, 4, 5})	# 集合
rdd5 = sc.parallelize({"key1": "value1", "key2": "value2"})	# 字典

# 如果要查看RDD里面有什么内容,需要用collect()方法
print(rdd1.collect())
print(rdd2.collect())
print(rdd3.collect())
print(rdd4.collect())
print(rdd5.collect())

# 用过textFile方法,读取文件数据加载到Spark内,成为RDD对象
rdd = sc.textFile("F:/ProjectSpace/PycharmProject/测试文件.txt")
print(rdd.collect())

sc.stop()

数据计算

对于返回值是新RDD的算子,可以通过链式调用的方式多次调用算子

map方法

map方法是将RDD的数据一条条处理(处理的逻辑基于map算子中接收的处理函数),返回新的RDD

语法:

rdd.map(func)
# func:		f:(T) -> U
# f:	表示这是一个函数(方法)
# (T) -> U 表示的是方法的定义:
#	() 表示传入参数,	(T) 表示传入1个参数,	() 表示没有传入参数
# T 是泛型的代称, 在这里表示 任意类型
# U 也是泛型代称, 在这里表示 任意类型

# -> U 表示返回值

# (T) -> U 总结起来的意思是: 这是一个方法, 这个方法接收一个参数传入, 传入的参数类型不限, 返回一个返回值, 返回值类型不限

# (A) -> A 总结起来的意思是: 这是一个方法, 这个方法接收一个参数传入, 传入的参数类型不限, 返回一个返回值, 返回值类型与传入参数类型一致

演示:

"""
演示RDD的map成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os

# 因为PySpark的原因会找不到解释器,这里需要指定一下
os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"

conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备一个RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# 通过map方法将全部数据都乘以10然后+5
# def func(data):
#     return data * 10 + 5

# rdd2 = rdd.map(func)

rdd2 = rdd.map(lambda x: x * 10).map(lambda x: x + 5)

print(rdd2.collect())
sc.stop()

注意:

  • 因为PySpark的原因会找不到解释器,需要手动指定一下
  • 可以使用定义函数然后传入函数的方式使用map方法,也可以使用lambda,同时支持链式调用

map方法总结:

  • 接收一个处理函数,可用lambda表达式快速编写
  • 对RDD内的元素逐个处理,并返回一个新的EDD

flatMap方法

flatMap方法可以对RDD执行map操作,然后进行解除嵌套操作 (福来他迈普)

解除嵌套:

# 嵌套的list
list = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

# 解除嵌套后
list = [1, 2, 3, 4, 5, 6, 7, 8, 9]

演示:

"""
演示RDD的flatMap成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os

os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备一个RDD
rdd = sc.parallelize(["itheima itcast 666", "itheima itheima itcast", "python itheima"])

# 需求,将RDD数据里面的一个个单词提取出来
rdd2 = rdd.map(lambda x: x.split(" "))	# 用map方法
print(rdd2.collect())
# [['itheima', 'itcast', '666'], ['itheima', 'itheima', 'itcast'], ['python', 'itheima']]

rdd2 = rdd.flatMap(lambda x: x.split(" "))	# 用flatMap方法
print(rdd2.collect())
# ['itheima', 'itcast', '666', 'itheima', 'itheima', 'itcast', 'python', 'itheima']

flatMap方法总结:

  • 计算逻辑与map方法一样
  • 可以比map多出解除一层嵌套的功能

reduceByKey方法

reduceByKey方法是针对KV型RDD,自动按照key分组,然后根据你提供的聚合逻辑完成**组内数据(value)**的聚合操作 (瑞丢思拜K)

语法:

rdd.reduceByKey(func)
# func: (V, V) -> V
# 接收2个传入参数(类型要一致), 返回一个返回值, 类型和传入要求一致

演示:

"""
演示RDD的reduceByKey成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os

os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备一个RDD
rdd = sc.parallelize([('张三', 99), ('张三', 88), ('张三', 99), ('李四', 98), ('李四', 66), ('李四', 0)])

# 求张三和李四两个组的成绩之和
rdd2 = rdd.reduceByKey(lambda a, b: a + b)
print(rdd2.collect())

reduceByKey方法总结:

  • 分组聚合,按照key进行分组,然后对value进行聚合操作

  • reduceByKey中接收的函数只负责聚合,分组是自动by key来分组的

综合练习-单词计数

读取文件,统计文件内单词出现的次数

"""
完成练习案例:单词计数统计
"""

# 1. 构建执行环境入口对象
from pyspark import SparkContext, SparkConf
import os

os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)
# 2. 读取数据文件
rdd = sc.textFile("F:/ProjectSpace/PycharmProject/测试文件.txt")
# 3. 取出全部单词
word_rdd = rdd.flatMap(lambda x: x.split(" "))
# 4. 将所有单词都转换成二元元组,单词为Key,value设置为1
word_with_one_rdd = word_rdd.map(lambda word: (word, 1))
# 5. 分组并求和
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)
# 6. 打印输出结果
print(result_rdd.collect())

filter方法

filter方法的功能是过滤想要的数据,函数对RDD数据进行逐个处理,得到True的保留至返回值的RDD中

语法:

rdd.filter(func)
# func: (T) -> boot		传入1个参数进来随意类型, 返回值必须是 True 或者 False
# 当返回是True的数据会被保留, False的数据会被丢弃

演示:

"""
演示RDD的filter成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os
os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备一个RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])
# 对RDD的数据进行过滤
rdd2 = rdd.filter(lambda num: num % 2 == 0)	# 条件是保留偶数, 如果不满足则被丢弃

print(rdd2.collect())
# [2, 4]

distinct方法

distinct方法是对RDD数据进行去重,返回新RDD

语法:

rdd.distinct()	# 无需传参

演示:

"""
演示RDD的distinct成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os

os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备一个RDD
rdd = sc.parallelize([1, 1, 3, 3, 5, 5, 7, 8, 8, 9, 10])
# 对RDD的数据进行去重
rdd2 = rdd.distinct()

print(rdd2.collect())

sortBy方法

sortBy方法是对RDD数据进行排序,基于指定的排序依据

语法:

rdd.sortBy(func, ascending=True, numPartitions=1)
# func: (T) -> U: 告知按照rdd中的哪个数据进行排序, 比如 lambda x: x[1] 表示按照rdd中第二列元素进行排序
# ascending: True升序 False降序
# numPartitions: 用多少分区排序

演示:

"""
演示RDD的sortBy成员方法的使用
"""
from pyspark import SparkConf, SparkContext
import os

os.environ['PYSPARK_PYTHON'] = "C:/Users/86151/venv/Scripts/python.exe"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 1. 读取数据文件
rdd = sc.textFile("F:/ProjectSpace/PycharmProject/测试文件.txt")
# 2. 取出全部单词
word_rdd = rdd.flatMap(lambda x: x.split(" "))
# 3. 将所有单词都转换成二元元组,单词为Key,value设置为1
word_with_one_rdd = word_rdd.map(lambda word: (word, 1))
# 4. 分组并求和
result_rdd = word_with_one_rdd.reduceByKey(lambda a, b: a + b)
# 5. 对结果进行排序
final_rdd = result_rdd.sortBy(lambda x: x[1], ascending=True, numPartitions=1)
print(final_rdd.collect())

数据输出

输出为Python对象

collect方法

collect方法是将RDD各个分区内的数据统一收集到Driver中,形成一个List对象

语法:

rdd.collect()
# 返回值是一个List
reduce方法

reduce方法是对RDD数据集按照传入的逻辑进行聚合,返回值等同于计算函数的返回值

语法:

rdd.reduce(func)
# func: (T, T) -> T
# 2参数传入, 1个返回值, 返回值和参数要求类型一致
take方法

take方法是取RDD的前N个元素,组合成List返回

语法:

rdd.take(3)
# 传入1个数字参数, 代表取前几个元素
count方法

count方法是计算RDD有多少条数据,返回值是一个数字

语法:

rdd.count()
# 返回1个数字, 代表有多少条数据

演示:

"""
演示将RDD输出为Python对象
"""

from pyspark import SparkConf, SparkContext
import os
import json

os.environ['PYSPARK_PYTHON'] = 'C:/Users/86151/venv/Scripts/python.exe'
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")
sc = SparkContext(conf=conf)

# 准备RDD
rdd = sc.parallelize([1, 2, 3, 4, 5])

# collect算子,输出RDD为list对象
rdd_list: list = rdd.collect()
print(rdd_list)
print(type(rdd_list))

# reduce算子,对RDD进行两两聚合
num = rdd.reduce(lambda a, b: a + b)
print(num)

# take算子,取出RDD前N个元素,组成list返回
take_list = rdd.take(3)
print(take_list)

# count,统计rdd内有多少条数据,返回值为数字
num_count = rdd.count()
print(f"rdd内有{num_count}个元素")

sc.stop()

输出为文件中

saveAsTextFile方法

saveAsTextFile可以将RDD的数据写入到文本文件中,支持本地写出,hdfs等文件系统

语法:

rdd.saveAsTextFile("输出的文件路径")

演示:

"""
演示将RDD输出到文件中
"""

from pyspark import SparkConf, SparkContext
import os
import json

# 需要配置hadoop相关依赖
os.environ['PYSPARK_PYTHON'] = 'C:/Users/86151/venv/Scripts/python.exe'
os.environ['HADOOP_HOME'] = "D:/dev/hadoop-3.0.0"
conf = SparkConf().setMaster("local[*]").setAppName("test_spark")

sc = SparkContext(conf=conf)

# 准备RDD1
rdd1 = sc.parallelize([1, 2, 3, 4, 5], numSlices=1)

# 准备RDD2
rdd2 = sc.parallelize([("Hello", 3), ("Spark", 5), ("Hi", 7)], 1)

# 准备RDD3
rdd3 = sc.parallelize([[1, 3, 5], [6, 7, 9], [11, 13, 11]], 1)

# 输出到文件中
rdd1.saveAsTextFile("D:/output1")
rdd2.saveAsTextFile("D:/output2")
rdd3.saveAsTextFile("D:/output3")

进阶知识

闭包

定义双层嵌套函数,内层函数可以访问外层函数的变量

将内存函数作为外层函数的返回,此内层函数就是闭包函数

闭包的优缺点

优点:不定义全局变量,也可以让函数持续访问和修改一个外部变量

优点:闭包函数引用的外部变量,是外层函数的内部变量。作用域封闭难以被误操作修改

缺点:由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存

nonlocal关键字的作用

在闭包函数(内部函数中)想要修改外部函数的变量值就需要用nonlocal声明这个外部变量

演示:

"""
演示Python的闭包特性
"""

# 使用闭包实现ATM小案例
def account_create(initial_amount=0):	# 默认存款为0

    def atm(num, deposit=True):		# 默认存款操作
        nonlocal initial_amount		# 声明外部变量
        if deposit:
            initial_amount += num
            print(f"存款:+{num}, 账户余额:{initial_amount}")
        else:
            initial_amount -= num
            print(f"取款:-{num}, 账户余额:{initial_amount}")

    return atm		# 返回atm函数对象

atm = account_create()	# 调用account_create函数返回atm函数对象

atm(100)	# 调用atm函数, 存款100
atm(200)	# 调用atm函数, 存款200
atm(100, deposit=False)	# 调用atm函数, 取款100

装饰器

装饰器其实也是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下为目标函数增加新功能

演示:

"""
演示装饰器的写法
"""

# 装饰器的一般写法(闭包)
# def outer(func):
#     def inner():
#         print("我睡觉了")
#         func()
#         print("我起床了")
#
#     return inner
#
#
# def sleep():
#     import random
#     import time
#     print("睡眠中......")
#     time.sleep(random.randint(1, 5))
#
#
# fn = outer(sleep)
# fn()

# 装饰器的快捷写法(语法糖)
def outer(func):
    def inner():
        print("我睡觉了")
        func()
        print("我起床了")

    return inner


@outer
def sleep():
    import random
    import time
    print("睡眠中......")
    time.sleep(random.randint(1, 5))

sleep()

单例模式

单例模式是指一个类无论获取多少次对象,都仅仅提供其唯一的类实例对象,持续复用它

演示:

"""
演示非单例模式的效果
"""

class StrTools:
    pass

s1 = StrTools()	# 第一次构建对象
s2 = StrTools()	# 第二次构建对象

print(id(s1))	# 3082632345248
print(id(s2))	# 3082632063696

str_tools.py

class StrTools:
    pass

str_tool = StrTools()	# 只构建一次对象

test.py

from str_tools import str_tool

s1 = str_tool	# 指向同一个对象
s2 = str_tool	# 指向同一个对象

print(id(s1))	# 1999118986656
print(id(s2))	# 1999118986656

工厂模式

工厂模式是将对象的创建由使用原生类本身创建转换到由特定的工厂方法来创建

演示:

"""
演示设计模式之工厂模式
"""

class Person:
    pass

class Worker(Person):
    pass

class Student(Person):
    pass

class Teacher(Person):
    pass

class PersonFactory:
    def get_person(self, p_type):
        if p_type == 'w':
            return Worker()
        elif p_type == 's':
            return Student()
        else:
            return Teacher()

pf = PersonFactory()
worker = pf.get_person('w')	# 传入w返回worker对象
stu = pf.get_person('s')	# 传入s返回student对象
teacher = pf.get_person('t')# 传入t返回teacher对象

工厂模式的优点:

  • 大批量创建对象的时候有统一的入口,易于代码维护
  • 当发生修改,仅修改工厂类的创建方法即可
  • 符合现实世界的模式,即由工厂来制作产品(对象)

多线程并行执行

进程和线程

进程:就是一个程序,运行在系统之上,那么就可以把这个程序看作一个运行进程,并分配进程ID系统管理,进程之间是内存隔离的,即不同的进程拥有各自的内存空间。

线程:线程归属与进程,一个进程可以开启多个线程,执行不同的工作,是进程的实际工作最小单位,线程之间是内存共享的,一个进程内的多个线程之间是共享这个进程所拥有的内存空间的。

操作系统中可以运行多个进程,即多任务运行

一个进程内可以运行多个进程,即多线程运行

并行执行

并行执行的意思指的是同一时间做不同的工作。

进程之间就是多任务并行执行的,操作系统可以同时运行多个程序,线程其实也是可以并行执行的:

  • 一个线程在输出:你好
  • 一个线程在输出:Hello

像这样一个程序在同一时间做两件乃至多件不同的事情,我们就称之为:多线程并行执行

多线程编程

绝大多数编程语言,都允许多线程编程,Pyhton也不例外。

Python的多线程可以通过threading模块来实现。

import threading

thread_obj = threading.Thread([group [,target [, name [, args [,kwargs]]]]])
- group: 暂时无用, 未来功能的预留参数
- target: 执行的目标任务名
- args: 以元组的方式给执行任务传参
- kwargs: 以字典方式给执行任务传参
- name: 线程名, 一般不用设置

# 启动线程, 让线程开始工作
thread_obj.start()

演示:

"""
演示多线程编程的使用
"""
import time
import threading

def sing(msg):
    print(msg)
    time.sleep(1)

def dance(msg):
    print(msg)
    time.sleep(1)

if __name__ == '__main__':
    # 创建一个唱歌的线程
    sing_thread = threading.Thread(target=sing, args=("我要唱歌 哈哈哈", ))
    # 创建一个跳舞的线程
    dance_thread = threading.Thread(target=dance, kwargs={"msg": "我在跳舞哦 啦啦啦"})

    # 启动线程
    sing_thread.start()
    dance_thread.start()

Socket服务端开发

socket是进程之间通信的一个工具,socket用于进程之间的网络数据传输,进程之间的网络通信需要socket

通信步骤:

1.创建Socket对象

2.绑定ip地址和端口

3.服务端开始监听端口

4.接收客户端连接,获得连接对象

5.客户端连接后,通过recv()方法,接收客户端发送的消息

6.通过conn(客户端当次连接对象),调用send()方法可以回复消息

7.conn(客户端当次连接对象)和服务端对象调用close()方法,关闭连接

演示:

"""
演示Socket服务端开发
"""
import socket
# 创建Socket对象
socket_server = socket.socket()
# 绑定ip地址和端口
socket_server.bind(("localhost", 8888))
# 监听端口
socket_server.listen(1)
# listen方法内接受一个整数传参数,表示接受的链接数量
# 等待客户端链接
# result: tuple = socket_server.accept()
# conn = result[0]        # 客户端和服务端的链接对象
# address = result[1]     # 客户端的地址信息
conn, address = socket_server.accept()
# accept方法返回的是二元元组(链接对象, 客户端地址信息)
# 可以通过 变量1, 变量2 = socket_server.accept()的形式,直接接受二元元组内的两个元素
# accept()方法,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一行不向下执行了

print(f"接收到了客户端的链接,客户端的信息是:{address}")

while True:
    # 接受客户端信息,要使用客户端和服务端的本次链接对象,而非socket_server对象
    data: str = conn.recv(1024).decode("UTF-8")
    # recv接受的参数是缓冲区大小,一般给1024即可
    # recv方法的返回值是一个字节数组也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象
    print(f"客户端发来的消息是:{data}")
    # 发送回复消息
    msg = input("请输入你要和客户端回复的消息:")
    if msg == 'exit':
        break
    conn.send(msg.encode("UTF-8"))
# 关闭链接
conn.close()
socket_server.close()

Socket客户端开发

演示:

"""
演示Socket客户端开发
"""
import socket
# 创建socket对象
socket_client = socket.socket()
# 连接到服务端
socket_client.connect(("localhost", 8888))

while True:
    # 发送消息
    msg = input("请输入要给服务端发送的消息:")
    if msg == 'exit':
        break
    socket_client.send(msg.encode("UTF-8"))
    # 接收返回消息
    recv_data = socket_client.recv(1024)        # 1024是缓冲区的大小,一般1024即可。 同样recv方法是阻塞的
    print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}")
# 关闭链接
socket_client.close()

正则表达式

正则表达式是一种字符串验证的规则,通过特殊的字符串组合来确立规则,用规则去匹配字符串是否满足

(^[\w-]+(.[\w-]+)*@\w-]+(.[\w-]+)+$) 可以表示为一个标准邮箱的格式

基础方法

re模块的三个主要方法

  • re.match,从头开始匹配,匹配第一个命中项

  • re.search,全局匹配,匹配第一个命中项

  • re.findall,全局匹配,匹配全部命中项

演示:

"""
演示Python正则表达式re模块的3个基础匹配方法
"""
import re

s = "python itheima python python"

# match 从头匹配
result = re.match("python", s)
print(result)
# print(result.span())
# print(result.group())

# search 搜索匹配
result = re.search("python", s)
print(result)

# findall 搜索全部匹配
result = re.findall("python", s)
print(result)

元字符匹配

单字符匹配:

字符功能
.匹配任意1个字符(除了\n) . . 匹配点本身
[]匹配[]中列举的字符
\d匹配数字,即0-9
\D匹配非数字
\s匹配空白,即空格、tab键
\S匹配非空白
\w匹配单词字符,即a-z、A-Z、0-9、_
\W匹配非单词字符
^匹配字符串开头
$匹配字符串结尾
\b匹配一个单词的边界
\B匹配非单词的边界
|匹配左右任意一个表达式
()将括号中字符作为一个分组
*匹配前一个规则的字符出现0至无数次
+匹配前一个规则的字符出现1至无数次
?匹配前一个规则的字符出现0次至1次
{m}匹配前一个规则的字符出现m次
{m,}匹配前一个规则的字符出现最少m次
{m,n}匹配前一个规则的字符出现m到n次

示例:

"""
演示Python正则表达式使用元字符进行匹配
"""
import re

s = "itheima1 @@python2 !!666 #itccast3"
# 字符串前面带上r的标记,表示字符串中转义字符无效,就是普通字符的意思
result = re.findall(r'[b-eF-Z3-9]', s)
print(result)

# 匹配账号,只能由字母和数字组成,长度限制6到10位
r = '^[0-9a-zA-Z]{6,10}$'
s = '123456_'
print(re.findall(r, s))

# 匹配QQ号,要求纯数字,长度5-11,第一位不为0
r = '^[1-9][0-9]{4,10}$'
s = '123453678'
print(re.findall(r, s))

# 匹配邮箱地址,只允许qq、163、gmail这三种邮箱地址
# abc.efg.daw@qq.com.cn.eu.qq.aa.cc
# abc@qq.com
# {内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}.{内容}@{内容}.{内容}.{内容}
r = r'(^[\w-]+(\.[\w-]+)*@(qq|163|gmail)(\.[\w-]+)+$)'
# s = 'a.b.c.d.e.f.g@qq.com.a.z.c.d.e'
s = 'a.b.c.d.e.f.g@163.com'
print(re.match(r, s))

递归

递归是指方法(函数)自己调用自己的一种特殊编程写法

演示:

"""
演示Python递归操作
需求:通过递归,找出一个指定文件夹内的全部文件

思路:写一个函数,列出文件夹内的全部内容,如果是文件就收集到list
如果是文件夹,就递归调用自己,再次判断。

"""
import os

def test_os():
    """演示os模块的3个基础方法"""
    print(os.listdir("D:/test"))        # 列出路径下的内容
    # print(os.path.isdir("D:/test/a"))   # 判断指定路径是不是文件夹
    # print(os.path.exists("D:/test"))    # 判断指定路径是否存在

def get_files_recursion_from_dir(path):
    """
    从指定的文件夹中使用递归的方式,获取全部的文件列表
    :param path: 被判断的文件夹
    :return: list,包含全部的文件,如果目录不存在或者无文件就返回一个空list
    """
    print(f"当前判断的文件夹是:{path}")
    file_list = []
    if os.path.exists(path):
        for f in os.listdir(path):
            new_path = path + "/" + f
            if os.path.isdir(new_path):
                # 进入到这里,表明这个目录是文件夹不是文件
                file_list += get_files_recursion_from_dir(new_path)
            else:
               file_list.append(new_path)
    else:
        print(f"指定的目录{path},不存在")
        return []

    return file_list

if __name__ == '__main__':
    print(get_files_recursion_from_dir("D:/test"))

def a():
    a()

SQL 操作

安装mysql

pip install pymysql

基础连接代码

"""
演示使用pymysql库进行数据插入的操作
"""
from pymysql import Connection

# 构建到MySQL数据库的链接
conn = Connection(
    host="localhost",   # 主机名(IP)
    port=3306,          # 端口
    user="root",        # 账户
    password="123456",  # 密码
    autocommit=True     # 自动提交(确认)
)

# 打印MySQL数据库软件信息
# print(conn.get_server_info())

# 执行非查询性质SQL
cursor = conn.cursor()      # 获取到游标对象
# 选择数据库
conn.select_db("world")
# 执行sql
cursor.execute("insert into student values(10002, '林俊节', 31, '男')")
# # 通过commit确认
# conn.commit()

# 关闭链接
conn.close()

JSON 格式

通过 json.dumps(data) 方法把Python数据转换成json数据,如果有中文可以加上 ensu_ascii=False 参数来保证中文可以正常转换

通过 json.loads(data) 方法把json数据转换成Python列表或字典

"""
演示JSON数据和Python字典的相互转换
"""
import json

# 准备列表,列表内每一个元素都是字典,将其转换为JSON
data = [{"name": "张大山", "age": 11}, {"name": "王大锤", "age": 13}, {"name": "赵小虎", "age": 16}]
json_str = json.dumps(data, ensure_ascii=False)
print(type(json_str))
print(json_str)

# 准备字典,将字典转换为JSON
d = {"name":"周杰轮", "addr":"台北"}
json_str = json.dumps(d, ensure_ascii=False)
print(type(json_str))
print(json_str)

# 将JSON字符串转换为Python数据类型[{k: v, k: v}, {k: v, k: v}]
s = '[{"name": "张大山", "age": 11}, {"name": "王大锤", "age": 13}, {"name": "赵小虎", "age": 16}]'
l = json.loads(s)
print(type(l))
print(l)

# 将JSON字符串转换为Python数据类型{k: v, k: v}
s = '{"name": "周杰轮", "addr": "台北"}'
d = json.loads(s)
print(type(d))
print(d)

镜像设置

配置清华大学的镜像

pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

配置阿里云镜像

pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/

恢复默认的源镜像

pip config unset global.index-url

查看pip的配置文件存放位置

pip config --list --user

在这里插入图片描述

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霁晨晨晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值