超详细 python 学习笔记,python 基础

分享 123456789987654321 ⋅ 于 2022-11-20 02:12:53 ⋅ 873 阅读

1-python基础

1.1数据类型转换

num = input('请输入数字:')
print(num)
print(type(num))  # str
print(type(int(num)))  # int

# 5. eval() -- 计算在字符串中的有效Python表达式,并返回一个对象
str2 = '1'
print(type(eval(str2)))  #<class 'int'>

1.1注释

# 单行注释

"""
第一行注释
"""

'''
注释
'''

1.2变量

my_name = 'TOM'
print(my_name)

# 定义变量:存储数据 程序员
schoolName = '我是程序员,我爱Python'
print(schoolName)

1.3数据类型

# int -- 整型
num1 = 1

# float -- 浮点型,就是小数
num2 = 1.1
print(type(num1))
print(type(num2))

# str -- 字符串,特点:数据都要带引号
a = 'hello world'
print(type(a))

# bool -- 布尔型,通常判断使用,布尔型有两个取值 True 和 False
b = True
print(type(b))

# list -- 列表
c = [10, 20, 30]
print(type(c))

# tuple -- 元组
d = (10, 20, 30)
print(type(d))

# set -- 集合
e = {10, 20, 30}
print(type(e))

# dict -- 字典 -- 键值对
f = {'name': 'TOM', 'age': 18}
print(type(f))

1.4格式化输出

age = 18
name = 'TOM'
weight = 75.5
stu_id = 1
stu_id2 = 1000

# 3. 我的体重是x公斤 -- 浮点数 %f
print('我的体重是%.3f公斤' % weight)  #末尾不足三位,填充0保留三位

# 4.1 我的学号是001
print('我的学号是%03d' % stu_id)  #前面补充0  填够3位

# 6. 我的名字是x,今年x岁了,体重x公斤,学号是x
print('我的名字是%s,今年%d岁了,体重%.2f公斤,学号是%06d' % (name, age + 1, weight, stu_id))

1.5 f格式化字符串

name = 'TOM'
age = 18

# 我的名字是x,今年x岁了
print('我的名字是%s,今年%s岁了' % (name, age))

# 语法 f'{表达式}'
print(f'我的名字是{name},今年{age}岁了')

1.6转义字符

print('hello\nPython')
print('\tabcd')

1.7print的结束符

print('hello', end="\n")
print('world', end="\t")
print('hello', end="...")
print('Python')

#hello
#world  hello...Python

1.8复合赋值运算符

# 先算复合赋值运算符右面的表达式
# d = d * 3 = 30 
d = 10
d *= 1 + 2
print(d)
#30

1.9逻辑运算符

# 1. and:   与 :  都真才真
# 2. or :  或 :  一真则真,都假才假
# 3. not:  非 :  取反

2-条件语句

2.1if语句

2.1.1if语句

age = int(input('请输入您的年龄:'))

if age < 18:
    print(f'您输入的年龄是{age}, 童工')

elif (age >= 18) and (age <= 60):
    print(f'您输入的年龄是{age}, 合法')

elif age > 60:
    print(f'您输入的年龄是{age}, 退休年龄')
else:
    print(f'测试的')

2.1.2random

import random

player = int(input('请出拳:0--石头;1--剪刀;2--布:'))
computer = random.randint(0, 2)

if ((player == 0) and (computer == 1)) or ((player == 1) and (computer == 2)) or ((player == 2) and (computer == 0)):
    print('玩家获胜,哈哈哈哈')
elif player == computer:
    print('平局,别走,再来一局')
else:
    print('电脑获胜')

2.1.3三元表达式

a = 1
b = 2

c = a if a > b else b
print(c)

3-循环

3.1while循环

#  1-100偶数累加和

i = 1
result = 0
while i <= 100:
    if i % 2 == 0:
        result += i
    i += 1

print(result)

3.2break

i = 1
while i <= 5:
    # 条件:如果吃到4 或 > 3 打印吃饱了不吃了
    if i == 4:
        print('吃饱了,不吃了')
        break
    print(f'吃了第{i}个苹果')
    i += 1

3.3continue

i = 1
while i <= 5:
    # 条件
    if i == 3:
        print('吃出一个大虫子,这个苹果不吃了')
        # 如果使用continue,在continue之前一定要修改计数器,否则进入死循环
        i += 1
        continue
    print(f'吃了第{i}个苹果')
    i += 1

3.4for循环

str1 = 'woaipppp'
for i in str1:
    if i == 'a':
        break
    print(i)

3.5for...else

str1 = 'tteeww'
for i in str1:
    if i == 'e':
        # break
        continue
    print(i)
else:
    print('循环正常结束执行的else的代码')

4-数据序列

4.1字符串

4.1.1字符串索引

str1 = 'abcdefg'
print(str1[0]) #a
print(str1[1]) #b

4.1.2字符串切片

#切片的值为取头不取尾
str1 = '012345678'
print(str1[2:5:1])  # 234
print(str1[-4:-1:1])  # 567
print(str1[-1:-4:-1])  # 876

4.1.3字符串查找

4.1.3.1_index

# 2.index()
print(mystr.index('and'))  # 12
print(mystr.index('and', 15, 30))  # 23
#print(mystr.index('ands'))  # 如果index查找子串不存在,抛异常

4.1.3.2_find

# 1. find()
print(mystr.find('and'))  # 12
print(mystr.find('and', 15, 30))  # 23
print(mystr.find('ands'))  # -1 , and字符串不存在

4.1.3.3_count

# 3.count() 统计字符串出现的次数
# 15:检索起始索引,
# 30检索结束索引
print(mystr.count('and', 15, 30))
print(mystr.count('and'))  # 3
print(mystr.count('ands'))  # 0

4.1.3.4_rfind

# 4.rfind() 返回字符串最后一次出现的位置
print(mystr.rfind('and'))  #35
#print(mystr.rfind('ands'))

4.1.3.5_rindex

# 5.rindex()
print(mystr.rindex('and'))  #35
# print(mystr.rindex('ands')) #不存在抛异常

4.1.4字符串修改

4.1.4.1_split

new_str = mystr.replace('and', 'he')
list1 = mystr.split('and', 3)
print(list1)

4.1.4.2_join

mylist = ['aa', 'bb', 'cc']
new_str = '...'.join(mylist)
print(new_str)  # 结果: aa...bb...cc

4.1.4.3_replace

mystr = "hello world and it and it and Python"
# 1. replace() 把and换成he   替换所有的
new_str = mystr.replace('and', 'he')
# new_str = mystr.replace('and', 'he', 1)
print(new_str)

4.1.4.4非重点操作

mystr = "hello world and itcast and itheima and Python"

# 1. capitalize() 字符串首字母大写
new_str = mystr.capitalize()

# 2.title(): 字符串中每个单词首字母大写
new_str = mystr.title()

# 3. upper():小写转大写
new_str = mystr.upper()

# 4. lower(): 大写转小写
new_str = mystr.lower()
print(new_str)

mystr = "   hello world and itcast and itheima and Python   "
print(mystr)
# 1. lstrip(): 删除左侧空白字符
new_str = mystr.lstrip()

# 2. rstrip(): 删除右侧空白字符
new_str = mystr.rstrip()

# 3.strip():删除两侧空白字符
new_str = mystr.strip()
print(new_str)

4.1.5字符串判断

mystr = "hello world and itcast and itheima and Python"

# 1. startswith(): 判断字符串是否以某个子串开头
print(mystr.startswith('hello'))

# 2. endswith(): 判断字符串是否以某个子串结尾
print(mystr.endswith('Python'))

# 3. isalpha(): 字母
print(mystr.isalpha())

# 4. isdigit(): 数字
print(mystr.isdigit())

# 5. isalnum() : 数字或字母或组合
print(mystr.isalnum())

mystr2 = 'abc123'
print(mystr2.isalnum())

# 6.isspace(): 空白
mystr3 = '   '
print(mystr3.isspace())

4.2列表(List)

4.2.1下标

#下标
name_list = ['TOM', 'Lily', 'ROSE']
print(name_list[1])

4.2.2索引

#index() 索引值
name_list = ['TOM', 'Lily', 'ROSE']
print(name_list.index('TOM')) #0

4.2.3_count

#count() 返回指定值在元组中出现的次数
print(name_list.count('Lily')) #1

4.2.4_len()

#len() 返回集合元素个数
print(len(name_list)) #3

4.2.5_in /notin

#in 是否存在
print('TOM' in name_list) #True

#not in 是否存在
print('TOM' not in name_list) #False

4.2.6_append

#append
name_list = ['TOM', 'Lily', 'ROSE']
name_list.append('xiaoming')
name_list.append([11, 22])
print(name_list) #['TOM', 'Lily', 'ROSE', 'xiaoming', [11, 22]]

4.2.7_extends

#extends
name_list = ['TOM', 'Lily', 'ROSE']
#把加入的数组拆开加入用extends, 否则用apppend#
name_list.extend(['xiaoming', 'xiaohong'])
print(name_list) #['TOM', 'Lily', 'ROSE', 'xiaoming', 'xiaohong']

4.2.8_insert

#insert
name_list = ['TOM', 'Lily', 'ROSE']

#name_list.insert(下标, 数据)
name_list.insert(1, 'aaa')
print(name_list)            
#['TOM', 'aaa', 'Lily', 'ROSE']

4.2.9删除数据

#pop 按照下标删除
#remove 删除某个数据
#clear 清空

4.2.9.1_del

# del 可以删除指定下标的数据
del name_list[0]
print(name_list)

4.2.9.2_pop

# 2. pop() -- 删除指定下标的数据,如果不指定下标,默认删除最后一个数据,
# pop函数返回这个被删除的数据
del_name = name_list.pop()
del_name = name_list.pop(1)
print(del_name)
print(name_list)

4.2.9.3_remove

# 3. remove(数据)
name_list.remove('ROSE')
print(name_list)

4.2.9.4_clear

# 4. clear() -- 清空
name_list.clear()
print(name_list)

4.2.9.5_修改数据

# 1. 修改指定下标的数据
name_list[0] = 'aaa'
print(name_list)

4.2.9.6_reverse

# 2. 逆序 reverse()
list1 = [1, 3, 2, 5, 4, 6]
list1.reverse()
print(list1)

4.2.9.7_sort

# 3. sort() 排序:升序(默认) 和 降序
list1.sort()
list1.sort(reverse=False)
print(list1)

4.2.9.8_copy复制列表

name_list = ['TOM', 'Lily', 'ROSE']
list1 = name_list.copy()
print(list1)
print(name_list)

4.2.9.9_while

name_list = ['TOM', 'Lily', 'ROSE']

i = 0
while i < len(name_list):
    print(name_list[i])
    i += 1

4.2.9.10_for

name_list = ['TOM', 'Lily', 'ROSE']
for i in name_list:
    print(i)

4.2.9.11_列表嵌套

name_list = [['TOM', 'Lily', 'Rose'], ['张三', '李四', '王五'], ['xiaohong', 'xiaoming', 'xiaolv']]
print(name_list[0][1]) #Lily

4.3元组

# 2. 单个数据的元组
t2 = (10,)
print(type(t2))

4.3.1_下标

# 1. 下标
print(t1[0])

4.3.2_index

# 2. index()
print(t1.index('bb')) #1

4.3.3_count

# 3. count()
print(t1.count('aa')) #1

4.3.4_len

# 4. len()
print(len(t1)) #4

4.4字典

4.4.1修改/新增

dict1 = {'name': 'TOM', 'age': 20, 'gender': '男'}

#新增
dict1['id'] = 110
print(dict1)

#修改
dict1['name'] = 'ROSE'
print(dict1)

4.4.2_删除del/clear

dict1 = {'name': 'TOM', 'age': 20, 'gender': '男'}

# del 删除字典或指定的键值对
del dict1['name']
print(dict1)

# clear()
dict1.clear()
print(dict1)

4.4.3查找数据

4.4.3.1_[key]

dict1 = {'name': 'TOM', 'age': 20, 'gender': '男'}

# 1. [key]
print(dict1['name'])  # 返回对应的值(key存在)
print(dict1['names']) #报错

4.4.3.2_get()

# 2. 函数
# 2.1 get()
print(dict1.get('names'))         # 如果key不存在,返回None
print(dict1.get('names', 'Lily')) # 如果key不存在,返回Lily

4.4.3.3_keys()

# 2.2 keys() 查找字典中所有的key,返回可迭代对象
print(dict1.keys())

4.4.3.4_values()

# 2.3 values() 查找字典中的所有的value,返回可迭代对象
print(dict1.values())

4.4.3.5_items

# 2.4 items() 查找字典中所有的键值对,返回可迭代对象,里面的数据是元组,元组数据1是字典的key,元组数据2是字典key对应的值
print(dict1.items())

4.4.3.6_for

dict1 = {'name': 'TOM', 'age': 20, 'gender': '男'}

for key in dict1.keys():
    print(key)

for value in dict1.values():
    print(value)
#获取每对 key/value 键值对    
for item in dict1.items():
    print(item)   

for key, value in dict1.items():
    print(key)
    print(value)
    print(f'{key}={value}')

4.5集合

s3 = set('abcdefg')
print(s3) #{'e', 'c', 'g', 'f', 'b', 'a', 'd'}

4.5.1_增加数据update

s1 = {10, 20}
# 1. 集合是可变类型
# add()
s1.add(100)
print(s1)

# 集合有去重功能,如果追加的数据是集合已有数据,则什么事情都不做
s1.add(100)
print(s1)

# update(): 增加的数据是序列
s1.update([10, 20, 30, 40, 50])
print(s1)

4.5.2_删除数据

4.5.2.1_remove

s1 = {10, 20, 30, 40, 50}
# remove(): 删除指定数据,如果数据不存在报错
s1.remove(10)
print(s1)

4.5.2.2_discard

s1 = {10, 20, 30, 40, 50}
# discard():删除指定数据,如果数据不存在不报错
s1.discard(10)
print(s1)

4.5.2.3_discard

s1 = {10, 20, 30, 40, 50}
# pop(): 随机删除某个数据,并返回这个数据
del_num = s1.pop()
print(del_num)
print(s1)

4.5.3_in/not in

s1 = {10, 20, 30, 40, 50}

# in 或not in 判断数据10是否存在
print(10 in s1) # True
print(10 not in s1) #False

4.6公共操作

range

for i in range(1, 10, 2):
    print(i)

for i in range(10):
    print(i)

# 1. 如果不写开始,默认从0开始
# 2. 如果不写步长,默认为1

enumerate(返回list元祖)

list1 = ['a', 'b', 'c', 'd', 'e']

# enumerate 返回结果是元组,元组第一个数据是原迭代对象的数据对应的下标,元组第二个数据是原迭代对象的数据
for i in enumerate(list1):
    print(i)

#(1, 'a')
#(2, 'b')
#(3, 'c')
#(4, 'd')
#(5, 'e')    

推导式

#需求:0, 1, 2,写入list
list1 = [i for i in range(10)]
print(list1)  #[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 需求:0-10偶数数据的列表
list3 = [i for i in range(10) if i % 2 == 0]
print(list3)

5-函数

#1.修改全局变量的值
    a = 100
    print(a)

def testB():
    # 想要修改全局变量a,值是200
    global a  # 声明a为全局变量
    a = 200
    print(a)

#2.return返回值类型
    # return后面可以直接书写 元组 列表 字典,返回多个值

#3.传参
    def user_info(name, age, gender):
        print(f'您的姓名是{name}, 年龄是{age}, 性别是{gender}')
    # 调用函数传参
    user_info('小明', gender='男', age=18)  # 关键字参数之间不分先后顺序

#4.默认值  gender='男'
    def user_info(name, age, gender='男'):
        print(f'您的姓名是{name}, 年龄是{age}, 性别是{gender}')
    user_info('TOM', 18)  # 没有为缺省参数传值,表示使用默认值  
    #您的姓名是TOM, 年龄是18, 性别是男

#5.args  接收所有位置参数,返回一个元组
    def user_info(*args):
        print(args)
    user_info('TOM')

#6. 收集所有关键字参数,返回一个字典
    def user_info(**kwargs):
        print(kwargs)
    user_info(name='TOM')

#7.lambda匿名方法
    students = [
        {'name': 'TOM', 'age': 20},
        {'name': 'ROSE', 'age': 19},
        {'name': 'Jack', 'age': 22}
    ]

    # sort(key=lambda..., reverse=bool数据)
    # 7.1 name key对应的值进行升序排序
    students.sort(key=lambda x: x['name'])
    print(students)

    # 7.2 name key对应的值进行降序排序
    students.sort(key=lambda x: x['name'], reverse=True)
    print(students)  

高阶函数

# 2. 写法二:高阶函数:f是第三个参数,用来接收将来传入的函数
def sum_num(a, b, f):
    return f(a) + f(b)

result1 = sum_num(-1, 5, abs)
print(result1)

reduce

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

# 1. 导入模块
import functools

#15
# 2. 定义功能函数
def func(a, b):
    return a + b

# 3. 调用reduce,作用:功能函数计算的结果和序列的下一个数据做累计计算
result = functools.reduce(func, list1)
print(result)

filter

list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 1. 定义功能函数:过滤序列中的偶数
def func(x):
    return x % 2 == 0

# 2. 调用filter
result = filter(func, list1)
print(result)

print(list(result))

6-文件操作

#访问模式 
#1. r 只读 (如果文件不存在,报错;不支持写入操作)
#2. w 只写, 如果文件不存在,新建文件;执行写入,会覆盖原有内容
#3. a 追加,如果文件不存在,新建文件;在原有内容基础上,追加新内容
#4.   访问模式参数可以省略, 如果省略表示访问模式为r

# r: 只读 (如果文件不存在,报错;不支持写入操作)
f = open('test1.txt', 'r')
f = open('test.txt', 'r')
f.write('aa')
f.close()

# w:只写, 如果文件不存在,新建文件;执行写入,会覆盖原有内容
f = open('1.txt', 'w')
f.write('bbffb44')
f.close()

# a:追加,如果文件不存在,新建文件;在原有内容基础上,追加新内容
f = open('2.txt', 'a')
f.write('xyz')
f.close()

# 访问模式参数可以省略, 如果省略表示访问模式为r
f = open('1.txt')
f.close()

读操作

f = open('test.txt', 'r')
#读一个字符
print(f.read(1))
#逐行读取,结果为list
print(f.readlines())
#读取一整行
print(f.readline())
f.close()

r+ w+ a+

# r+:  r没有该文件则报错; 文件指针在开头,所以能读取出来数据
f = open('test1.txt', 'r+')
f = open('test.txt', 'r+')

# w+: 没有该文件会新建文件;w特点:文件指针在开头,用新内容覆盖原内容
f = open('test1.txt', 'w+')
f = open('test.txt', 'w+')

# a+:没有该文件会新建文件;文件指针在结尾,无法读取数据(文件指针后面没有数据)
f = open('test.txt', 'a+')

con = f.read()
print(con)

f.close()

seek

"""
语法: 文件对象.seek(偏移量, 起始位置)  0开头1当前2结尾
"""

f = open('test.txt', 'a+')

# 1. 改变读取数据开始位置
f.seek(0, 0)  #偏移量为0  指针移向开头

con = f.read()
print(con)
f.close()

文件备份

# 1. 用户输入目标文件  sound.txt.mp3
old_name = input('请输入您要备份的文件名:')
print(old_name)
# print(type(old_name))

# 2. 规划备份文件的名字
# 2.1 提取后缀 -- 找到名字中的点 -- 名字和后缀分离--最右侧的点才是后缀的点 -- 字符串查找某个子串rfind
index = old_name.rindex('.')
print(index)

# 4. 思考:有效文件才备份 .txt
if index > 0:
    # 提取后缀
    postfix = old_name[index:]

# 2.2 组织新名字 = 原名字 + [备份] + 后缀
# 原名字就是字符串中的一部分子串 -- 切片[开始:结束:步长]
# print(old_name[:index])
# print(old_name[index:])
# new_name = old_name[:index] + '[备份]' + old_name[index:]
new_name = old_name[:index] + '[备份]' + postfix
print(new_name)

# 3. 备份文件写入数据(数据和原文件一样)
# 3.1 打开 原文件 和 备份文件
old_f = open(old_name, 'rb')
new_f = open(new_name, 'wb')

# 3.2 原文件读取,备份文件写入
# 如果不确定目标文件大小,循环读取写入,当读取出来的数据没有了终止循环
while True:
    con = old_f.read(1024)
    if len(con) == 0:
        # 表示读取完成了
        break

    new_f.write(con)

# 3.3 关闭文件
old_f.close()
new_f.close()

文件和文件夹操作

"""
1. 导入模块os
2. 使用模块内功能
"""
import os

# 1. rename(): 重命名
os.rename('11.txt', '11.txt')

# 2. remove(): 删除文件
os.remove('10.txt')

# 3. mkdir():创建文件夹
os.mkdir('a1a')

# 4.rmdir(): 删除文件夹
os.rmdir('aa')

# 5. getcwd(): 返回当前文件所在目录路径
print(os.getcwd())

# 6. chdir():改变目录路径
os.mkdir('aa')
# 需求:在aa里面创建bb文件夹: 1. 切换目录到aa,2创建bb
os.mkdir('bb')

os.chdir('aa')
os.mkdir('bb')

# 7. listdir(): 获取某个文件夹下所有文件,返回一个列表
print(os.listdir())
print(os.listdir('aa'))

# 8. rename() -- 重命名文件夹  bb重命名为bbbb
os.rename('bb', 'bbbb')

批量重命名

# 需求1:把code文件夹所有文件重命名 Python_xxxx
# 需求2: 删除Python_ 重命名:1, 构造条件的数据 2. 书写if
import os

# 构造条件的数据
flag = 2

# 1. 找到所有文件: 获取code文件夹的目录列表 -- listdir()
file_list = os.listdir()
print(file_list)

# 2. 构造名字
for i in file_list:
    if flag == 1:
        # new_name = 'Python_' + 原文件i
        new_name = 'Python_' + i
    elif flag == 2:
        # 删除前缀
        num = len('Python_')
        new_name = i[num:]
# 3. 重命名
    os.rename(i, new_name)

7-面向对象

7.1 _ _init__

#带参数的init
# 1. 定义类:带参数的init:宽度和高度; 实例方法:调用实例属性
class Washer():
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def print_info(self):
        print(f'洗衣机的宽度是{self.width}, 洗衣机的高度是{self.height}')

# 2. 创建对象,创建多个对象且属性值不同;调用实例方法
haier1 = Washer(10, 20)
haier1.print_info()

7.2 _ _str__

#__str__ 返回的是return的方法  打印对象返回的是return值 不是内存地址
class Washer():
    def __init__(self):
        self.width = 300

    def __str__(self):
        return '解释说明:类的说明或对象状态的说明'

haier = Washer()
print(haier)

7.3_ _del__

#删除对象时,默认调用此方法
class Washer():
    def __init__(self):
        self.width = 300

    def __del__(self):
        print('对象已经删除')
haier = Washer()

7.4继承

7.4.1多继承

# 结论:如果一个类继承多个父类,优先继承第一个父类的同名属性和方法

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.kongfuu = '[古法煎饼果子配方1]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 为了验证多继承,添加School父类
class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'
        self.kongfuf = '[黑马煎饼果子配方1]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类
class Prentice(School, Master):
    pass

# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()

print(daqiu.kongfu)

daqiu.make_cake()
daqiu.kongfuu()

7.4.2多继承

结论:如果一个类继承多个父类,优先继承第一个父类的同名属性和方法

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'
        self.kongfuu = '[古法煎饼果子配方1]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 为了验证多继承,添加School父类
class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'
        self.kongfuf = '[黑马煎饼果子配方1]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类
class Prentice(School, Master):
    pass

# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()

print(daqiu.kongfu)

daqiu.make_cake()
daqiu.kongfuu()

7.4.3子类重写父类同名属性和方法

结论:如果子类和父类拥有同名属性和方法,子类创建对象调用属性和方法的时候,调用到的是子类里面的同名属性和方法

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 为了验证多继承,添加School父类
class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类, 添加和父类同名的属性和方法
class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake() #[独创煎饼果子技术]  调用子类的方法

7.4.3_mro.py

mro方法来获取这个类的调用顺序

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类, 添加和父类同名的属性和方法
class Prentice(Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()

print(daqiu.kongfu)

daqiu.make_cake()

print(Prentice.__mro__)  #用__mro__方法来获取这个类的调用顺序
#(<class '__main__.Prentice'>, <class '__main__.Master'>, <class 'object'>) 

7.4.5子类调用父类同名属性和方法

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 为了验证多继承,添加School父类
class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类, 添加和父类同名的属性和方法
class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        # 加自己的初始化的原因:如果不加这个自己的初始化,kongfu属性值是上一次调用的init内的kongfu属性值
        self.__init__()  
        print(f'运用{self.kongfu}制作煎饼果子')

    # 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
    def make_master_cake(self):
        # 父类类名.函数()
        # 再次调用初始化的原因:这里想要调用父类的同名方法和属性,属性在init初始化位置,所以需要再次调用init
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)

# 3. 用徒弟类创建对象,调用实例属性和方法
daqiu = Prentice()
#daqiu.make_cake()

daqiu.make_master_cake()

#daqiu.make_school_cake()
#daqiu.make_cake()

7.4.6多层继承

# 1. 师父类,属性和方法
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 为了验证多继承,添加School父类
class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

# 2. 定义徒弟类,继承师父类 和 学校类, 添加和父类同名的属性和方法
class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    # 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)

# 步骤:1. 创建类Tusun, 用这个类创建对象;2. 用这个对象调用父类的属性或方法看能否成功
class Tusun(Prentice):
    pass

xiaoqiu = Tusun()

xiaoqiu.make_cake()

xiaoqiu.make_master_cake()

xiaoqiu.make_school_cake()

7.4.5Super

class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class School(Master):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

        # 2.2 无参数的super
        super().__init__()
        super().make_cake()

class Prentice(School):

    # 需求:一次性调用父类School Master的方法
    def make_old_cake(self):
        # 2.2 无参数super
        super().__init__()
        super().make_cake()

daqiu = Prentice()

daqiu.make_old_cake()

7.4.6私有权限

# 定义私有属性
self.__money = 2000000  #私有属性不能继承给子类

# 定义私有方法
def __info_print(self):
    print('这是私有方法')
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'
        # self.money = 2000000
        # 定义私有属性
        self.__money = 2000000

    # 定义私有方法
    def __info_print(self):
        print('这是私有方法')

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)

class Tusun(Prentice):
    pass

xiaoqiu = Tusun()

# print(xiaoqiu.money)
# print(xiaoqiu.__money)

xiaoqiu.__info_print()

7.4.7获取和修改私有属性

# 定义函数:获取私有属性值 get_xx
def get_money(self):
    return self.__money

# 定义函数:修改私有属性值 set_xx
def set_money(self):
    self.__money = 500
class Master(object):
    def __init__(self):
        self.kongfu = '[古法煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
    def __init__(self):
        self.kongfu = '[黑马煎饼果子配方]'

    def make_cake(self):
        print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
    def __init__(self):
        self.kongfu = '[独创煎饼果子技术]'
        # 定义私有属性
        self.__money = 2000000

    # 定义函数:获取私有属性值 get_xx
    def get_money(self):
        return self.__money

    # 定义函数:修改私有属性值 set_xx
    def set_money(self):
        self.__money = 500

    # 定义私有方法
    def __info_print(self):
        print('这是私有方法')

    def make_cake(self):
        self.__init__()
        print(f'运用{self.kongfu}制作煎饼果子')

    def make_master_cake(self):
        Master.__init__(self)
        Master.make_cake(self)

    def make_school_cake(self):
        School.__init__(self)
        School.make_cake(self)

class Tusun(Prentice):
    pass

xiaoqiu = Tusun()
print(xiaoqiu.get_money())
xiaoqiu.set_money()
print(xiaoqiu.get_money())

7.5多态

# 需求:警务人员和警犬一起工作,警犬分2种:追击敌人和追查毒品,携带不同的警犬,执行不同的工作

# 1. 定义父类,提供公共方法: 警犬 和 人
class Dog(object):
    def work(self):
        pass

# 2. 定义子类,子类重写父类方法:定义2个类表示不同的警犬
class ArmyDog(Dog):
    def work(self):
        print('追击敌人...')

class DrugDog(Dog):
    def work(self):
        print('追查毒品...')

# 定义人类
class Person(object):
    def work_with_dog(self, dog):
        dog.work()

# 3. 创建对象,调用不同的功能,传入不同的对象,观察执行的结果
ad = ArmyDog()
dd = DrugDog()

daqiu = Person()
daqiu.work_with_dog(ad)
daqiu.work_with_dog(dd)

7.6设置和访问类属性

7.7修改类属性

#通过类属性修改才可以修改属性值, 通过实例化对象修改不能修改类的值

class Dog(object):
    tooth = 10

wangcai = Dog()
xiaohei = Dog()

# 1. 类 类.类属性 = 值
# Dog.tooth = 20
# print(Dog.tooth)
# print(wangcai.tooth)
# print(xiaohei.tooth)

# 2. 测试通过对象修改类属性
wangcai.tooth = 200

print(Dog.tooth)  # 10
print(wangcai.tooth)  # 200
print(xiaohei.tooth)  # 10

7.8类方法

# 1. 定义类:私有类属性,类方法获取这个私有类属性
class Dog(object):
    __tooth = 10

    # 定义类方法
    @classmethod
    def get_tooth(cls):
        return cls.__tooth

    def get_tooth1(cls):
        return cls.__tooth
# 2. 创建对象,调用类方法
wangcai = Dog()
result = wangcai.get_tooth()
print(Dog.get_tooth())
print(result)

7.9静态方法

# 1. 定义类,定义静态方法
class Dog(object):
    @staticmethod
    def info_print():
        print('这是一个静态方法')

# 2. 创建对象
wangcai = Dog()

# 3. 调用静态方法:类 和 对象
wangcai.info_print()

Dog.info_print()

8.异常

"""
try:
    可能发生错误的代码
except:
    发生错误的时候执行的代码
"""

#捕获多个异常信息
try:
    print(1/0)
except (NameError, ZeroDivisionError) as result:
    print(result)

#捕获所有异常   
#finally   else
try:
    f = open('test100.txt', 'r')
except Exception as result:
    f = open('test100.txt', 'w')
else:
    print('我是else,当没有异常的时候执行的代码')
finally:
    f.close()

8.1异常传递

import time
try:
    f = open('test.txt')
    # 尝试循环读取内容
    try:
        while True:
            con = f.readline()
            # 如果读取完成退出循环
            if len(con) == 0:
                break

            time.sleep(3)
            print(con)
    except:
        # 在命令提示符中如果按下ctrl+C结束终止的键
        print('程序被意外终止')
except:
    print('该文件不存在')

8.2自定义异常

# __init__   __str__    继承Exception

# 1. 自定义异常类, 继承Exception, 魔法方法有init和str(设置异常描述信息)
class ShortInputError(Exception):
    def __init__(self, length, min_len):
        # 用户输入的密码长度
        self.length = length
        # 系统要求的最少长度
        self.min_len = min_len

    # 设置异常描述信息
    def __str__(self):
        return f'您输入的密码长度是{self.length}, 密码不能少于{self.min_len}'

def main():
    # 2. 抛出异常: 尝试执行:用户输入密码,如果长度小于3,抛出异常
    try:
        password = input('请输入密码:')
        if len(password) < 3:
            # 抛出异常类创建的对象
            raise ShortInputError(len(password), 3)
    # 3. 捕获该异常
    except Exception as result:
        print(result)
    else:
        print('没有异常,密码输入完成')

main()

9.模块和包

#变量名与模块名重名,变量名会覆盖模块名

9.1all列表

9.1.1my_module2模块

# 定义多个功能,把某个功能添加到__all__
__all__ = ['testA']

#__all__ 支队
def testA():
    print('testA')

def testB():
    print('testB')
from my_module2 import *
testA()

9.2包

#指定需要调用的方法,  外面在调用方法的时候才能调用到
__all__ = ['my_module1','my_module2(1)']  

9.3 dict

__dict__  转为字典
# 1. 定义类
class A(object):
    a = 0

    def __init__(self):
        self.b = 1

# 2. 创建对象
aa = A()

# 3. 调用__dict__
print(A.__dict__)

print(aa.__dict__) #打印的是当前对象的实例属性

10.多线程

10.1进程

10.1.1进程之间不共享全局变量

import multiprocessing
import time

print("xxx")
# 定义全局变量列表
g_list = list()  #=> []

# 添加数据的任务
def add_data():
    for i in range(3):
        # 因为列表是可变类型,可以在原有内存的基础上修改数据,并且修改后内存地址不变
        # 所以不需要加上global关键字
        # 加上global 表示声明要修改全局变量的内存地址
        g_list.append(i)
        print("add:", i)
        time.sleep(0.2)

    print("添加完成:", g_list)

# 读取数据的任务
def read_data():
    print("read:", g_list)

# 提示: 对应linux和mac主进程执行的代码不会进程拷贝,但是对应window系统来说主进程执行的代码也会进行拷贝执行
# 对应window来说创建子进程的代码如果进程拷贝执行相当于递归无限制进行创建子进程,会报错
# 如果解决windows递归创建子进程,通过判断是否是主模块来解决

# 理解说明: 直接执行的模块就是主模块,那么直接执行的模块里面就应该添加判断是否是主模块的代码
# 1. 防止别人导入文件的时候执行main里面的代码  防止windows系统递归创建子进程
if __name__ == '__main__':

    # 添加数据的子进程
    add_process = multiprocessing.Process(target=add_data)
    # 读取数据的子进程
    read_process = multiprocessing.Process(target=read_data)

    # 启动进程执行对应的任务
    add_process.start()
    # 当前进程(主进程)等待添加数据的进程执行完成以后代码再继续往下执行
    add_process.join()
    print("main:", g_list)
    read_process.start()

10.1.202-主进程会等待所有的子进程执行结束再结束(2种办法)

import multiprocessing
import time

def task():
    # for i in range(10):
    while True:
        print("任务执行中...")
        time.sleep(0.2)

# 判断是否是直接执行的模块, 程序入口模块

# 标准python写法,直接执行的模块,需要加上判断是否是主模块的代码
if __name__ == '__main__':

    # 创建子进程
    sub_process = multiprocessing.Process(target=task)
    # 把子进程设置成为守护主进程,以后主进程退出子进程直接销毁   第一种办法
    # sub_process.daemon = True
    sub_process.start()

    # 主进程延时0.5秒钟
    time.sleep(0.5)
    # 退出主进程之前,先让子进程进行销毁   第二种办法
    sub_process.terminate()
    print("over")

# 结论: 主进程会等待子进程执行完成以后程序再退出

# 解决办法: 主进程退出子进程销毁
# 1. 让子进程设置成为守护主进程,主进程退出子进程销毁,子进程会依赖主进程
# 2. 让主进程退出之前先让子进程销毁

10.1.3获取进程编号

#获取当前进程的编号
os.getpid()
# 获取当前进程的父进程编号
os.getppid()
# 1. 导入进程包
import multiprocessing
import time
import os

# 跳舞任务
def dance():
    # 获取当前进程(子进程)的编号
    dance_process_id = os.getpid()
    # 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
    print("dance_process_id:", dance_process_id, multiprocessing.current_process())
    # 获取当前进程的父进程编号
    dance_process_parent_id = os.getppid()
    print("dance_process的父进程编号是:", dance_process_parent_id)

    for i in range(3):
        print("跳舞中...")
        time.sleep(0.2)
        # 扩展: 根据进程编号强制杀死指定进程
        os.kill(dance_process_id, 9)

# 唱歌任务
def sing():
    # 获取当前进程(子进程)的编号
    sing_process_id = os.getpid()
    # 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
    print("sing_process_id:", sing_process_id, multiprocessing.current_process())

    # 获取当前进程的父进程编号
    sing_process_parent_id = os.getppid()
    print("sing_process的父进程编号是:", sing_process_parent_id)

    for i in range(3):
        print("唱歌中...")
        time.sleep(0.2)

# 获取当前进程(主进程)的编号
main_process_id = os.getpid()
# 获取当前进程对象,查看当前代码是由那个进程执行的 : multiprocessing.current_process()
print("main_process_id:", main_process_id, multiprocessing.current_process())

# 2. 创建子进程(自己手动创建的进程称为子进程, 在__init__.py文件中已经导入的Process类)
# 1. group: 进程组,目前只能使用None,一般不需要设置
# 2. target: 进程执行的目标任务
# 3. name: 进程名,如果不设置,默认是Process-1, ......
dance_process = multiprocessing.Process(target=dance, name="dance_process")
print("dance_process:", dance_process)
sing_process = multiprocessing.Process(target=sing, name="sing_process")
print("sing_process:", sing_process)

# 3. 启动进程执行对应的任务
dance_process.start()
sing_process.start()

10.1.4进程执行带有参数的任务

args    传入元祖
kwargs  传字典
import multiprocessing

# 显示信息的任务
def show_info(name, age):
    print(name, age)

# 创建子进程
# 以元组方式传参,元组里面的元素顺序要和函数的参数顺序保持一致
# sub_process = multiprocessing.Process(target=show_info, args=("李四", 20))
# # 启动进程
# sub_process.start()

# 以字典方式传参,字典里面的key要和函数里面的参数名保持一致,没有顺序要求
# sub_process = multiprocessing.Process(target=show_info, kwargs={"age":20, "name": '王五'})
# # 启动进程
# sub_process.start()

sub_process = multiprocessing.Process(target=show_info, args=("冯七",), kwargs={"age": 20})
# 启动进程
sub_process.start()

10.2多线程

# 1. 导入线程模块
import threading
import time

def sing():
    # 获取当前线程
    current_thread = threading.current_thread()
    print("sing:", current_thread)

    for i in range(3):
        print("唱歌中...")
        time.sleep(0.2)

def dance():
    # 获取当前线程
    current_thread = threading.current_thread()
    print("dance:", current_thread)

    for i in range(3):
        print("跳舞中...")
        time.sleep(0.2)

if __name__ == '__main__':

    # 获取当前线程
    current_thread = threading.current_thread()
    print("main_thread:", current_thread)

    # 2. 创建子线程
    sing_thread = threading.Thread(target=sing, name="sing_thread")
    dance_thread = threading.Thread(target=dance, name="dance_thread")
    # 3. 启动子线程执行对应的任务
    sing_thread.start()
    dance_thread.start()

10.2.1线程执行带有参数的任务

 %s : string类型
 %d : 数值类型
import threading

def show_info(name, age):
    print("name: %s age: %d" % (name, age))

if __name__ == '__main__':

   #argsc
    # sub_thread = threading.Thread(target=show_info, args=("李四", 20))
    # sub_thread.start()

    #kwargs
    sub_thread = threading.Thread(target=show_info, kwargs={"name": "王五", "age": 30})
    sub_thread.start()

10.2.2守护线程

import threading
import time

def task():
    while True:
        print("任务执行中...")
        time.sleep(0.3)

if __name__ == '__main__':
    # 创建子线程
    # daemon=True 表示创建的子线程守护主线程,主线程退出子线程直接销毁
    # sub_thread = threading.Thread(target=task, daemon=True)
    sub_thread = threading.Thread(target=task)
    # 把子线程设置成为守护主线程  主线程退出子线程直接销毁
    sub_thread.setDaemon(True)
    sub_thread.start()

    # 主线程延时执行1秒
    time.sleep(1)
    print("over")

10.2.3线程之间共享全局变量

#多线程操作数据,要是用线程等待
first_thread.join()
import threading
import time

# 定义全局变量
g_list = []

# 添加数据的任务
def add_data():
    for i in range(3):
        # 每循环一次把数据添加到全局变量
        g_list.append(i)
        print("add:", i)
        time.sleep(0.3)

    # 代码执行到此,说明添加数据完成
    print("添加数据完成:", g_list)

# 读取数据的任务
def read_data():
    print("read:", g_list)

if __name__ == '__main__':
    # 创建添加数据的子线程
    add_thread = threading.Thread(target=add_data)
    # 创建读取数据的子线程
    read_thread = threading.Thread(target=read_data)

    # 启动线程执行对应的任务
    add_thread.start()
    # time.sleep(1)
    # 让当前线程(主线程)等待添加数据的子线程执行完成以后代码在继续执行
    add_thread.join()
    read_thread.start()

10.2.4互斥锁

lock = threading.Lock()
lock.acquire()
lock.release()
import threading

# 全局变量
g_num = 0

# 创建互斥锁, Lock本质上是一个函数,通过调用函数可以创建一个互斥锁
lock = threading.Lock()

# 循环100万次执行的任务
def task1():
    # 上锁
    lock.acquire()
    for i in range(1000000):
        # 每循环一次给全局变量加1
        global g_num  # 表示要声明修改全局变量的内存地址
        g_num = g_num + 1  # g_num += 1

    # 代码执行到此,说明数据计算完成
    print("task1:", g_num)
    # 释放锁
    lock.release()

# 循环100万次执行的任务
def task2():
    # 上锁
    lock.acquire()
    for i in range(1000000):
        # 每循环一次给全局变量加1
        global g_num  # 表示要声明修改全局变量的内存地址
        g_num = g_num + 1  # g_num += 1

    # 代码执行到此,说明数据计算完成
    print("task2:", g_num)
    # 释放锁
    lock.release()

if __name__ == '__main__':
    # 创建两个子线程
    first_thread = threading.Thread(target=task1)
    second_thread = threading.Thread(target=task2)

    # 启动线程执行任务
    first_thread.start()

    second_thread.start()

    # 互斥锁可以保证同一时刻只有一个线程去执行代码,能够保证全局变量的数据没有问题
    # 线程等待和互斥锁都是把多任务改成单任务去执行,保证了数据的准确性,但是执行性能会下降

10.2.5死锁

return之前释放锁
# 死锁: 一直等待对方释放锁的情景叫做死锁
import threading

# 创建互斥锁
lock = threading.Lock()

# 需求: 多线程同时根据下标在列表中取值,要保证同一时刻只能有一个线程去取值
def get_value(index):
    # 上锁
    lock.acquire()
    my_list = [1, 4, 6]
    # 判断下标是否越界
    if index >= len(my_list):
        print("下标越界:", index)
        # 取值不成功,也需要释放互斥锁,不要影响后面的线程去取值
        # 锁需要在合适的地方进行释放,防止死锁
        lock.release()
        return

    # 根据下标取值
    value = my_list[index]
    print(value)
    # 释放锁
    lock.release()

if __name__ == '__main__':
    # 创建大量线程,同时执行根据下标取值的任务
    for i in range(10):
        # 每循环一次创建一个子线程
        sub_thread = threading.Thread(target=get_value, args=(i,))
        # 启动线程执行任务
        sub_thread.start()

11.TCP网络编程

11.1客户端(发送端)

import socket

if __name__ == '__main__':

    # 1. 创建tcp客户端套接字
    # AF_INET: ipv4地址类型
    # SOCK_STREAM: tcp传输协议类型
    tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 2. 和服务端套接字建立连接
    tcp_client_socket.connect(("127.0.0.1", 7070))

    send_content = "你好,我是客户端小白!!" # input()
    # 对字符串进程编码成为二进制数据
    send_data = send_content.encode("utf-8")

    # 3. 发送数据到服务端
    # windows里面的网络调试助手使用的gbk编码
    # linux 里面的络调试助手使用的utf-8编码
    tcp_client_socket.send(send_data)
    # 4. 接收服务端的数据
    # 1024:表示每次接收的最大字节数
    recv_data = tcp_client_socket.recv(1024)
    # 对二进制数据进行解码
    recv_content = recv_data.decode("utf-8")
    print("接收服务端的数据为:", recv_content)
    # 5. 关闭套接字
    tcp_client_socket.close()

11.2服务端(接收端)

import socket

if __name__ == '__main__':

    # 1. 创建tcp服务端套接字
    # AF_INET: ipv4 , AF_INET6: ipv6
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 2. 绑定端口号
    # 第一个参数表示ip地址,一般不用指定,表示本机的任何一个ip即可
    # 第二个参数表示端口号
    tcp_server_socket.bind(("", 7070))
    # 3. 设置监听
    # 128: 表示最大等待建立连接的个数
    tcp_server_socket.listen(128)
    # 4. 等待接受客户端的连接请求
    # 注意点: 每次当客户端和服务端建立连接成功都会返回一个新的套接字
    # tcp_server_socket只负责等待接收客户端的连接请求,收发消息不使用该套接字
    #返回的是元祖,所以接受的变量可以写两个
    new_client, ip_port = tcp_server_socket.accept()
    # 代码执行到此,说明客户端和服务端建立连接成功
    print("客户端的ip和端口号为:", ip_port)
    # 5. 接收客户端的数据
    # 收发消息都使用返回的这个新的套接字
    recv_data = new_client.recv(1024)
    # 对二进制数据进行解码变成字符串
    recv_content = recv_data.decode("utf-8")
    print("接收客户端的数据为:", recv_content)

    send_content = "问题正在处理中..."
    # 对字符串进行编码
    send_data = send_content.encode("utf-8")
    # 6. 发送数据到客户端
    new_client.send(send_data)
    # 关闭服务与客户端套接字,表示和客户端终止通信
    new_client.close()
    # 7. 关闭服务端套接字, 表示服务端以后不再等待接受客户端的连接请求
    tcp_server_socket.close()

11.3端口号复用

    # 设置端口号复用,表示意思: 服务端程序退出端口号立即释放
    # 1. SOL_SOCKET: 表示当前套接字
    # 2. SO_REUSEADDR: 表示复用端口号的选项
    # 3. True: 确定复用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)

11.4tcp服务端服务于多个客户端

import socket
import threading

# 处理客户端请求的任务
def handle_client_request(ip_port, new_client):
    print("客户端的ip和端口号为:", ip_port)
    # 5. 接收客户端的数据
    # 收发消息都使用返回的这个新的套接字
    # 循环接收客户端的消息
    while True:
        recv_data = new_client.recv(1024)
        if recv_data: #判断这个变量是否有值,
            print("接收的数据长度是:", len(recv_data))
            # 对二进制数据进行解码变成字符串
            recv_content = recv_data.decode("gbk")
            print("接收客户端的数据为:", recv_content, ip_port)

            send_content = "问题正在处理中..."
            # 对字符串进行编码
            send_data = send_content.encode("gbk")
            # 6. 发送数据到客户端
            new_client.send(send_data)
        else:
            # 客户端关闭连接
            print("客户端下线了:", ip_port)
            break
    # 关闭服务与客户端套接字,表示和客户端终止通信
    new_client.close()

if __name__ == '__main__':

    # 1. 创建tcp服务端套接字
    # AF_INET: ipv4 , AF_INET6: ipv6
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置端口号复用,表示意思: 服务端程序退出端口号立即释放
    # 1. SOL_SOCKET: 表示当前套接字
    # 2. SO_REUSEADDR: 表示复用端口号的选项
    # 3. True: 确定复用
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 2. 绑定端口号
    # 第一个参数表示ip地址,一般不用指定,表示本机的任何一个ip即可
    # 第二个参数表示端口号
    tcp_server_socket.bind(("", 9090))
    # 3. 设置监听
    # 128: 表示最大等待建立连接的个数
    tcp_server_socket.listen(128)
    # 4. 等待接受客户端的连接请求
    # 注意点: 每次当客户端和服务端建立连接成功都会返回一个新的套接字
    # tcp_server_socket只负责等待接收客户端的连接请求,收发消息不使用该套接字
    # 循环等待接受客户端的连接请求
    while True:

        new_client, ip_port = tcp_server_socket.accept()
        # 代码执行到此,说明客户端和服务端建立连接成功
        # 当客户端和服务端建立连接成功,创建子线程,让子线程专门负责接收客户端的消息
        sub_thread = threading.Thread(target=handle_client_request, args=(ip_port, new_client))
        # 设置守护主线程,主线程退出子线程直接销毁
        sub_thread.setDaemon(True)
        # 启动子线程执行对应的任务
        sub_thread.start()

    # 7. 关闭服务端套接字, 表示服务端以后不再等待接受客户端的连接请求
    # tcp_server_socket.close()  # 因为服务端的程序需要一直运行,所以关闭服务端套接字的代码可以省略不写

12.MYSQL

# 1. 导包
import pymysql

if __name__ == '__main__':

    conn = pymysql.connect(host="127.0.0.1",
                           port=3306,
                           user="mpf",
                           password="123456",
                           database="test",
                           charset="utf8")

    # 3. 获取游标, 目的就是要执行sql语句
    cursor = conn.cursor()
    # 注意点:对数据表完成添加、删除、修改操作,需要把修改的数据提交到数据库
    sql = "delete from student where id=1;"

    try:
        # 4. 执行sql语句
        cursor.execute(sql)
        # 删 改  需要commit操作才会执行
        conn.commit()
    except Exception as e:
        # 对修改的数据进行撤销,表示数据回滚(回到没有修改数据之前的状态)
        conn.rollback()
    finally:
        # 5. 关闭游标
        cursor.close()
        # 6. 关闭连接
        conn.close()

12.1sql注入

 sql = "insert into students(name, age, gender, c_id) values(%s, %s, %s, %s)"
# 1. 导包
import pymysql

if __name__ == '__main__':

    conn = pymysql.connect(host="localhost",
                           port=3306,
                           user="root",
                           password="mysql",
                           database="python41",
                           charset="utf8")

    # 3. 获取游标, 目的就是要执行sql语句
    cursor = conn.cursor()
    # 准备sql, 使用防止sql注入的sql语句, %s是sql语句的参数和字符串里面的%s不一样,不要加上引号
    sql = "insert into students(name, age, gender, c_id) values(%s, %s, %s, %s)"
    print(sql)

    try:
        # 4. 执行sql语句
        # 1. sql
        # 2. 执行sql语句的传入的参数,参数类型可以是元组,列表,字典
        cursor.execute(sql,["司马懿", 76, '男', 3]);
        conn.commit()
    except Exception as e:
        conn.rollback()

    finally:
        # 5. 关闭游标
        cursor.close()
        # 6. 关闭连接
        conn.close()

13.REDIS

import redis

if __name__ =='__main__':

    #2.创建redis的连接实例
    # 我们在连接/获取外界资源的时候一定要注意使用 try
    try:
        rs=redis.Redis()
    except Exception as e:
        print(e)

    #3.操作 string
    # 添加 set key value
    # result = rs.set('name','itcast')
    # print (result)

    #获取
    name = rs.get('name')
    print(name)
#encoding=utf-8
#1.导入库
from rediscluster import StrictRedisCluster

if __name__ == '__main__':

    #2.组织集群的host和端口
    nodes = [{'host':'127.0.0.1','port':'6379'}]
    try:
        #3.创建集群实例
        src=StrictRedisCluster(startup_nodes=nodes)
    except Exception as e:
        print(e)

    result = src.set('age',15)
    print(result)

15.闭包和装饰器

15.1闭包

内部函数调用了外部函数的变量, 外部函数返回内部函数

# 闭包的形成条件
# 1. 函数嵌套
# 2. 内部函数使用了外部函数的变量或者参数
# 3. 外部函数返回内部函数, 这个使用了外部函数变量的内部函数称为闭包

# 1. 函数嵌套
def func_out():
    # 外部函数
    num1 = 10

    def func_inner(num2):
        # 内部函数
        # 2. 内部函数必须使用了外部函数的变量
        result = num1 + num2
        print("结果:", result)

    # 3. 外部函数要返回内部函数,这个使用了外部函数变量的内部函数称为闭包
    return func_inner #返回内部函数

# 获取闭包对象
# 这个new_func就是闭包
# 这里的new_func = func_inner
new_func = func_out()  
# 执行闭包
new_func(1)
new_func(10)

15.1.1闭包的使用

先定义外部的函数变量,再定义内部的变量

# 外部函数接收姓名参数
def config_name(name):
    # 内部函数保存外部函数的参数,并且完成数据显示的组成
    def inner(msg):
        print(name + ":" + msg)

    print(id(inner))
    # 外部函数要返回内部函数
    return inner

# 创建tom闭包实例(对象)
tom = config_name("tom")
# 创建jerry闭包实例
jerry = config_name("jerry")
# 如果执行tom闭包,因为已经保存了name参数,那么以后在输入的时候都是,tom说:xxx
tom("哥们,过来一下,我们一起玩耍!")
jerry("打死都不去!")
tom("我不吃你")
jerry("谁相信你")   #相当于两次函数调用

15.1.2修改闭包内使用的外部函数变量

在闭包内修改外部函数的变量需要使用nonlocal关键字

# 1. 函数嵌套
def func_out():
    # 外部函数的变量
    num1 = 10

    def func_inner():
        # 在闭包内修改外部函数的变量需要使用nonlocal关键字
        nonlocal num1
        num1 = 20

        # 2.内部要使用外部函数的变量
        result = num1 + 10
        print(result)

    print("修改前的外部变量:", num1)
    func_inner()
    print("修改后的外部变量:", num1)

    # 3. 返回内部函数
    return func_inner

# 创建闭包对象
new_func = func_out()
new_func()

15.2装饰器

15.2.1装饰器

如果闭包有一个参数为函数类型,就是装饰器

# 学习装饰器目的: 对已有函数进行额外的功能扩展, 装饰器本质上一个闭包函数,也就是说他也是一个函数嵌套

# 装饰器的特点:
# 1. 不修改已有函数的源代码
# 2. 不修改已有函数的调用方式
# 3. 给以后函数添加额外的功能

# 定义装饰器
def decorator(func):  # 如果闭包函数的参数有且只有一个并且是函数类型,那么这个闭包函数称为装饰
版权声明:原创作品,允许转载,转载时务必以超链接的形式表明出处和作者信息。否则将追究法律责任。来自海汼部落-123456789987654321,http://hainiubl.com/topics/75936
回复数量: 0
    暂无评论~~
    • 请注意单词拼写,以及中英文排版,参考此页
    • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
    • 支持表情,可用Emoji的自动补全, 在输入的时候只需要 ":" 就可以自动提示了 :metal: :point_right: 表情列表 :star: :sparkles:
    • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif,教程
    • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
    Ctrl+Enter