抽象接口
- class Alert(object) : '''报警基类'''def send(self) : raise NotImplementedError class MailAlert(Alert) : def send(self) : #如果子类中没有创建相应的功能时,就会报错。print('hello world') m = MailAlert() m.send()
raise 实现自动报警功能
通过 @staticmethod 装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过 self. 调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
- class Dog(object) : def __init__(self, name) : self.name = name@staticmethod#把eat方法变为静态方法def eat(self) : print("%s is eating" % self.name) d = Dog("ChenRonghua") d.eat()
上面的调用会出以下错误,说是 eat 需要一个 self 参数,但调用时却没有传递,没错,当 eat 变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给 self 了
输出结果:
Traceback (most recent call last):
File "D:/py_s15 / 练习 / 1111.py", line 9, in
d.eat()
TypeError: eat() missing 1 required positional argument:'self'
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给 eat 方法,即 d.eat(d)
2. 在 eat 方法中去掉 self 参数,但这也意味着,在 eat 中不能通过 self. 调用实例中的其它变量了
,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
- class Dog(object) : def __init__(self, name) : self.name = name@classmethod def eat(self) : print("%s is eating" % self.name) d = Dog("ChenRonghua") d.eat()
输出结果:执行报错如下,说 Dog 没有 name 属性,因为 name 是个实例变量,类方法是不能访问实例变量的
C:\Python35\python.exe D:/py_s15 / 练习 / 1111.py
Traceback (most recent call last):
File "D:/py_s15 / 练习 / 1111.py", line 8, in
d.eat()
File "D:/py_s15 / 练习 / 1111.py", line 6, in eat
print("%s is eating" % self.name)
AttributeError: type object 'Dog' has no attribute 'name'
此时可以定义一个类变量,也叫 name, 看下执行效果
- class Dog(object) : name = '我是变量'def __init__(self, name) : self.name = name@classmethod def eat(self) : print("%s is eating" % self.name) d = Dog("ChenRonghua") d.eat()
输出结果:我是变量 is eating
�个静态属性
- class Dog(object) : def __init__(self, name) : self.name = name@property def eat(self) : print(" %s is eating" % self.name) d = Dog("ChenRonghua") d.eat()
输出结果:Traceback (most recent call last):
File "D:/py_s15 / 练习 / 1111.py", line 8, in
d.eat()
TypeError: 'NoneType' object is not callable
调用会出以下错误, 说 NoneType is not callable, 因为 eat 此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加 () 号了,直接 d.eat 就可以了
- class Dog(object) : def __init__(self, name) : self.name = name@property def eat(self) : print(" %s is eating" % self.name) d = Dog("ChenRonghua") d.eat
好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:
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 0@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 已经是个属性了, 那我能否给它赋值呢?试试吧
f.flight_status = 1
输出结果:AttributeError: can't set attribute
很显然,修改这个静态属性是不能这样改的,,此时 你需要写一个新方法, 对这个 flight_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 0@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 : 'cancle',
- 1 : 'arrived',
- 2 : 'departuresd'
- }
- print('\033[31; 1mHas changed the flight status to\033[0m', status_dic[status])@flight_status.deleter#删除静态属性def flight_status(self) : print("status got removed...") f = Flight('CA980') f.flight_status = 2 del f.flight_status
1.__doc__ 显示类的描述信息
- print(Flight.__doc__)类.__doc__ 2.__module__表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
- class Dog(object) : '''够累'''def __init__(self) : print(1) def __call__(self, *args, **kwargs) : print(args, kwargs) def __getitem__(self, item) : print('get item', item) return 22 print(Dog.__doc__) print(Dog.__module__) print(Dog.__class__)
输出结果: 够累 __main__ <class'type'>
3. __init__ 构造方法,通过类创建对象时,自动触发执行。
4.__del__
析构方法,当对象在内存中被释放时,自动触发执行。
5. __call__ 对象后面加括号,触发执行。
6. __dict__ 查看类或对象中的所有成员
- class Province: country = 'China'def __init__(self, name, count) : self.name = name self.count = count def func(self, *args, **kwargs) : print('fun') print(Province.__dict__.items()) m = Province('hebei', 100000) print(m.__dict__)
输出结果:
获取类的成员 {'__module__': '__main__', 'func': <function Province.func at 0x00000039DB60C400>, 'country': 'China', '__doc__': None, '__weakref__': <attribute'__weakref__'of'Province'objects>, '__dict__': <attribute'__dict__'of'Province'objects>, '__init__': <function Province.__init__ at 0x00000039DB60C378>}
获取对象的成员 {'name': 'hebei', 'count': 100000}
7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
- class Foo: def __str__(self) : return'alex li'obj = Foo() print(obj)输出结果:alex li 8.__getitem__、__setitem__、__delitem__用于索引操作,如字典。以上分别表示获取、设置、删除数据
- 9.__new__\__metaclass__
- class Foo(object) : def __init__(self, name) : self.name = name f = Foo("alex")
上述代码中,f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo 类本身也是一个对象,因为在 Python 中一切事物都是对象。
如果按照一切事物都是对象的理论:f 对象是通过执行 Foo 类的构造方法创建,那么 Foo 类对象应该也是通过执行某个类的 构造方法 创建。
- class Foo(object) : def __init__(self, name) : self.name = name f = Foo("alex") print(type(f)) print(type(Foo))
输出结果:
所以,f 对象是 Foo 类的一个实例,Foo 类对象是 type 类的一个实例,即:Foo 类对象 是通过 type 类的构造方法创建。
那么,创建类就可以有两种方式:
1. 普通方法:
class Foo:
def func(self):
print('hello')
- def func(self) : print'hello wupeiqi'Foo = type('Foo', (object, ), {'func': func
- })#type第一个参数:类名#type第二个参数:当前类的基类#type第三个参数:类的成员
类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type 类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个 type 类的派生类,从而查看 类 创建的过程。
- #_ * _coding: utf - 8_ * _ class MyType(type) : def __init__(self, child_cls, bases = None, dict = None) : print("--MyType init---", child_cls, bases, dict)#super(MyType, self).__init__(child_cls, bases, dict)#def __new__(cls, *args, **kwargs) : #print("in mytype new:", cls, args, kwargs)#type.__new__(cls) def __call__(self, *args, **kwargs) : print("in mytype call:", self, args, kwargs) obj = self.__new__(self, args, kwargs) self.__init__(obj, *args, **kwargs) class Foo(object, metaclass = MyType) : # in python3#__metaclass__ = MyType# in python2 def __init__(self, name) : self.name = name print("Foo ---init__") def __new__(cls, *args, **kwargs) : print("Foo --new--") return object.__new__(cls) def __call__(self, *args, **kwargs) : print("Foo --call--", args, kwargs)#第一阶段:解释器从上到下执行代码创建Foo类#第二阶段:通过Foo类创建obj对象obj = Foo("Alex")#print(obj.name)
类的生成 调用 顺序依次是 __new__ --> __call__ --> __init__
通过字符串映射或修改程序运行时的状态、属性、方法, 有以下 4 个方法 (反射是通过字符串的形式操作对象相关的成员。一切事物都是对象!!!)
WEB 框架,路由系统 li = {}
getattr getattr() 专门去某个地方获取其他内部的东西,可以使字符串的形式 以字符串的形式去某个对象中获取指定的属性
hasattr 判断获取的某个东西中是否有我们想要的东西,相当于容器 以字符串的形式判断某个对象中是否含有指定的属性。
setattr 以字符串的形式去 [某个对象] 中设定指定的属性
delattr 以字符串的形式去 [某个对象] 中删除指定的属性
以字符串的形式导入模块 __import__('time')
app.py
- from controller import account action = input(' >>> >>:') if (hasattr(account, action)) : func = getattr(account, action) result = func()
- else: result = '404'print(result)
account.py
- def login() : return'请输入密码'def logout() : return'跳回登陆页面'
- 异常处理
- 一、基本结构
- try: 代码块代码块。。。except Exception as e: 将错误信息写入日志二、复杂结构
- try: .........except....
- else: (与expect相反)...
- finally(肯定执行)...三、异常对象
- try: 代码块代码块。。。except Exception as e: #(e是Exceotion的对象)python内部将错误信息封装到e中将错误信息写入日志(e中封装了当前触发的错误信息)四、异常种类Exception能将所有的异常捕获。。。其他:只能处理某一种情况,精确的定位问题
- try: 代码块代码块。。。except Exception as e: 将错误信息写入日志其他错误类型继承Exception五、主动触发异常raise Exception('邮件发送失败')六、断言(异常处理的简写)#不会做记录告知别人,,这个条件必须满足,起到警示作用。assert七、自定义异常
- class HaitaoError(Exception) : def __init__(self, message) : self.msg = message super(HaitaoError, self).__init__(message) try: name = 'alex'
- if name != 'haitao': raise HaitaoError('you can not take my body') except HaitaoError as e: print(e, e.msg) except Exception as e: print(e, 111111)
基本模版展示:
- try: int('asdasdwqqws') li = ['11', '22'] li[1000] except IndexError as e: pass except ValueError as e: pass except Exception as e: pass
- else: print('a')
- finally: print('hello world')
- app.py
- #account / login#account / logout#home / index
- while True: action = input(' >>> >>:') m,
- n = action.split(' / ') try: module = __import__('controller. % s' % m, fromlist = True) if (hasattr(module, n)) : func = getattr(module, n) result = func()
- else: result = '404'except Exception as e: result = 500 print(result)
此例子,将动态倒入模块,异常处理,以及反射融合在一起。实例中所调用的模块,在上面的反射实例中有提到。
常用到的异常种类:
- AttributeError试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError输入 / 输出异常;基本上是无法打开文件ImportError无法引入模块或包;基本上是路径问题或名称错误IndentationError语法错误(的子类);代码没有正确对齐IndexError下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError试图访问字典里不存在的键KeyboardInterrupt Ctrl + C被按下NameError使用一个还未被赋予对象的变量SyntaxError Python代码非法,代码不能编译 (个人认为这是语法错误,写错了)TypeError传入对象类型与要求的不符合UnboundLocalError试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,导致你以为正在访问它ValueError传入一个调用者不期望的值,即使值的类型是正确的
- 写入具体的异常处理,只能具体处理某一种异常,当遇到其他类型的错误程序就会报异常,导致无法运行,所以还有万能异常处理。
socket 通常也称作 "套接字",用于描述 IP 地址和端口,是一个通信链的句柄,应用程序通常通过 "套接字" 向网络发出请求或者应答网络请求。
socket 起源于 Unix,而 Unix/Linux 基本哲学之一就是 "一切皆文件",对于文件用【打开】【读写】【关闭】模式来操作。socket 就是该模式的一个实现,socket 即是一种特殊的文件,一些 socket 函数就是对其进行的操作(读 / 写 IO、打开、关闭)
socket 和 file 的区别:
更多功能
sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
sk.bind(address)
s.bind(address) 将套接字绑定到地址。address 地址的格式取决于地址族。在 AF_INET 下,以元组(host,port)的形式表示地址。
sk.listen(backlog)
开始监听传入连接。backlog 指定在拒绝连接之前,可以挂起的最大连接数量。
backlog 等于 5,表示内核已经接到了连接请求,但服务器还没有调用 accept 进行处理的连接个数最大为 5 这个值不能无限大,因为要在内核中维护连接队列
sk.setblocking(bool)
是否阻塞(默认 True),如果设置 False,那么 accept 和 recv 时一旦无数据,则报错。
sk.accept()
接受连接并返回(conn,address), 其中 conn 是新的套接字对象,可以用来接收和发送数据。address 是连接客户端的地址。
接收 TCP 客户的连接(阻塞式)等待连接的到来
sk.connect(address)
连接到 address 处的套接字。一般,address 的格式为元组(hostname,port), 如果连接出错,返回 socket.error 错误。
sk.connect_ex(address)
同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061
sk.close()
关闭套接字
sk.recv(bufsize[,flag])
接受套接字的数据。数据以字符串形式返回,bufsize 指定最多可以接收的数量。flag 提供有关消息的其他信息,通常可以忽略。
sk.recvfrom(bufsize[.flag])
与 recv() 类似,但返回值是(data,address)。其中 data 是包含接收数据的字符串,address 是发送数据的套接字地址。
sk.send(string[,flag])
将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于 string 的字节大小。即:可能未将指定内容全部发送。
sk.sendall(string[,flag])
将 string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常。
内部通过递归调用 send,将所有内容发送出去。
sk.sendto(string[,flag],address)
将数据发送到套接字,address 是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于 UDP 协议。
sk.settimeout(timeout)
设置套接字操作的超时期,timeout 是一个浮点数,单位是秒。值为 None 表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待 5s )
sk.getpeername()
返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。
sk.getsockname()
返回套接字自己的地址。通常是一个元组 (ipaddr,port)
sk.fileno()
套接字的文件描述符
简单的 socket 交互
socket_server
- import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#生成一个socket实例server.bind(('0.0.0.0', 8000)) server.listen(5) print('start to listen'.center(20, ' - ')) while True: conn,
- client_addr = server.accept()#accept会返回两个值,conn就是实际建立的连接,service相当于整个服务,想和某个连接的通信,只能是通过conn,每一个小连接时conn print(conn, client_addr) while True: data = conn.recv(1024)#收数据,本次消息要收多少内容1024字节print('recv from cli', data) conn.send(b'got you msg')#socket发送必须是字节格式
socket_client
- import socket client = socket.socket() client.connect(('localhost', 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)
客户端与服务端交互
服务端
- import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 8000)) server.listen(5) conn,
- client_addr = server.accept() print(conn, client_addr) while True: data = conn.recv(1024) print('rece from cli: ', data) conn.send(b'got your msg')
客户端
- import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('localhost', 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)
这样的结果就是当再有客户端请求时,可以建立连接,但是无法交互,客户端也会卡住,当我们断开第一个客户端是,服务端也会断开,所以,我们的需要在小循环断开后继续建立新的连接
服务端
- import socket server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 8000)) server.listen(5) while True: conn,
- client_addr = server.accept() print(conn, client_addr) while True: try: data = conn.recv(1024) print('rece from cli: ', data) conn.send(b'got your msg') except ConnectionResetError as e: print(e) break
这里断开是会报连接错误,只要把这个错误抓住就行了。(断开后就无法执行 data = conn.reve(1024), 所以会报错)
通过 socket,实现 ssh 连接。
客户端 (程序在 linux 环境)
- # ! /usr/bin / env python# ! -*-coding: utf - 8 - *-import socket import subprocess server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 8000)) server.listen(5) while True: conn,
- client_addr = server.accept() print(conn, client_addr) while True: try: data = conn.recv(1024) print('rece from cli: ', data) res = subprocess.Popen(data, shell = True, stdout = subprocess.PIPE) conn.send(res.stdout.read()) except ConnectionResetError as e: print(e)
客户端
- import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('192.168.1.198', 8000)) while True: msg = input(' >> :').strip() if len(msg) == 0 : continue client.send(msg.encode()) print('send', msg) data = client.recv(1024) print(data.decode())
socket 发送信息的存在缓存中,如果满了就一起发送出去。
但是如果执行动态命令或者命令返回的结果很长,这样就不能一次给我们返回结果,或者是返回的结果不是我们想要的,那么,改如何去解决呢。
通过服务端去告知客户端要发送数据的长度,然后客户端通过自己能接受最大字符串进行循环接受,然后统一打印。
服务端
- # ! /usr/bin / env python# ! -*-coding: utf - 8 - *-import socket import subprocess server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('0.0.0.0', 8000)) server.listen(5) while True: conn,
- client_addr = server.accept() print(conn, client_addr) while True: try: data = conn.recv(1024) print('rece from cli: ', data) res = subprocess.Popen(data, shell = True, stdout = subprocess.PIPE) res1 = res.stdout.read() conn.send(str(len(res1)).encode()) print('--res len: ', len(res1)) conn.send(res1) except ConnectionResetError as e: print(e) break
客户端
- import socket client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect(('192.168.1.198', 8000)) while True: msg = input(' >> :').strip() if len(msg) == 0 : continue client.send(msg.encode()) print('send', msg) data = client.recv(1024) print('res: ', data.decode()) total_size = int(data.decode())#和总长度比较received_size = 0 res2 = b''
- while received_size < total_size: d = client.recv(1024) res2 += d received_size += len(d)# += len(d)防止最后不够1024 print('---------rece done') print(res2.decode())
来源: http://www.bubuko.com/infodetail-1857838.html