• Day8-面向对象进阶&&socket基础


    抽象类

    python2中的写法

    import abc
    class Alert(object):
        '''报警基类'''
        __metaclass__ = abc.ABCMeta
        @abc.abstractmethod
        def send(self):
            '''报警消息发送接口'''
            pass
    
    class MailAlert(Alert):
        pass
    
    m = MailAlert()
    m.send()

    python3中的写法

    class Alert(object):
        def send(self):
            raise NotImplementedError
    
    class MailAlert(Alert):
        def send(self,msg):
            print('--sending--',msg)
    
    class SMSAlert(Alert):
        pass
    
    m = MailAlert()
    m.send()

    必须重构父类的send方法,否则主动抛出错误。

    静态方法:不能访问公有属性,也不能访问实例

    应用场景:实例多,节省内存开销

    通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法

    1、主动传实例给eat方法

    class Person(object):
        def __init__(self,name):
            self.name = name
        @staticmethod
        def eat(self):
            print('%s is eating '%self.name)
    p = Person('alex')
    p.eat(p)

    2、和类没什么关系,和函数差不多,只是通过类进行调用。

    class Person(object):
        def __init__(self,name):
            self.name = name
        @staticmethod
        def eat(name):
            print('%s is eating '%name)
    
    Person.eat('alex')

    类方法:访问类的公有属性,不能访问实例属性

    class Dog(object):
        name = "alex"
    
        def __init__(self, name):
            self.name = name
    
        @classmethod
        def eat(self):
            print("%s is eating" % self.name)
    
    
    d = Dog("xxx")
    d.eat()

    输出结果是alex is eating,和实例化里的name没关系

    属性方法:
    属性方法的作用就是通过@property把一个方法变成一个静态属性

    class Dog(object):
     
        def __init__(self,name):
            self.name = name
     
        @property
        def eat(self):
            print(" %s is eating" %self.name)
     
     
    d = Dog("alex")
    d.eat

    在调用eat时不能加(),此时eat是属性而不是方法

    属性方法的应用场景:

    比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:

    1. 连接航空公司API查询

    2. 对查询结果进行解析 

    3. 返回结果给你的用户

    因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,还是看代码吧。

    class Flight(object):
        def __init__(self,name):
            self.flight_name = name
    
    
        def checking_status(self):
            print("checking flight %s status " % self.flight_name)
            return  1
    
        @property
        def flight_status(self):
            status = self.checking_status()
            if status == 0 :
                print("flight got canceled...")
            elif status == 1 :
                print("flight is arrived...")
            elif status == 2:
                print("flight has departured already...")
            else:
                print("cannot confirm the flight status...,please check later")
    
    
    f = Flight("CA980")
    f.flight_status

    既然flight_status是属性了,给它改个值,改完之后就sb了

    class Flight(object):
        def __init__(self,name):
            self.flight_name = name
    
    
        def checking_status(self):
            print("checking flight %s status " % self.flight_name)
            return  1
    
    
        @property
        def flight_status(self):
            status = self.checking_status()
            if status == 0 :
                print("flight got canceled...")
            elif status == 1 :
                print("flight is arrived...")
            elif status == 2:
                print("flight has departured already...")
            else:
                print("cannot confirm the flight status...,please check later")
        
        @flight_status.setter #修改
        def flight_status(self,status):
            status_dic = {
                0 : "canceled",
                1 :"arrived",
                2 : "departured"
            }
            print("33[31;1mHas changed the flight status to 33[0m",status_dic.get(status) )
    
        @flight_status.deleter  #删除
        def flight_status(self):
            print("status got removed...")
    
    f = Flight("CA980")
    f.flight_status
    f.flight_status =  2 #触发@flight_status.setter 
    del f.flight_status #触发@flight_status.deleter

    类的特殊成员方法

    1.__doc__表示类的描述信息

    class Foo:
        """ 描述类信息,这是用于看片的神奇 """
     
        def func(self):
            pass
     
    print Foo.__doc__
    #输出:类的描述信息

    2. __module__ 和  __class__ 

      __module__ 表示当前操作的对象在那个模块

      __class__     表示当前操作的对象的类是什么

    special.py
    class Foo(object):
        """ 描述类信息,这是用于看片的神奇 """
    
        def func(self):
            pass
    
    if __name__ == '__main__':
        print(Foo.__doc__)

    from special import Foo
    obj = Foo()
    print(obj.__class__)
    print(obj.__module__)
    View Code

    输出:

    <class 'special.Foo'>
    special

    3. __init__ 构造方法,通过类创建对象时,自动触发执行。

    4.__del__

     析构方法,当对象在内存中被释放时,自动触发执行。

    5. __call__ 对象后面加括号,触发执行。

    两种方式,一种是类()(),另一种先实例化对象,对象()

    class Foo:
    def __init__(self):
            pass
    
        def __call__(self, *args, **kwargs):
            print('-----',args,kwargs)
    
    
    obj = Foo()  # 执行 __init__

    1.obj('alex') # 执行 __call__ 2.Foo()('wusir')

    6. __dict__ 查看类或对象中的所有成员

    class Province:
     
        country = 'China'
     
        def __init__(self, name, count):
            self.name = name
            self.count = count
     
        def func(self, *args, **kwargs):
            print 'func'
     
    # 获取类的成员,即:静态字段、方法、
    print Province.__dict__
    # 输出:{'country': 'China', '__module__': '__main__', 'func': <function func at 0x10be30f50>, '__init__': <function __init__ at 0x10be30ed8>, '__doc__': None}
     
    obj1 = Province('HeBei',10000)
    print obj1.__dict__
    # 获取 对象obj1 的成员
    # 输出:{'count': 10000, 'name': 'HeBei'}
     
    obj2 = Province('HeNan', 3888)
    print obj2.__dict__
    # 获取 对象obj1 的成员
    # 输出:{'count': 3888, 'name': 'HeNan'}

    7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。

    class Foo:
     
        def __str__(self):
            return 'alex li'
     
     
    obj = Foo()
    print obj
    # 输出:alex li

    8.__getitem__、__setitem__、__delitem__

    用于索引操作,如字典。以上分别表示获取、设置、删除数据

    class Foo(object):
     
        def __getitem__(self, key):
            print('__getitem__',key)
     
        def __setitem__(self, key, value):
            print('__setitem__',key,value)
     
        def __delitem__(self, key):
            print('__delitem__',key)
     
     
    obj = Foo()
     
    result = obj['k1']      # 自动触发执行 __getitem__
    obj['k2'] = 'alex'   # 自动触发执行 __setitem__
    del obj['k1']  

    9. __new__ __metaclass__

    class Foo(object):
     
     
        def __init__(self,name):
            self.name = name
     
     
    f = Foo("alex")

    上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象

    如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。

    f对象是Foo类的一个实例Foo类对象是 type 类的一个实例

    所以创建类有两种方法:

    1、普通方法

    是个人都会,没什么好装逼的

    class Foo(object):
      
        def func(self):
            print 'hello alex'

    2、装逼必备

    def __init__(self,name):#构造函数
        self.name = name
    def talk(self,msg):
        print('%s is talking:%s'%(self.name,msg))
    dog = type( '',(object,),{'talk2':talk,'__init__':__init__})#创建dog类
    
    d = dog('alex')
    d.talk2('eeeeeee')#在调用类方法的时候就通过type中的talk2

    10. __getattr__ 

    当实例中属性查找失败时,会调用类的__getattr__函数,如果没有定义这个函数,那么抛出AttributeError异常

    class OpEvent(object):
        def __init__(self, **kwargs):
            self.app = kwargs['app']
    
        def __getattr__(self, log_type):
            def _log(**kwargs):
                kwargs['type'] = log_type
                kwargs['app'] = self.app
                kwargs['timestamp'] = time.time()
                kwargs['uuid'] = '%s' % uuid.uuid1()
                redis = get_redis_cluster()
                redis.lpush(EVENT_KEY, json.dumps(kwargs))
                return kwargs['uuid']
            return _log
    

      

    op = OpEvent(app='ops.deploy')
    op.info()
    

      

    异常处理

    一、基本异常处理结构

    try:
        代码块
        代码块
    except Exception as e:
        将错误信息写入日志文件

    二、复杂结构

    try:
        # 主代码块
        pass
    except KeyError,e:
        # 异常时,执行该块
        pass
    else:
        # 主代码块执行完,执行该块
        pass
    finally:
        # 无论异常与否,最终执行该块
        pass

    主动触发异常:

    try:
        raise Exception('错误了。。。')
    except Exception,e:
        print e

    自定义异常

    class AlexError(Exception):
        def __init__(self,message):
            self.msg = message
            super(AlexError,self).__init__(message)#继承Exception
    try:
        name = 'wusir'
        if name!= 'alex':
            raise AlexError('你不能进入我的身体')
    except AlexError as e:
        print(e,e.msg)
    except Exception as e:
        print(e,1111)

    断言

    assert 条件

    满足就往下执行

    条件不满足就报异常

    反射:

    反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!

    python中的反射功能是由以下四个内置函数提供:hasattr、getattr、setattr、delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员、获取成员、设置成员、删除成员。

    getattr()以字符串的形式去某个对象中获取指定的属性

    hasattr()以字符串的形式判断某个对象中是否含有指定的属性

    setattr(容器,‘名称’,值)

    以字符串的形式导入模块

    __import__('time')

    module = __import__('controller.account',fromlist=True)

    controller/func.py
    from controller import func
    inp = input('>>>>')
    if(hasattr(func,inp)):
        resul = getattr(func,inp)
        result = resul()
    else:
        result = '404'
    print(result)
    View Code

    socket概念

    socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。 我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 。

    建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务端被动等待并接收请求,客户端主动发起请求, 连接建立之后,双方可以互发数据。

    Socket 方法

    socket.socket(family=AF_INETtype=SOCK_STREAMproto=0fileno=None)

    sk.bind(address)

      s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。

    sk.listen(backlog)

      开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。

          backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5
          这个值不能无限大,因为要在内核中维护连接队列

    sk.accept()

      接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。

      接收TCP 客户的连接(阻塞式)等待连接的到来

    sk.connect(address)

      连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。

    sk.recv(bufsize[,flag])

      接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。

     简易ssh

    server端

    import socket
    import subprocess
    server = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind(('0.0.0.0',8000))
    server.listen(5)
    print('--------start to listen-------')
    while True:
        conn,client_addr = server.accept()
        print(conn,client_addr)
    
        while True:
            data = conn.recv(1024)
            print('recv from cli:',data)
            res_obj = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
            res = res_obj.stdout.read()
            conn.send(str(len(res)).encode())
            print('--res len:',len(res))
            conn.send(res)

    client端

    import socket
    
    client = socket.socket()
    client.connect(('10.69.112.77',8000))
    while True:
        msg = input('>>').strip()
        if len(msg) == 0:continue
        client.send(msg.encode())
        print('send',msg)
        data = client.recv(1024)
        print('receive from server:',data.decode())
        total_size = int(data.decode())
    
        received_size = 0
        res = b''
        while received_size < total_size:
            d = client.recv(1024)
            res += d
            received_size += len(d)
        print('--------recv done-------')
        print(res.decode())
  • 相关阅读:
    Python—模块
    Python之路_Day5
    Python之路_Day4
    Py获取本机指定网卡的ip地址
    Python之路_Day3
    Python之路—Day2作业
    Python之路—Day2
    Python之路—Day1作业
    Python之路—Day1
    Python数据类型
  • 原文地址:https://www.cnblogs.com/hongpeng0209/p/6108867.html
Copyright © 2020-2023  润新知