跳转至

第三阶段考试题

  1. 简述面向对象的三大特性
继承:将多个子类的相同方法写到父类中, 子类继承父类的方法。提升重用性
封装:将多个数据封装到一个对象中,同类型的方法编写到一个类中。
多态:天然支持多态,崇尚鸭子模型,不对类型做任何限制,只要具备属性即可。
  1. super的作用?
根据mro的顺序,向上查找类
  1. 实例变量和类变量的区别?
实例变量: 属于对象 ,每个对象各自存储,管理自己的变量
类变量 : 属于类, 在类中存储
  1. @staticmethod 和 @classmethod的区别?
statimethod  静态方法    可以有任意个参数, 执行时  类和对象都可以调用
classmethod  类方法      至少有一个cls参数  执行时 类和对象都可以调用  自动把当前类当参数传给cls
  1. 简述 __new__和__init__的区别?
__new__ 初始化方法  用于创建对象
__init__ 初始化方法  用于对象中初始化值
  1. 在Python中如何定义私有成员?
使用 __ 开头的
  1. 请基于__new__ 实现一个单例类(加锁)。
# 请基于`__new__` 实现一个单例类(加锁)。
import threading


class Singleton(object):
    instance = None
    lock = threading.RLock()

    def __init__(self, name):
        self.name = name

    def __new__(cls, *args, **kwargs):
        if cls.instance:
            return cls.instance
        with cls.lock:
            if cls.instance:
                return cls.instance
            cls.instance = super().__new__(cls)
        return cls.instance


t1 = Singleton('aaa')
t2 = Singleton('bbbb')
print(t1 is t2)
  1. 比较以下两段代码的区别
class F1(object):
    def func(self, num):
        print("F1.func", num) #F1.func 1


class F2(F1):
    def func(self, num):
        print("F2.func", num)


class F3(F2):
    def run(self):
        F1.func(self, 1)  # 指定了F1类的 func方法


obj = F3()
obj.run()
class F1(object):
    def func(self, num):
        print("F1.func", num)


class F2(F1):
    def func(self, num):
        print("F2.func", num)  # F2.func 1


class F3(F2):
    def run(self):
        super().func(1)  # 去父进程找func方法


obj = F3()
obj.run()
  1. 补充代码实现
class Context:
    pass

with Context() as ctx:
    ctx.do_something()

# 请在Context类下添加代码完成该类的实现
class Context:
    def __enter__(self):
        print('enter')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

    def do_something(self):
        print('do_something')


with Context() as ctx:
    ctx.do_something()

# 请在Context类下添加代码完成该类的实现
  1. 简述 迭代器、可迭代对象 的区别?

    迭代器:
                1 定义了__iter__ 和 __next__ 方法
                2 运行 __iter__ 返回对象本身
                3 运行 __next__ 返回下一个数据,没有抛出 StopIteration 异常
    可迭代对象:
                定义了 __iter__ 方法 返回一个 迭代器对象
    
  2. 什么是反射?反射的作用?

    通过字符串的方式操作对象的成员
    
  3. 简述OSI七层模型。

    osi  open system interconnection  国际化标准组织制定的计算机与通信网络互连的标准体系。
    
    应用层   规定数据格式
    表示层   将应用层的数据进行编码 压缩 分块 加密解密 等任务
    会话层   与目标建立连接  中断连接
    传输层   建立端口到端口的通信
    网络层   标记ip信息
    数据链路层 标记mac信息
    物理层    将二进制数据在物理媒介上传输
    
  4. UDP和TCP的区别。

    UDP 不提供可靠的连接, 它只是将应用层传给ip层数据包发出去,不保证到达目的地,由于发送数据包前客户端和服务器没有建立可靠的连接,且没有重发机制,所有速度快,常见的应用:语音通话 视频会议 实时游戏画面
    TCP 提供可靠连接,在收发数据前 ,必须建立可靠的连接。常见应用 web网站,手机app等
    
  5. 简述TCP三次握手和四次挥手的过程。

    tcp 三次握手  四次挥手过程
    三次握手
    client  -----》 seq = 100 随机值 server
    client  《------- seq = 300随机值 ack=101(第一次seq+1) server
    client  ------>  seq= 101(第一次seq+1) ack =301(第二次seq+1) server
    
    四次挥手  任意一方可发起
    client  -----》  seq = 100 随机值 fin=1  server
    client  《------- seq=300  ack = 101(第一次seq+1)    server
    client   《-------- seq = 300 ack= 101 fin=1   server
    client   -------》 seq=101(第一次seq+1)  ack = 301(第三次seq+1)  server
    
    
    Seq:序列号
    ACK:确认标志
    SYN:同步标志
    FIN: 结束标志
    
  6. 简述你理解的IP和子网掩码。

    子网掩码是用来给ip划分网段 , IP分为网络地址+主机地址
    子网掩码掩盖的是网络地址 未掩盖的是主机地址
    
  7. 端口的作用?

    在网络编程中,  ip指某个计算机, 端口则代指计算机某个程序, 用来区分不同程序进程。
    
  8. 什么是粘包?如何解决粘包?

    两台电脑收发数据时候, 其实不是直接将数据发送给对方的。
    - 对于发送者, 在执行 sendall/send 发送消息时,是将数据发送至自己电脑的网卡写缓冲区,再由缓冲区发送至对方网卡的读缓冲区
    - 对于接收者: 在执行 recv  接收消息时,是从自己电脑网卡的读缓冲区获取数据。
    再发送者连续发送两条数据,接收者会当一条数据处理了, 即两个数据黏在一起了。
    
    解决思路:
            双方约定规则: 按照 数据头+数据 方式来处理数据 (数据头设置好数据长度)
    
  9. IO多路复用的作用是什么?

    可以监听多个 io对象的变化(可读 可写 异常)
    网络编程中与非阻塞的socket配合使用   监听 服务端 客户端的变化(可读 可写 异常)
    
    socket 多种模式
      select 限制1024  轮询
      poll   无限制  
      epoll 无限制  采用回调机制(边缘触发)
    
  10. 简述进程、线程、协程的区别。

    进程:计算机中资源分配的最小单位
    线程:计算机中cpu调度的最小单位
    进程为线程提供资源分配,一个进程中可以有多个线程, 一个进程中的多个线程共享此进程的资源
    
    协程:也称微线程,是一种用户态内的上下文切换,开发中结合遇到io操作自动切换,实现一个线程中并发操作。
    所以:协程比线程更节省资源,(开发难度大一些)
    
  11. 什么是GIL锁?其作用是什么?

    GIL是Cpython中独有的全局解释器锁, 作用: 让一个进程中同一个时刻只有一个线程供cpu调用
    
  12. 进程之间如何实现数据的共享?

    multiprocessing.Value
    multiprocessing.Array
    multiprocessing.Manager
    multiprocessing.Pipe
    multiprocessing.Queue
    
  13. 已知一个订单对象(tradeOrder)有如下字段:

    字段英文名 中文名 字段类型 取值举例
    nid ID int 123456789
    name 姓名 str 张三
    items 商品列表 list 可以存放多个订单对象
    is_member 是否是会员 bool True

    商品对象有如下字段:

    字段英文名称 中文名 字段类型 取值
    id 主键 int 987654321
    name 商品名称 str 手机

    请根据要求实现如下功能:

    • 编写相关类。
    • 创建订单对象并根据关系关联多个商品对象。
    • 用json模块将对象进行序列化为JSON格式(提示:需自定义JSONEncoder)。
  14. 基于面向对象的知识构造一个链表。

    image-20210428164850308

    注意:每个链表都是一个对象,对象内部均存储2个值,分为是:当前值、下一个对象 。

  15. 读源码,分析代码的执行过程。

    • socket服务端
    import socket
    import threading
    
    
    class BaseServer:
    
        def __init__(self, server_address, request_handler_class):
            self.server_address = server_address
            self.request_handler_class = request_handler_class
    
        def serve_forever(self):
            while True:
                request, client_address = self.get_request()
                self.process_request(request, client_address)
    
        def finish_request(self, request, client_address):
            self.request_handler_class(request, client_address, self)()
    
        def process_request(self, request, client_address):
            pass
    
        def get_request(self):
            return "傻儿子", "Alex"
    
    
    class TCPServer(BaseServer):
        address_family = socket.AF_INET
    
        socket_type = socket.SOCK_STREAM
    
        request_queue_size = 5
    
        allow_reuse_address = False
    
        def __init__(self, server_address, request_handler_class, bind_and_activate=True):
            BaseServer.__init__(self, server_address, request_handler_class)
            self.socket = socket.socket(self.address_family, self.socket_type)
            self.server_bind()
            self.server_activate()
    
        def server_bind(self):
            self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            self.socket.bind(self.server_address)
            self.server_address = self.socket.getsockname()
    
        def server_activate(self):
            self.socket.listen(self.request_queue_size)
    
        def get_request(self):
            return self.socket.accept()
    
        def close_request(self, request):
            request.close()
    
    
    class ThreadingMixIn:
        def process_request_thread(self, request, client_address):
            self.finish_request(request, client_address)
            self.close_request(request)
    
        def process_request(self, request, client_address):
            t = threading.Thread(target=self.process_request_thread, args=(request, client_address))
            t.start()
    
    
    class ThreadingTCPServer(ThreadingMixIn, TCPServer):
        pass
    
    
    class BaseRequestHandler:
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
            self.setup()
    
        def __call__(self, *args, **kwargs):
            try:
                self.handle()
            finally:
                self.finish()
    
        def setup(self):
            pass
    
        def handle(self):
            pass
    
        def finish(self):
            pass
    
    
    class MyHandler(BaseRequestHandler):
        def handle(self):
            print(self.request)
            self.request.sendall(b'hahahahah...')
    
    
    server = ThreadingTCPServer(("127.0.0.1", 8000), MyHandler)
    server.serve_forever()
    
  • socket客户端
    import socket

    # 1. 向指定IP发送连接请求
    client = socket.socket()
    client.connect(('127.0.0.1', 8000)) # 向服务端发起连接(阻塞)10s

    # 2. 连接成功之后,发送消息
    client.sendall('hello'.encode('utf-8'))

    # 3. 等待,消息的回复(阻塞)
    reply = client.recv(1024)
    print(reply)

    # 4. 关闭连接
    client.close()
  1. 请自己基于socket模块和threading模块实现 门票预订 平台。(无需考虑粘包)

    • 用户作为socket客户端

    • 输入景区名称,用来查询景区的余票。

    • 输入景区名称-预订者-8,用于预定门票。

    • socket服务端,可以支持并发多人同时查询和购买。(为每个客户度创建一个线程)。

    • 服务端数据存储结构如下:

      db
      ├── tickets
      │   ├── 欢乐谷.txt # 内部存储放票数量
      │   ├── 迪士尼.txt
      │   └── 长城.txt
      └── users
          ├── alex.txt # 内部存储次用户预定记录
          └── 武沛齐.txt
      
      # 注意:当用户预定门票时,放票量要减去相应的数量(变为0之后,则不再接受预定)。
      

      image-20210428133641127

      image-20210428133822091