python知识点
1. 函数参数(2020-3-3)
-
args 可变参数 : 效果相当于传入参数 list或tuple,可以将list类型前面加一个 *使得list类型变为可变参数:
nums表示把nums这个list的所有元素作为可变参数传进去。 -
关键字参数:效果相当于传入参数 dict ,可以将dict类型前面加一个**使得dict类型转换为关键字参数(实则是一份拷贝)
-
命名关键字参数
-
-
参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数
-
对于任意函数,都可以通过类似
func(*args, **kw)的形式调用它 -
默认参数一定要用不可变对象,如果是可变对象,程序运行时会有逻辑错误
2. 高级特性(2020-3-4)
-
切片:(可对string实现截取的操作,例如 list[2:1]不能执行) 左闭右开
-
语法: str(start:end :step)
-
L[0:3]表示,从索引0开始取,直到索引3为止,但不包括索引3
-
L[:3]
-
L[-2:]
-
L[-2:-1] 最后一个元素(-1)不会取得
-
L[:10:2] 前10个数,每两个取一个
-
L[:] 达到复制的功能
-
-
迭代:Iterable Itertor
-
列表生成式:[ 生成元素 i * i for i in range(10) if i % 2 == 0 ]
-
for循环的前部分是一个表达式(若为if必须加else),求具x的值求值
-
for循环的后部分是一个筛选条件(if不能加else)
-
-
生成器生成方法(两种)<yield>:
-
把一个列表生成式的
[]改成(),就创建了一个generator,例如( i * i for i in range(10) if i%2 == 0)-
如果一个函数定义中包含
yield关键字,那么这个函数就不再是一个普通函数,而是一个generator
-
-
概念:
-
Iterable: 可作用于for循环
-
Iterator: 可作用与next对象,进行惰性计算,例如yield(生成器)
-
集合数据类型如 list 、 dict 、 str 等是 Iterable但不是 Iterator ,不过可以通过 iter() 函数获得一个 Iterator 对象。Python的 for 循环本质上就是通过不断调用 next() 函数实现的
-
-
map函数:接收两个参数,一个是函数,一个是 Iterable,返回一个Iterator,可用list()函数转换为list
-
reduce函数:接受两个参数,一个是函数,一个是 Iterable,该函数必须接受两个参数,reduce函数功能是将函数值继续和序列的下一个元素做累积计算,例如
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4), 返回一个值
高级函数(2020-3-5)
-
lambda函数:
f = lambda x: x * x:前,函数参数,:后,函数主体,只能一个表达式 -
filter函数:过滤函数返回为Ture的保留
-
sorted函数:可以接收一个
key函数来实现自定义的排序,例如按绝对值大小排序:-
sorted([36, 5, -12, 9, -21], key=abs)
-
-
返回函数:函数
lazy_sum中又定义了函数sum,并且,内部函数sum可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数sum时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”的程序结构拥有极大的威力 -
关于赋值语句:a, b = [1, 2] 左值数到等于右值数,否则报错
-
装饰器:
-
装饰器不带参数: 用装饰器函数封装一个函数,所以函数就收一个函数为参数,返回一个装饰后的函数wrapper(一般)
-
装饰器带参数复杂点,比不带参数的多了一层嵌套
-
-
偏函数:
functools.partial就是帮助我们创建一个偏函数-
int2 = functools.partial(int, base=2)
-
-
包和目录的区别:包相对于目录含有_init _.py文件
-
作用域:
-
_ _xxx _ _ 表示特殊变量
-
_xxx 非公开
-
面向对象编程 (2020-3-6)
-
普通的函数相比,在类中定义的函数只有一点不同,就是第一个参数永远是实例变量
self,并且,调用时,不用传递该参数。 -
__xxx表示私有数据,实际转换为:类名 +_xxx_xxx表示不希望外部引用的数据 -
“开闭”原则:
-
对扩展开放:允许新增
Animal子类; -
对修改封闭:不需要修改依赖
Animal类型的run_twice()等函数
-
-
鸭子类型:
Python的“file-like object“就是一种鸭子类型。对真正的文件对象,它有一个
read()方法,返回其内容。但是,许多对象,只要有read()方法,都被视为“file-like object“。许多函数接收的参数就是“file-like object“,你不一定要传入真正的文件对象,完全可以传入任何实现了read()方法的对象。 -
相比于type类型,总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。
-
dir:获取对象的所有属性和方法,配合
getattr()、setattr()以及hasattr() -
定制类:
-
len():使用len()函数,函数自动去调用对象的
__len__()方法 -
print():使用print函数,函数自动取调用对象的
__str__方法 -
for...in...:要定义
__iter__函数,首先返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值 -
list:要使得能像list一样下标引用,要实现对象的
__getitem__方法 -
__getattr__:引用对象中没有的属性,才会去在__getattr__中查找是否有该属性class Student(object):
def __getattr__(self, attr):
if attr=='age':
return lambda: 25
raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr) -
__call__():只需要定义一个__call__()方法,就可以直接对实例进行调用,即类中的__call__方法不用写成xx.__call__,而是直接xx()即可,能被调用的对象就是一个Callable对象,使用callable()函数可以判断某个变量是对象还是函数 -
__class__功能:__class__功能和type()函数一样,都是查看对象所在的类。
-
-
由于实例属性优先级比类属性高,因此,它会屏蔽掉类的同名属性。
-
s.name = 'Michael' # 动态给实例绑定一个属性
s.set_age = MethodType(set_age, s) # 动态给实例绑定一个方法
Student.set_score = set_score #为了给所有实例都绑定方法,可以给class绑定方法 -
限制实例的属性和方法的动态添加:
__slots__-
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称,,,使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
-
-
@property使得方法变为属性,选择使用@xxx.setter使得方法增加setter,否则为只读属性
-
使用@property使得类的属性不用增加getter和setter方法
-
以后遇到类的属性就用@property语法,视情况增加@xxx.setter
-
-
MixIn:(多重继承) 在设计类的继承关系时,通常,主线都是单一继承下来的,例如,
Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。MixIn设计要求有一个主继承,把额外功能写进另外的类里,加后缀MixIn进行标识。-
如何避免钻石继承(菱形继承)问题
-
Python 使用了一个叫“方法解析顺序(Method Resolution Order,MRO)”的东西,还用了一个叫 C3 的算法
-
-
-
type动态创建类:python遇到class Xxx类都是调用type来创建类,type也是一个类
-
class的名称;
-
继承的父类集合,注意Python支持多重继承,如果只有一个父类,别忘了tuple的单元素写法;
-
class的方法名称与函数绑定,这里我们把函数
fn绑定到方法名hello上。 -
例:Hello = type('Hello', (object,), dict(hello=fn))
-
-
metaclass:先定义metaclass,就可以创建类,最后创建实例;可以把类看成是metaclass创建出来的“实例”
-
实例化一个类的时候,具体的执行逻辑是这样的:
-
p = Person(name, age)
-
首先执行使用name和age参数来执行Person类的
__new__方法,这个__new__方法会 返回Person类的一个实例(通常情况下是使用 super(Persion, cls).__new__(cls, … …) 这样的方式) -
然后利用这个实例来调用类的i
__init__nit方法,上一步里面__new__产生的实例也就是__init__里面的的 self.
-
-
__init__和__new__最主要的区别在于:-
__init__通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。 -
__new__通常用于控制生成一个新实例的过程。它是类级别的方法。 -
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供 -
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例 -
可以将类比作制造商,
__new__方法就是前期的原材料购买环节,__init__方法就是在有原材料的基础上,加工,初始化商品环节 -
__new__实现单例模式
-
-
-
对元类的理解与注意事项 元类就是类的类,python中函数type实际上是一个元类。type就是Python在背后用来创建所有类的元类。Python中所有的东西——都是对象。这包括整数、字符串、函数以及类。它们全部都是对象,而且它们都是从一个类创建而来,这个类就是type。type就是Python的内建元类,当然了,也可以创建自己的元类。
-
Python的错误其实也是class,所有的错误类型都继承自
BaseException -
import logging
logging.basicConfig(level=logging.INFO) #debug,info,warning,error等级
s = '0'
n = int(s)
logging.info('n = %d' % n)
print(10 / n)
测试与IO编程 (2020 3 7)
-
def __setattr__(self, key, value):
self[key] = value #???
-
断言(继承unittest.TestCase):
-
self.assertEqual(abs(-1), 1) #断言函数返回的结果与1相等 -
with self.assertRaises(KeyError): #期待抛出指定类型的Error value = d['empty']
-
-
运行单元测试:
python -m unittest mydict_test -
setUp与tearDown这两个方法会分别在每调用一个测试方法的前后分别被执行 -
文档注释:(自动提取注释中的代码执行)
-
import doctest doctest.testmod()
-
-
文件操作:
-
打开文件
-
open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
-
-
操作文件
-
read(size):一次读取文件size字节内容到内存
-
readline():一次读取一行
-
readlines():一次读取所有,按行组成的list返回
-
-
关闭文件
-
-
StringIO:操作的不是文件,是str(你需要对获取到的数据进行操作,但是你并不想把数据写到本地硬盘上,这时候你就可以用stringIO)
-
BytesIO:操作的是二进制数据
-
操作文件和目录:
-
os.name os.uname() os.environ # 1.查看当前目录的绝对路径: os.path.abspath('.') '/Users/michael' # 2.在某个目录下创建一个新目录,首先把新目录的完整路径表示出来: os.path.join('/Users/michael', 'testdir') '/Users/michael/testdir' # 3.然后创建一个目录: os.mkdir('/Users/michael/testdir') # 4.删掉一个目录: os.rmdir('/Users/michael/testdir') # 5.将两个目录合并为一个 os.path.join() # 6.将目录拆分为两部分,后一部分总是最后级别的目录或文件名 os.path.split('/Users/michael/testdir/file.txt') # 7.可以直接让你得到文件扩展名,很多时候非常方便 os.path.splitext() # 8.对文件重命名: >>> os.rename('test.txt', 'test.py') # 9.删掉文件: >>> os.remove('test.py') # 10.shutil模块提供了copyfile()的函数,你还可以在shutil模块中找到很多实用函数,它们可以看做是os模块的补充。
-
-
序列化:变量从内存中变成可存储或传输的过程
-
pickle.dumps(d):把任意对象序列化为一个bytes <==> pickle.loads()
-
pickle.dump(d, f):直接把对象序列化后写入一个file-like Object <==>pickle.load()
-
通用序列化:将类实例化要传入参数
default=lambda obj: obj.__dict__,json反序列化要传入参数object_hook-
json.dumps 序列化为str <==> json.loads
-
print(json.dumps(s, default=lambda obj: obj.__dict__))
-
-
json.dump 序列化为file-like-Object <==>
-
-
对中文进行JSON序列化时,
json.dumps()提供了一个ensure_ascii参数,设置为False可以显示中文
-
-
进程线程
-
datetime:
-
#获取当前日期和时间 now = datetime.now() #获取指定日期和时间 dt = datetime(2015, 4, 19, 12, 20) #datetime转换为timestamp datetime(2015, 4, 19, 12, 20).timestamp() #timestamp转换为datetime datetime.fromtimestamp(1429417200.0) #str转换为datetime datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S') #datetime转换为str now.strftime('%a, %b %d %H:%M') #datetime加减 now + timedelta(hours=10)
-
-
collections:
-
namedtuple:
Point = namedtuple('Point', ['x', 'y']) >>> p = Point(1, 2) -
deque是为了高效实现插入(append, appendleft)和删除(pop, popleft)操作的双向列表,适合用于队列和栈
-
defaultdict:引用的Key不存在,如果希望key不存在时,返回一个默认值
dd = defaultdict(lambda: 'N/A') -
OrderedDict:
orderedDict的Key会按照插入的顺序排列,不是Key本身排序 -
ChainMap:用
ChainMap实现参数的优先级查找 -
Counter:
-
常见内建模块 (2020 3 9)
-
Base64:是一种用64个字符来表示任意二进制数据的方法。
2020 3 10
-
struct:二进制数据和bytes的转换
-
hashlib:常见算法:md5,sha1
-
hmac:使用方法如下:需要注意传入的key和message都是
bytes类型,str类型需要首先编码为bytes,两种方法,1:b'abc' 2:‘abc'.encode('utf-8')import hmac message = b'Hello, world!' key = b'secret' h = hmac.new(key, message, digestmod='MD5') # 如果消息很长,可以多次调用h.update(msg) h.hexdigest() 'fa4ee7d173f2d97ee79022d1a7355bcf'
-
itertools:返回迭代器
-
count(start, step) 1, 3, 5, 6, ...
-
cycle((4, -4)) 4, -4, 4, -4, ...
-
repeat(1) 1, 1, 1, ...
-
chain() itertools.chain('ABC', 'XYZ'): # 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'
-
groupby('AAABBBAAA', lambda c: c.upper())把迭代器中相邻的重复元素挑出来放在一起:
-
-
contextlib:实现上下文管理是通过
__enter__和__exit__这两个方法(返回自身)实现的-
@contextmanager:希望在某段代码(比如一个函数)执行前后自动执行特定代码
from contextlib import contextmanager class Query(object): def __init__(self, name): self.name = name def query(self): print('Query info about %s...' % self.name) @contextmanager def create_query(name): print('Begin') q = Query(name) yield q print('End') 代码执行顺序: with语句首先执行yield之前的语句,因此打印出<h1>; yield调用会执行with语句内部的所有语句,因此打印出hello和world; 最后执行yield之后的语句,打印出</h1>
-
-
urllib:urllib提供的功能就是利用程序去执行各种HTTP请求。如果要模拟浏览器完成特定功能,需要把请求伪装成浏览器。伪装的方法是先监控浏览器发出的请求,再根据浏览器的请求头来伪装,
User-Agent头就是用来标识浏览器的。 -
request库
-
chardet库:chardet.detect(b'Hello, world!')
-
psutil库:系统运维工具
-
virtualenv
-
1. virtualenv --no-site-packages venv #得到一个纯净的python虚拟环境 2. source venv/bin/activate #有了venv这个Python环境,可以用source进入该环境,用该命令进入一个virtualenv环境时,virtualenv会修改相关环境变量,让命令python和pip均指向当前的virtualenv环境。 3. deactivate #退出当前的venv环境
-
-
Tkinter:编写的Python代码会调用内置的
Tkinter,Tkinter封装了访问Tk的接口;Tk是一个图形库,支持多个操作系统,使用Tcl语言开发;Tk会调用操作系统提供的本地GUI接口,完成最终的GUI -
TCP编程
-
客户端编程:
-
创建一个socket
-
创建连接
-
发送数据
-
接收数据
-
关闭连接
-
-
2020 3 12
-
tcp编程
-
服务端编程:
-
创建一个socket
-
绑定套接字
-
开始监听
-
接受请求,开启新线程处理
-
接受数据
-
发送数据
-
关闭连接
-
-
-
电子邮件编程
-
SMTP编程:
-
Python对SMTP支持有
smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件。from email import encoders from email.header import Header from email.mime.text import MIMEText from email.utils import parseaddr, formataddr def _format_addr(s): name, addr = parseaddr(s) return formataddr((Header(name, 'utf-8').encode(), addr)) msg = MIMEText('Hello,send by Python...', 'plain', 'utf-8') # 输入Email地址和口令: from_addr = input('From: ') password = input('Password: ') # 输入收件人地址: to_addr = input('To: ') # 输入SMTP服务器地址: smtp_server = input('SMTP server: ') # 添加主题 msg = MIMEText('hello, send by Python...', 'plain', 'utf-8') msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr) msg['To'] = _format_addr('管理员 <%s>' % to_addr) msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode() import smtplib server = smtplib.SMTP(smtp_server, 25) # SMTP协议默认端口是25 server.set_debuglevel(1) server.login(from_addr, password) server.sendmail(from_addr, [to_addr], msg.as_string()) server.quit()-
发送HTML邮件:方法很简单,在构造
MIMEText对象时,把HTML字符串传进去,再把第二个参数由plain变为html就可以了 -
发送附件
# 邮件对象: msg = MIMEMultipart() msg['From'] = _format_addr('Python爱好者 <%s>' % from_addr) msg['To'] = _format_addr('管理员 <%s>' % to_addr) msg['Subject'] = Header('来自SMTP的问候……', 'utf-8').encode() # 邮件正文是MIMEText: msg.attach(MIMEText('send with file...', 'plain', 'utf-8')) # 添加附件就是加上一个MIMEBase,从本地读取一个图片: with open('/Users/michael/Downloads/test.png', 'rb') as f: # 设置附件的MIME和文件名,这里是png类型: mime = MIMEBase('image', 'png', filename='test.png') # 加上必要的头信息: mime.add_header('Content-Disposition', 'attachment', filename='test.png') mime.add_header('Content-ID', '<0>') mime.add_header('X-Attachment-Id', '0') # 把附件的内容读进来: mime.set_payload(f.read()) # 用Base64编码: encoders.encode_base64(mime) # 添加到MIMEMultipart: msg.attach(mime) -
-
插入图片:要把图片嵌入到邮件正文中,我们只需按照发送附件的方式,先把邮件作为附件添加进去,然后,在HTML中通过引用
src="cid:0"就可以把附件作为图片嵌入了。如果有多个图片,给它们依次编号,然后引用不同的cid:x即可。把上面代码加入
MIMEMultipart的MIMEText从plain改为html,然后在适当的位置引用图片msg.attach(MIMEText('<html><body><h1>Hello</h1>' + '<p><img src="cid:0"></p>' + '</body></html>', 'html', 'utf-8')) -
加密SMTP
-
小结:使用Python的smtplib发送邮件十分简单,只要掌握了各种邮件类型的构造方法,正确设置好邮件头,就可以顺利发出。
构造一个邮件对象就是一个
Messag对象,如果构造一个MIMEText对象,就表示一个文本邮件对象,如果构造一个MIMEImage对象,就表示一个作为附件的图片,要把多个对象组合起来,就用MIMEMultipart对象,而MIMEBase可以表示任何对象。它们的继承关系如下:Message +- MIMEBase +- MIMEMultipart +- MIMENonMultipart +- MIMEMessage +- MIMEText +- MIMEImage
-
-
POP3收取邮件:
-
Python内置一个
poplib模块,实现了POP3协议,可以直接用来收邮件 -
收取邮件分两步:
第一步:用
poplib把邮件的原始文本下载到本地;第二部:用
email解析原始文本,还原为邮件对象。 -
通过POP3下载
from email.parser import Parser from email.header import decode_header from email.utils import parseaddr import poplib # 输入邮件地址, 口令和POP3服务器地址: email = input('Email: ') password = input('Password: ') pop3_server = input('POP3 server: ') def guess_charset(msg): charset = msg.get_charset() if charset is None: content_type = msg.get('Content-Type', '').lower() pos = content_type.find('charset=') if pos >= 0: charset = content_type[pos + 8:].strip() return charset def decode_str(s): value, charset = decode_header(s)[0] if charset: value = value.decode(charset) return value def print_info(msg, indent=0): if indent == 0: for header in ['From', 'To', 'Subject']: value = msg.get(header, '') if value: if header=='Subject': value = decode_str(value) else: hdr, addr = parseaddr(value) name = decode_str(hdr) value = u'%s <%s>' % (name, addr) print('%s%s: %s' % (' ' * indent, header, value)) if (msg.is_multipart()): parts = msg.get_payload() for n, part in enumerate(parts): print('%spart %s' % (' ' * indent, n)) print('%s--------------------' % (' ' * indent)) print_info(part, indent + 1) else: content_type = msg.get_content_type() if content_type=='text/plain' or content_type=='text/html': content = msg.get_payload(decode=True) charset = guess_charset(msg) if charset: content = content.decode(charset) print('%sText: %s' % (' ' * indent, content + '...')) else: print('%sAttachment: %s' % (' ' * indent, content_type)) # 连接到POP3服务器: server = poplib.POP3(pop3_server) # 可以打开或关闭调试信息: server.set_debuglevel(1) # 可选:打印POP3服务器的欢迎文字: print(server.getwelcome().decode('utf-8')) # 身份认证: server.user(email) server.pass_(password) # stat()返回邮件数量和占用空间: print('Messages: %s. Size: %s' % server.stat()) # list()返回所有邮件的编号: resp, mails, octets = server.list() # 可以查看返回的列表类似[b'1 82923', b'2 2184', ...] print(mails) # 获取最新一封邮件, 注意索引号从1开始: index = len(mails) resp, lines, octets = server.retr(index) # lines存储了邮件的原始文本的每一行, # 可以获得整个邮件的原始文本: msg_content = b'\r\n'.join(lines).decode('utf-8') # 稍后解析出邮件: msg = Parser().parsestr(msg_content) print_info(msg) # 可以根据邮件索引号直接从服务器删除邮件: # server.dele(index) # 关闭连接: server.quit()
-
-
-
数据库:
-
JSON格式
[ {"name":"Michael","score":99}, {"name":"Bob","score":85}, {"name":"Bart","score":59}, {"name":"Lisa","score":87} ] -
SQLite:
-
使用Python的DB-API时,只要搞清楚
Connection和Cursor对象,打开后一定记得关闭,就可以放心地使用。 -
使用
Cursor对象执行insert,update,delete语句时,执行结果由rowcount返回影响的行数,就可以拿到执行结果。 -
使用
Cursor对象执行select语句时,通过featchall()可以拿到结果集。结果集是一个list,每个元素都是一个tuple,对应一行记录。 -
如果SQL语句带有参数,那么需要把参数按照位置传递给
execute()方法,有几个?占位符就必须对应几个参数,例如:cursor.execute('select * from user where name=? and pwd=?', ('abc', 'password'))
-
-
MySQL:
-
-
HTTP格式:
-
HTTP GET请求的格式:每个Header一行一个,换行符是
\r\n。GET /path HTTP/1.1 Header1: Value1 Header2: Value2 Header3: Value3
-
HTTP POST请求的格式:当遇到连续两个
\r\n时,Header部分结束,后面的数据全部是Body。POST /path HTTP/1.1 Header1: Value1 Header2: Value2 Header3: Value3 body data goes here... Body的数据类型由Content-Type头来确定,如果是网页,Body就是文本,如果是图片,Body就是图片的二进制数据。 当存在Content-Encoding时,Body数据是被压缩的,最常见的压缩方式是gzip,所以,看到Content-Encoding: gzip时,需要将Body数据先解压缩,才能得到真正的数据。压缩的目的在于减少Body的大小,加快网络传输。)
-
-
WCGI接口:
-
Web应用的本质就是:
-
浏览器发送一个HTTP请求;
-
服务器收到请求,生成一个HTML文档;
-
服务器把HTML文档作为HTTP响应的
Body发送给浏览器; -
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
-
-
WSGI接口定义非常简单,它只要求Web开发者实现一个函数,就可以响应HTTP请求:
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')])#发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()函数。start_response()函数接收两个参数,一个是HTTP响应码,一个是一组list表示的HTTP Header,每个Header用一个包含两个str的tuple表示。 return [b'<h1>Hello, web!</h1>'] #environ:一个包含所有HTTP请求信息的dict对象; #start_response:一个发送HTTP响应的函数。 -
运行WSGI服务
# server.py # 从wsgiref模块导入: from wsgiref.simple_server import make_server # 导入我们自己编写的application函数: from hello import application # 创建一个服务器,IP地址为空,端口是8000,处理函数是application: httpd = make_server('', 8000, application) print('Serving HTTP on port 8000...') # 开始监听HTTP请求: httpd.serve_forever()-
使用Web框架:其实一个Web App,就是写一个WSGI的处理函数,针对每个HTTP请求进行响应。但是如何处理HTTP请求不是问题,问题是如何处理100个不同的URL。每一个URL可以对应GET和POST请求,当然还有PUT、DELETE等请求,但是我们通常只考虑最常见的GET和POST请求。一个最简单的想法是从
environ变量里取出HTTP请求的信息,然后逐个判断:def application(environ, start_response): method = environ['REQUEST_METHOD'] path = environ['PATH_INFO'] if method=='GET' and path=='/': return handle_home(environ, start_response) if method=='POST' and path='/signin': return handle_signin(environ, start_response) ...但是这样代码可维护性极差,代码这么写没法维护的原因是因为WSGI提供的接口虽然比HTTP接口高级了不少,但和Web App的处理逻辑比,还是比较低级,我们需要在WSGI接口之上能进一步抽象,让我们专注于用一个函数处理一个URL,至于URL到函数的映射,就交给Web框架来做。
-
flask框架:
from flask import Flask from flask import request app = Flask(__name__) @app.route('/', methods=['GET', 'POST']) def home(): return '<h1>Home</h1>' @app.route('/signin', methods=['GET']) def signin_form(): return '''<form action="/signin" method="post"> <p><input name="username"></p> <p><input name="password" type="password"></p> <p><button type="submit">Sign In</button></p> </form>''' @app.route('/signin', methods=['POST']) def signin(): # 需要从request对象读取表单内容: if request.form['username']=='admin' and request.form['password']=='password': return '<h3>Hello, admin!</h3>' return '<h3>Bad username or password.</h3>' if __name__ == '__main__': app.run() -
使用模板:
-
-
异步IO:
-
协程
def consumer(): r = '' while True: n = yield r if not n: return print('[CONSUMER] Consuming %s...' % n) r = '200 OK' def produce(c): c.send(None) n = 0 while n < 5: n = n + 1 print('[PRODUCER] Producing %s...' % n) r = c.send(n) print('[PRODUCER] Consumer return: %s' % r) c.close() c = consumer() produce(c) -
asyncio:
-
2020 3 15
-
1、上传本地文件到服务器
scp /path/filename username@servername:/path/
例如scp /var/www/test.php root@192.168.0.101:/var/www/ 把本机/var/www/目录下的test.php文件上传到192.168.0.101这台服务器上的/var/www/目录中
2、从服务器上下载文件
下载文件我们经常使用wget,但是如果没有http服务,如何从服务器上下载文件呢?
scp username@servername:/path/filename /var/www/local_dir(本地目录)
例如scp root@192.168.0.101:/var/www/test.txt 把192.168.0.101上的/var/www/test.txt 的文件下载到/var/www/local_dir(本地目录)
3、从服务器下载整个目录
scp -r username@servername:/var/www/remote_dir/(远程目录) /var/www/local_dir(本地目录)
例如:scp -r root@192.168.0.101:/var/www/test /var/www/
4、上传目录到服务器
scp -r local_dir username@servername:remote_dir
-

浙公网安备 33010602011771号