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("\033[31;1mHas changed the flight status to \033[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__ 表示当前操作的对象的类是什么
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class Foo(object): """ 描述类信息,这是用于看片的神奇 """ def func(self): pass if __name__ == '__main__': print(Foo.__doc__)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from special import Foo obj = Foo() print(obj.__class__) print(obj.__module__)
输出:
<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)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from controller import func inp = input('>>>>') if(hasattr(func,inp)): resul = getattr(func,inp) result = resul() else: result = '404' print(result)
socket概念
socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。 我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 。
建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务端被动等待并接收请求,客户端主动发起请求, 连接建立之后,双方可以互发数据。
Socket 方法
socket.
socket
(family=AF_INET, type=SOCK_STREAM, proto=0, fileno=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())