zoukankan      html  css  js  c++  java
  • python周报第十周

    0.本周知识点预览

    • python作用域
    • 浅谈py2和py3的多继承
    • socketserver源码简析
    • IO多路复用
    • 初识多线程

    1.python作用域

    先看一个简单的例子

    例子1:

    def func():
        name = "lk"
    
    func()
    print(name)

    执行结果如下:

    Traceback (most recent call last):
      File "/Users/liukai/PycharmProjects/s13/day10/test.py", line 12, in <module>
        print(name)
    NameError: name 'name' is not defined

    例子2:

    if 1==1:
        name = "lk"
    
    print(name)

    执行结果如下:

    lk

    例子3:

    name = 'lk'
    
    def f1():
        print(name)
    
    def f2():
        name = "liukai"
        return f1
    
    ret = f2()
    ret()

    执行结果如下:

    lk

    例子4:

    li = [lambda :x for x in range(10)]
    print(li[0],li[1])
    print(li[0]())

    执行结果如下:

    <function <listcomp>.<lambda> at 0x1079470d0> <function <listcomp>.<lambda> at 0x107947158>
    9

     代码解析:

    例子1:变量name定义在函数func()内,当print(name)的时候,报变量未定义,可推断出,python至少作用域为函数级。

    例子2:在if else代码块内,定义了变量name,可以成功print,可见,python也并不是代码块级作用域。PS:java、c#是代码块级作用域。

    例子3:python为函数级作用域,而且内部函数未找到变量时,会去外层函数找,但例子3中,f1函数在f2函数内,不过输出的并不是我们想要的liukai,说明,python的作用域在代码执行之前就确定了,和函数如何嵌套是没关系的,代码从上到下执行,到加载到f1函数时,作用域就为函数体内,如若找不到变量,便去函数体外找,并不是在f2内。

    例子4:li列表的最终结果为10个lambda函数,如li[0],li[1]...,不过为什么li[0]不等于0呢?这是因为,for x in range(10),已经让x等于9,并且,函数如若不加括号,便不会执行,也不会加载函数体内的内容。所有函数体内的x值一直不变,当执行li[0]()的时候,便会输出此时已经等于9的x。

    综上:python的作用域为函数级,包括class,def,lambda;if else / while / for 不会改变作用域,搜索顺序为先搜索本地局部变量,在搜索上层变量直至全局变量。

    2.py2和py3的多继承

    1.py2

    这里先说python2.7的版本。python2.7版本的类分为两种。

    一、经典类

    class A:
        def fuck(self):
            print("我是A类")
    
    class B(A):
        def haha(self):
            print("我是B类")
    
    class C(A):
        def haha(self):
            print("我是C类")
    
    class D(B):
        def haha(self):
            print("我是D类")
    
    class E(C):
        def fuck(self):
            print("我是E类")
    
    class F(D,E):
        def haha(self):
            print("我是F类")
    
    f = F()
    f.fuck()

    执行结果如下:

    我是A类

    代码解析:python2.7的经典类的继承关系为深度优先,一直找到最顶层的父类,也就是一条道走到黑的模式。

    如图:

    二、新式类

    class A(object):
        def fuck(self):
            print("我是A类")
    
    class B(A):
        def haha(self):
            print("我是B类")
    
    class C(A):
        def haha(self):
            print("我是C类")
    
    class D(B):
        def haha(self):
            print("我是D类")
    
    class E(C):
        def fuck(self):
            print("我是E类")
    
    class F(D,E):
        def haha(self):
            print("我是F类")
    
    f = F()
    f.fuck()

    执行结果如下:

    我是E类

    代码解析:经典类和新式类在写法上的区别为 class A 和 class A (object),新式类的继承方式为广度优先。

    如图:

    2.py3

    python3的类继承举例:

    class A:
        def fuck(self):
            print("我是A类")
    
    class B(A):
        def haha(self):
            print("我是B类")
    
    class C(A):
        def haha(self):
            print("我是C类")
    
    class D(B):
        def haha(self):
            print("我是D类")
    
    class E(C):
        def fuck(self):
            print("我是E类")
    
    class F(D,E):
        def haha(self):
            print("我是F类")
    
    f = F()
    f.fuck()

    执行结果如下:

    我是E类

    代码解析:python3的类继承和python2.7的新式类的继承方式一样,都是广度优先。

    3.socketserver 源码简析

    socketserver源码举例:

    import socketserver         ###导入socketserver模块
    
    
    class MySocketServer(socketserver.BaseRequestHandler):      ###创建一个类继承socketserver.BaseRequestHandler
        def handle(self):
            pass
    
    if __name__ == '__main__':
        server = socketserver.ThreadingTCPServer(("127.0.0.1",8007),MySocketServer)     ###实例化socketserver.ThreadingTCPServer的对象,参数一是地址和端口,参数二是创建的类
        server.serve_forever()

    以下为socketserver源码的执行顺序

    ###找sockerserver 源码  -> socketserver.ThreadingTCPServer类
    ###1. TCPServer __init__
    
    ###2. BaseServer __init__    封装变量  self.server_address = server_address = ("127.0.0.1",8007)
    ###                                   self.RequestHandlerClass = RequestHandlerClass = MySocketServer
    
    ###3. server.serve_forever()
    
    ###4. 找BaseServer的serve_forever()  serve_forever()执行self._handle_request_noblock
    
    ###5. self._handle_request_noblock  执行  self.process_request()
    
    ###6. process_request 去 ThreadingMixIn 类里找,并执行了self.process_request_thread
    
    ###7. self.process_request_thread 执行了 self.finish_request , finish_request 去BaseServer 找
    ###8. finish_request 里执行了self.RequestHandlerClass(request, client_address, self)
    
    ###9. self.RequestHandlerClass(request, client_address, self) -> MySocketServer(request, client_address, self)
    
    ###10.  MySocketServer(request, client_address, self) 会执行 MySocketServer 的__init__方法
    
    ###11. MySocketServer 中没有 __init__方法,便去父类找,咱们写的父类是socketserver.BaseRequestHandler
    
    ###12. 父类中执行self.handle(),便是执行MySocketServer的handle()

    4.I/O多路复用 

     I/O多路复用,有三种方法,select、poll、epoll。

    windows适用于select

    mac 适用于select

    linux 适用于select、poll、epoll

    在这里只举例select的方法

    服务端:

    #!/usr/bin/env python3
    # -*- coding=utf-8 -*-
    # Author : LiuKai
    
    ## I/O 多路复用
    import socket       ###导入socket模块
    import select       ###导入select模块
    
    
    s = socket.socket()     ###创建一个socket
    
    s.bind(("127.0.0.1",9999,))     ###绑定地址
    
    
    s.listen(5)         ###设置等待队列
    input = [s,]        ###设置监听socket队列
    output = []         ###设置将要发送数据的socket队列
    
    while True:
        ###rlist 是当参数1 -> input中的socket发生变化时,就会将变化的socket加入到rlist中.变化是指当创建的socket接收请求(accept方法),或者创建连接的(conn方法)
        ###wlist 是只要参数2有值,就将socket对象传入wlist
        ###elist 是只要参数3的socket出现问题,就会把其加入到elist
        ###第四个参数1,代表超时时间,如若未设置,则select 会一直阻塞,直到文件句柄发生变化,如若设置为1,那么监听的socket无变化则阻塞1秒,返回空列表.
        rlist, wlist, elist = select.select(input,output,[],1)
    
        print(len(input),len(rlist),len(output),len(wlist))
        
        ###只要有新连接或者接收消息,则rlist就会添加元素
        for i in rlist:
            ###循环rlist,假如是新连接,则接受请求,把conn添加到input中,方便select 监听
            if i == s:
                conn, address = i.accept()
                input.append(conn)
                conn.sendall(bytes("hello",encoding="utf-8"))
            ###假如不是新连接,而是接收的信息(conn变化了),则如若接收没问题,则把连接(conn)假如到output列表中,方便wlist监听,发送消息.
            else:
                try:
                    data = i.recv(1024)
                    if not data:
                        raise Exception("收到空值")
                    else:
                        output.append(i)
                except:
                    ###假如客户端断开连接造成异常,则在监听队列中删除该conn
                    input.remove(i)
    
        ###从监听的即将要发送的等待队列中(conn),遍历该列表,发送消息,消息发出后,从发送队列中删除该conn.
        for j in wlist:
            j.sendall(bytes("response",encoding="utf-8"))
            output.remove(j)

    客户端:

    #!/usr/bin/env python3
    # -*- coding=utf-8 -*-
    # Author : LiuKai
    
    import socket
    
    s = socket.socket()
    
    s.connect(("127.0.0.1",9999,))
    
    data = s.recv(1024)
    print(data)
    
    while True:
        inp = input(">>>")
        s.sendall(bytes(inp,encoding="utf-8"))
        data = s.recv(1024)
        print(data)
    s.close()

    执行服务端后,执行多个客户端,客户端结果如下:

    b'hello'
    >>>ll
    b'response'
    >>>ll
    b'response'

    服务端结果如下:

    0 0 1 1
    1 1 0 0
    1 0 1 1
    1 1 0 0
    1 0 1 1
    1 0 0 0

    代码解析:服务端的结果为当创建一个连接,第一列和第二列为1,当新建的连接(第二列)发生变化后,连接用掉之后,会归0,当接收消息后,根据代码逻辑,会放入第三列一个socket待监听,致使第四列也会变为1.服务端发出消息后,第三列、第四列都归0.

    5.初识多线程

    简介:

    0.线程是应用程序中工作的最小单元。

    1.一个应用程序,可以有单、多进程,可以有单、多线程。

    2.默认:单进程、单线程

    3.当程序不怎么占用CPU时,I/O操作较频繁时,推荐用单进程、多线程。

    4.当程序多进行计算性操作,利用CPU较频繁,I/O操作较少时,推荐用单线程、多进程。

    5.由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,当多个线程同时修改同一条数据时可能会出现脏数据,所以,出现了线程锁 - 同一时刻允许一个线程执行操作。

    不用多线程的代码:

    import time
    
    def f1(arg):
        time.sleep(1)
        print(arg)
    
    print(time.ctime())
    for i in range(5):
        f1(i)
    print(time.ctime())

    执行结果如下:

    Wed Jul 13 22:19:55 2016
    0
    1
    2
    3
    4
    Wed Jul 13 22:20:00 2016

    代码解析:可见,连续执行5次函数f1,执行的时间为5秒。

    以下为利用多线程的代码:

    import threading
    import time
    
    def f1(arg):
        time.sleep(1)
        print(arg)
    
    print(time.ctime())
    for i in range(5):
        t = threading.Thread(target=f1,args=(i,))
        t.start()
    print(time.ctime())

    执行结果如下:

    Wed Jul 13 22:25:38 2016
    Wed Jul 13 22:25:38 2016
    0
    2
    3
    4
    1

    代码解析:利用多线程,执行时间变为1秒。

  • 相关阅读:
    手把手教你利用create-nuxt-app脚手架创建NuxtJS应用
    初识NuxtJS
    webpack打包Vue应用程序流程
    用选择器代替表格列的筛选功能
    Element-UI
    Spectral Bounds for Sparse PCA: Exact and Greedy Algorithms[贪婪算法选特征]
    Sparse Principal Component Analysis via Rotation and Truncation
    Generalized Power Method for Sparse Principal Component Analysis
    Sparse Principal Component Analysis via Regularized Low Rank Matrix Approximation(Adjusted Variance)
    Truncated Power Method for Sparse Eigenvalue Problems
  • 原文地址:https://www.cnblogs.com/Caesary/p/5662661.html
Copyright © 2011-2022 走看看