python基础学习之一

1. python是解释型语言

第一个缺点就是运行速度慢,和C程序相比非常慢,因为Python是解释型语言,你的代码在执行时会一行一行地翻译成CPU能理解的机器码,这个翻译过程非常耗时,所以很慢。而C程序是运行前直接编译成CPU能执行的机器码,所以非常快。

第二个缺点就是代码不能加密。如果要发布你的Python程序,实际上就是发布源代码,这一点跟C语言不同,C语言不用发布源代码,只需要把编译后的机器码(也就是你在Windows上常见的xxx.exe文件)发布出去。要从机器码反推出C代码是不可能的,所以,凡是编译型的语言,都没有这个问题,而解释型的语言,则必须把源码发布出去。

2. python range() 函数可创建一个整数列表,一般用在 for 循环中。

range(start, stop[, step])

参数说明:

  • start: 计数从 start 开始。默认是从 0 开始。例如range(5)等价于range(0, 5);
  • stop: 计数到 stop 结束,但不包括 stop。例如:range(0, 5) 是[0, 1, 2, 3, 4]没有5
  • step:步长,默认为1。例如:range(0, 5) 等价于 range(0, 5, 1)

2. python中@的用法

@是一个装饰器,针对函数,起调用传参的作用。
有修饰和被修饰的区别,‘@function'作为一个装饰器,用来修饰紧跟着的函数(可以是另一个装饰器,也可以是函数定义)。

3. 装饰器”(Decorator)

在代码运行期间动态增加功能的方式,称之为“装饰器”(Decorator)。本质上,decorator就是一个返回函数的高阶函数

4. 迭代器

迭代器有两个基本的方法iter() 和 next()

字符串,列表或元组对象都可用于创建迭代器

4. 生成器(generator)

在Python中,这种一边循环一边计算的机制,称为生成器:generator

在 Python 中,使用了 yield 的函数被称为生成器(generator)

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

通过next()函数获得generator的下一个返回值

生成器的启动需要next()

生成器启动可用send(None)

生成器send()方法

send和next的执行很像,只是send可以和生成器互动,传入一个值。

send() 方法可带一个参数,也可以不带任何参数(用 None 表示)。其中,当使用不带参数的 send() 方法时,它和 next() 函数的功能完全相同

带参数的 send(value) 无法启动执行生成器函数。也就是说,程序中第一次使用生成器调用 next() 或者 send() 函数时,不能使用带参数的 send() 函数

Python生成器close()方法

当程序在生成器函数中遇到 yield 语句暂停运行时,此时如果调用 close() 方法,会阻止生成器函数继续执行,该函数会在程序停止运行的位置抛出 GeneratorExit 异常。

generator保存的是算法,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。

generator也是可迭代对象

如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator

函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行

generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。

5. 协程

进程(Process)和线程(Thread)是os通过调度算法,保存当前的上下文,然后从上次暂停的地方再次开始计算,重新开始的地方不可预期,每次CPU计算的指令数量和代码跑过的CPU时间是相关的,跑到os分配的cpu时间到达后就会被os强制挂起,开发者无法精确的控制它们。

协程(Coroutine)是一种轻量级的用户态线程,实现的是非抢占式的调度,即由当前协程切换到其他协程由当前协程来控制。目前的协程框架一般都是设计成 1:N 模式。所谓 1:N 就是一个线程作为一个容器里面放置多个协程。那么谁来适时的切换这些协程?答案是有协程自己主动让出 CPU,也就是每个协程池里面有一个调度器,这个调度器是被动调度的。意思就是他不会主动调度。而且当一个协程发现自己执行不下去了(比如异步等待网络的数据回来,但是当前还没有数据到),这个时候就可以由这个协程通知调度器,这个时候执行到调度器的代码,调度器根据事先设计好的调度算法找到当前最需要 CPU 的协程。切换这个协程的 CPU 上下文把 CPU 的运行权交个这个协程,直到这个协程出现执行不下去需要等等的情况,或者它调用主动让出 CPU 的 API 之类,触发下一次调度。

和多线程比,协程有何优势?

最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。

第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。

因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能

Python对协程的支持是通过generator实现的。

6. Gevent 库

Gevent使用说明

  • monkey可以使一些阻塞的模块变得不阻塞,机制:遇到IO操作则自动切换,手动切换可以用gevent.sleep(0)(将爬虫代码换成这个,效果一样可以达到切换上下文)
  • gevent.spawn 启动协程,参数为函数名称,参数名称
  • gevent.joinall 停止协程

Monkey-patching猴子补丁是将标准库中大部分的阻塞式调用替换成非阻塞的方式,包括socketsslthreadingselecthttplib等。通过monkey.path_xxx()函数来打补丁,根据Gevent文档中的建议,应当将猴子补丁的代码尽可能早的被调用,这样可以避免一些奇怪的异常。

gevent.spawn()    创建一个普通的Greenlet对象并切换
gevent.spawn_later(seconds=3)    延时创建一个普通的Greenlet对象并切换
gevent.spawn_raw()    创建的协程对象属于一个组
gevent.getcurrent()    返回当前正在执行的greenlet
gevent.joinall(jobs)    将协程任务添加到事件循环,接收一个任务列表
gevent.wait()    可以替代join函数等待循环结束,也可以传入协程对象列表
gevent.kill()    杀死一个协程
gevent.killall()    杀死一个协程列表里的所有协程
monkey.patch_all()    非常重要,会自动将python的一些标准模块替换成gevent框架
采用gevent.sleep()时,会切换到另外一个使用gevent.spawn()衍生的函数去执行

#向指定的url地址发送请求,并返回服务器响应的类文件对象
response = urllib2.urlopen('http://www.baidu.com/')
#服务器返回的类文件对象支持python文件对象的操作方法
#read()方法就是读取文件里的全部内容,返回字符串
html = response.read()

7. asyncio

asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持

python中使用协程最常用的库就是asyncio

@asyncio.coroutine把一个generator标记为coroutine类型

注意这里是【标记】,划重点。
实际上,它的本质还是一个生成器。
标记后,它实际上已经可以当成协程使用

yield from 作用:

简单的说,就是让生成器进行嵌套,在一个生成器里面可以使用另外一个生成器,允许一个generator生成器将其部分操作委派给另一个生成器。

对于简单的迭代器,yield from iterable本质上等于for item in iterable: yield item的缩写版, 例如:

>>> def g(x):
...     yield from range(x, 0, -1)
...     yield from range(x)
...
>>> list(g(5))
[5, 4, 3, 2, 1, 0, 1, 2, 3, 4]

然而,不同于普通的循环,yield from允许子生成器直接从调用者接收其发送的信息或者抛出调用时遇到的异常,并且返回给委派生产器一个值

yield from语法可以让我们方便地调用另一个generator

asyncio.sleep()也是一个coroutine

1、event_loop 事件循环:相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足条件时,就会调用对应的处理方法。
2、coroutine 协程:协程对象,只一个使用async关键字定义的函数,他的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环中,由事件循环调用。
3、task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程的进一步封装,其中包含任务的各种状态。
4、future:代表将来执行或没有执行的任务结果。它与task没有本质的区别。
5、async/await 关键字:python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。

定义一个协程 通过async定义一个协程,协程是一个对象,不能直接运行,需要把协程加入到事件循环(loop)中,由loop在适当的时候调用协程。asyncio.get_event_loop()方法可以创建一个事件循环,然后由run_until_complete(协程对象)将协程注册到事件循环中,并启动事件循环。

协程对象不能直接运行,在注册事件循环的时候,其实是 run_until_complete 方法将协程包装成为了一个任务(task)对象,保存了协程运行后的状态,用于未来获取协程的结果

run_until_complete根据传递的参数的不同,返回的结果也有所不同

1、run_until_complete()传递的是一个协程对象或task对象,则返回他们finished的返回结果(前提是他们得有return的结果,否则返回None)
2、run_until_complete(asyncio.wait(多个协程对象或任务)),函数会返回一个元组包括(done, pending),通过访问done里的task对象,获取返回值
3、run_until_complete(asyncio.gather(多个协程对象或任务)),函数会返回一个列表,列表里面包括各个任务的返回结果,按顺序排列
python 3.7 以前的版本调用异步函数的步骤:

1、调用asyncio.get_event_loop()函数获取事件循环loop对象
2、通过不同的策略调用loop.run_forever()方法或者loop.run_until_complete()方法执行异步函

loop.run_until_complete 方法运行事件循环,当其中的全部任务完成后,自动停止事件循环;loop.run_ferever 方法为无限运行事件循环,需要自定义 loop.stop 方法并执行

Stream 函数

asyncio.open_connection

coroutine asyncio.open_connection(host=Noneport=None*loop=Nonelimit=Nonessl=Nonefamily=0proto=0flags=0sock=Nonelocal_addr=Noneserver_hostname=Nonessl_handshake_timeout=None)

建立网络连接并返回一对 (reader, writer) 对象。

返回的 reader 和 writer 对象是 StreamReader 和 StreamWriter 类的实例。

StreamReader

class asyncio.StreamReader

表示一个从IO stream中获取数据的提供api 接口的对象

coroutine read(n=-1)

每次读取N个字节,如果n 没有或者设为-1, 那么就会一直读到EOF

Read up to n bytes. If n is not provided, or set to -1, read until EOF and return all read bytes.

If EOF was received and the internal buffer is empty, return an empty bytes object.

coroutine readline()

Read one line, where "line" is a sequence of bytes ending with \n.

If EOF is received and \n was not found, the method returns partially read data.

If EOF is received and the internal buffer is empty, return an empty bytes object.

class asyncio.StreamWriter

Represents a writer object that provides APIs to write data to the IO stream.

write(data)

Write data to the stream.

This method is not subject to flow control. Calls to write() should be followed by drain().

coroutine drain()

Wait until it is appropriate to resume writing to the stream. Example:

writer.write(data)
await writer.drain()

This is a flow control method that interacts with the underlying IO write buffer. When the size of the buffer reaches the high watermark, drain() blocks until the size of the buffer is drained down to the low watermark and writing can be resumed. When there is nothing to wait for, the drain() returns immediately.

这是一个与底层IO输入缓冲区交互的流量控制方法。当缓冲区达到上限时,drain()阻塞,待到缓冲区回落到下限时,写操作可以被恢复。当不需要等待时,drain()会立即返回

作用:

刷新底层传输的写缓冲区。也就是把需要发送出去的数据,从缓冲区发送出去。没有手工刷新,asyncio为你自动刷新了。当执行到reader.readline()时,asyncio知道应该把发送缓冲区的数据发送出去了。

yield from主要有什么用?

1. 利用yield from从生成器读取数据

2. 利用yield from语句向生成器(协程)传送数据

3. 利用yield from向生成器传送数据--处理异常

yield from 是 Python3.3 后新加的语言结构。和其他语言的await关键字类似,它表示:*在生成器 gen 中使用 yield from subgen()时,subgen 会获得控制权,把产出的值传个gen的调用方,即调用方可以直接控制subgen。于此同时,gen会阻塞,等待subgen终止。


import asyncio
 
 
@asyncio.coroutine
def wget(host):
    print('wget %s...' % host)
    connect = asyncio.open_connection(host, 80)  # 与要获取数据的网页建立连接
    # 连接中包含一个 reader和writer
    reader, writer = yield from connect  # 通过writer向服务器发送请求,通过reader读取服务器repnse回来的请求
    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host  # 组装请求头信息
    writer.write(header.encode('utf-8'))  # 需要对请求头信息进行编码
    yield from writer.drain()  # 由于writer中有缓冲区,如果缓冲区没满不且drain的话数据不会发送出去
    while True:
        line = yield from reader.readline()  # 返回的数据放在了reader中,通过readline一行一行地读取数据
        if line == b'\r\n':  # 因为readline实际上已经把\r\n转换成换行了,而此时又出现\r\n说明以前有连续两组\r\n
            break           # 即\r\n\r\n,所以下面就是response body了
        print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
    # Ignore the body, close the socket
    writer.close()
    # reader.close()   AttributeError: 'StreamReader' object has no attribute 'close'
 
 
loop = asyncio.get_event_loop()
tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
loop.run_until_complete(asyncio.wait(tasks))
loop.close()

7. wsgi

Web服务器网关接口Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器Web应用程序框架之间的一种简单而通用的接口

8. 

字符串前加 b

例: response = b'<h1>Hello World!</h1>'     # b' ' 表示这是一个 bytes 对象

作用:

b" "前缀表示:后面字符串是bytes 类型。

用处:

网络编程中,服务器和浏览器只认bytes 类型数据。

如:send 函数的参数和 recv 函数的返回值都是 bytes 类型

附:

在 Python3 中,bytes 和 str 的互相转换方式是
str.encode('utf-8')
bytes.decode('utf-8')

猜你喜欢

转载自blog.csdn.net/ai2000ai/article/details/104883024
今日推荐