黑马程序猿的python学习视频:https://www.bilibili.com/video/BV1qW4y1a7fU/
===============================================================
目录
1. 什么是闭包
定义双层嵌套函数,内层函数可以访问外层函数的变量
将内存函数作为外层函数的返回,此内存函数就是闭包函数
2. 闭包的优缺点
优点:
- 无需定义全局变量即可实现通过函数,持续的访问,修改某个值
- 闭包使用的变量的所用于在函数内,难以被错误的调用修改
缺点:
- 由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存。
3. nonlocal关键字的作用
在闭包函数(内部函数)中想要修改外部函数的变量值
需要用nonlocal声明这个外部变量
4. 简单闭包
# 简单闭包 def outer(logo): def inner(msg): print(f"<{logo}>{msg}<{logo}>") return inner fn1 = outer("啦啦"); fn1("新年好呀") |
<啦啦>新年好呀<啦啦> |
5. 使用nonlocal关键字修改外部函数的值
# 使用nonlocal关键字膝盖外部函数的值 def outer(num1): def inner(num2): nonlocal num1 num1+=num2 print(num1) return inner fn1 = outer(20); fn1(1) |
21 |
6. 使用闭包实现ATM小案例
# 使用闭包实现ATM小案例 def account_create(initial_amount=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 = account_create() atm(100) atm(200) atm(100,deposit=False) |
存款:+100,账户余额100 存款:+200,账户余额300 取款:-100,账户余额:200 |
7. 装饰器概念
装饰器其实也是一种闭包,其功能就是在 不破坏目标函数原有的代码和功能的前提下, 为目标函数增加新功能
8. 装饰器的一般写法
# 装饰器的一般写法(闭包) def sleep(): import random import time print("睡眠中") time.sleep(random.randint(1,5)) def outer(func): def inner(): print("我睡觉了") func() print("我起床了") return inner fn = outer(sleep) fn() |
我睡觉了 睡眠中 我起床了 |
9. 装饰器的快捷写法-语法糖
# 装饰器的快捷写法(语法糖) from numpy import outer 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() |
我睡觉了 睡眠中 我起床了 |
10. 设计模式
设计模式是一种编程套路,可以极大地方便程序的开发。
最常见,最经典的设计模式,就是我们所学习的面向对象了。
除了面向对象外,在编程中也有很多既定的套路可以方便开发,我们称之为设计模式:
- 单例模式,工厂模式
- 建造者、责任链、状态、备忘录、解释器、访问者、观察者、中介、模板、代理模式
- 等等模式
11. 单例模式
单例模式是一种常见的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场
定义:保证一个类只有一个实例,并提供一个访问他的全局访问点
适用场景:当一个类只能有一个实例,而客户可以从一个众所周知的访问点访问他时。
单例模式就是对一个类,只获取其唯一 类实例对象,持续复用他。
节省内存,节省创建对象的开销
12. 工厂模式
概念:将对象的创建由使用原生类本身创建,转换到由特定的工厂方法来创建
好处:
- 可以大批量创建对象的时候有统一的入口,易于代码的维护
- 当发生修改,仅修改工厂类的创建方法即可
- 符合现实世界的模式,即由工厂来制作产品(对象)
造人工厂实例如下
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") student=pf.get_person("s") teacher=pf.get_person("t") |
13. 什么是进程
程序在操作系统内运行,即成为一个运行进程
14. 什么是线程
进程内部可以有多个线程,程序的运行本质上就是由进程内部的线程在实际工作的
15. 什么是并行执行
多个进程同时在运行,即不同的程序同时运行,称之为:多任务并行执行
一个进程内的多个线程同时在运行,称之为:多线程并行执行
16. 演示多线程
import time import threading def sing(): while True: print("我在唱歌....") time.sleep(1) def dance(): while True: print("我在跳舞....") time.sleep(1) if __name__ =='__main__': # 创建一个唱歌的线程 sing_thread = threading.Thread(target=sing) # 创建一个跳舞的线程 dance_thread = threading.Thread(target=dance) # 让线程干活吧 sing_thread.start() dance_thread.start() |
我在唱歌.... 我在跳舞.... 我在跳舞....我在唱歌.... 我在跳舞....我在唱歌.... 我在跳舞....我在唱歌.... 我在跳舞....我在唱歌.... |
17. 多线程传参
import time import threading def sing(msg): while True: print(msg) time.sleep(1) def dance(msg): while True: 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() |
我在唱歌.. 我在跳舞.. 我在唱歌.. 我在跳舞.. 我在跳舞..我在唱歌.. |
18. Socket概念
19. Socket连接-聊天效果
服务端 | 客户端 |
D:\python\python.exe D:\qwb\workspace\myworkspace_python\01python入门\23socket服务端.py 接收到了客户端的链接,客户端的信息是:('127.0.0.1', 55012) 客户端发来的消息是:在呢 请输入你要和客户端回复的消息:我也在的 客户端发来的消息是:在干嘛呢 请输入你要和客户端回复的消息:关你屁事 客户端发来的消息是:你大爷的 滚吧 请输入你要和客户端回复的消息:exit 进程已结束,退出代码0 | D:\python\python.exe D:\qwb\workspace\myworkspace_python\01python入门\24Socket客户端.py 请输入要给服务器发送的消息:在呢 服务端回复的消息是:我也在的 请输入要给服务器发送的消息:在干嘛呢 服务端回复的消息是:关你屁事 请输入要给服务器发送的消息:你大爷的 滚吧 服务端回复的消息是: 请输入要给服务器发送的消息:exit 进程已结束,退出代码0 |
20. Socket-服务端开发
""" 演示Socket服务端开发 """ import socket # 创建Socket对象 socket_server = socket.socket() # 绑定ip地址和端口 socket_server.bind(("localhost", 8888)) # 监听端口 # listen方法内接收一个整数 传参数 ,表示接收的链接数量 socket_server.listen(1) # 等待客户端链接 # accept方法返回的是二元元组(连接对象,客户端的地址信息) conn:客户端和服务端的链接 address:客户端的地址信息 # 可以通过 变量1,变量2=socket_server.accept()的形式,直接接受二元元组的两个元素 # accept方法 ,是阻塞的方法,等待客户端的链接,如果没有链接,就卡在这一步 不向下执行了 conn,address = socket_server.accept() print(f"接收到了客户端的链接,客户端的信息是:{address}") while True: # 接收客户端消息,要使用客户端和服务端的本次链接对象,而非socket_server对象 data = conn.recv(1024).decode("UTF-8") # recv接收的参数是缓冲区大小,一般是1024即可 # recv方法的返回值是一个字节数组 也就是bytes对象,不是字符串,可以通过decode方法通过UTF-8编码,将字节数组转换为字符串对象 print(f"客户端发来的消息是:{data}") msg = input("请输入你要和客户端回复的消息:") # 如果服务端输入exit,断开连接 if(msg=='exit'): break # 发送回复消息 # encode方法可以将字符串编码为字节数组对象 conn.send(msg.encode("UTF-8")) # 关闭连接 conn.close() socket_server.close() |
21. 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")) # 接收返回消息 # 1024是缓冲区的大小 一般1024即可。同样recv是阻塞方法 recv_data = socket_client.recv(1024) print(f"服务端回复的消息是:{recv_data.decode('UTF-8')}") # 关闭连接 socket_client.close() |
22. 递归
什么是递归:在满足条件的情况下,函数自己调用自己 一种特殊编程技巧
递归需要注意什么:注意退出的条件,否则容易变成无限递归
注意返回值的传递,确保从最内层,层层传递到最外层
os模块的3个方法
os.listdir,列出指定目录下的内容
os.path.isdir,判断给定路径是否是文件夹,是的话返回True,否的话返回False
os.path.exists,判断给定路径是否存在,存在返回True,不存在返回False