申明:本文内容主要转自Alex老师的博客,仅供学习记录!
静态方法
只是名义上归类管理,实际上在静态方法里访问不了类实例中的任何属性
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
1 class Dog(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @staticmethod #把eat方法变为静态方法 7 def eat(self): 8 print("%s is eating" % self.name) 9 10 11 12 d = Dog("ChenRonghua") 13 d.eat()
上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
1 Traceback (most recent call last): 2 File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/静态方法.py", line 17, in <module> 3 d.eat() 4 TypeError: eat() missing 1 required positional argument: 'self'
想让上面的代码可以正常工作有两种办法
1. 调用时主动传递实例本身给eat方法,即d.eat(d)
2. 在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
1 class Dog(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @staticmethod 7 def eat(): 8 print(" is eating") 9 10 11 12 d = Dog("ChenRonghua") 13 d.eat()
类方法:
只能访问类变量,不能访问实例变量
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是, 类方法只能访问类变量,不能访问实例变量
1 class Dog(object): 2 def __init__(self,name): 3 self.name = name 4 5 @classmethod 6 def eat(self): 7 print("%s is eating" % self.name) 8 9 10 11 d = Dog("ChenRonghua") 12 d.eat()
执行报错如下,说Dog没有name属性,因为name是个实例变量,类方法是不能访问实例变量的
1 Traceback (most recent call last): 2 File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 16, in <module> 3 d.eat() 4 File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/类方法.py", line 11, in eat 5 print("%s is eating" % self.name) 6 AttributeError: type object 'Dog' has no attribute 'name'
此时可以定义一个类变量,也叫name,看下执行效果
1 class Dog(object): 2 name = "我是类变量" 3 def __init__(self,name): 4 self.name = name 5 6 @classmethod 7 def eat(self): 8 print("%s is eating" % self.name) 9 10 11 12 d = Dog("ChenRonghua") 13 d.eat() 14 15 16 #执行结果 17 18 我是类变量 is eating
属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
1 class Dog(object): 2 3 def __init__(self,name): 4 self.name = name 5 6 @property 7 def eat(self): 8 print(" %s is eating" %self.name) 9 10 11 d = Dog("ChenRonghua") 12 d.eat()
调用会出以下错误, 说NoneType is not callable, 因为eat此时已经变成一个静态属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
1 Traceback (most recent call last): 2 ChenRonghua is eating 3 File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 16, in <module> 4 d.eat() 5 TypeError: 'NoneType' object is not callable
正常调用如下
d = Dog("ChenRonghua") d.eat 输出 ChenRonghua is eating
好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:
1. 连接航空公司API查询
2. 对查询结果进行解析
3. 返回结果给你的用户
因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?
1 class Flight(object): 2 def __init__(self,name): 3 self.flight_name = name 4 5 6 def checking_status(self): 7 print("checking flight %s status " % self.flight_name) 8 return 1 9 10 @property 11 def flight_status(self): 12 status = self.checking_status() 13 if status == 0 : 14 print("flight got canceled...") 15 elif status == 1 : 16 print("flight is arrived...") 17 elif status == 2: 18 print("flight has departured already...") 19 else: 20 print("cannot confirm the flight status...,please check later") 21 22 23 f = Flight("CA980") 24 f.flight_status
cool , 那现在我只能查询航班状态, 既然这个flight_status已经是个属性了, 那我能否给它赋值呢?试试吧
1 f = Flight("CA980") 2 f.flight_status 3 f.flight_status = 2
输出, 说不能更改这个属性,我擦。。。。,怎么办怎么办。。。
1 checking flight CA980 status 2 flight is arrived... 3 Traceback (most recent call last): 4 File "/Users/jieli/PycharmProjects/python基础/自动化day7面向对象高级/属性方法.py", line 58, in <module> 5 f.flight_status = 2 6 AttributeError: can't set attribute
当然可以改, 不过需要通过@proerty.setter装饰器再装饰一下,此时 你需要写一个新方法, 对这个flight_status进行更改。
1 class Flight(object): 2 def __init__(self,name): 3 self.flight_name = name 4 5 6 def checking_status(self): 7 print("checking flight %s status " % self.flight_name) 8 return 1 9 10 11 @property 12 def flight_status(self): 13 status = self.checking_status() 14 if status == 0 : 15 print("flight got canceled...") 16 elif status == 1 : 17 print("flight is arrived...") 18 elif status == 2: 19 print("flight has departured already...") 20 else: 21 print("cannot confirm the flight status...,please check later") 22 23 @flight_status.setter #修改 24 def flight_status(self,status): 25 status_dic = { 26 : "canceled", 27 :"arrived", 28 : "departured" 29 } 30 print("\033[31;1mHas changed the flight status to \033[0m",status_dic.get(status) ) 31 32 @flight_status.deleter #删除 33 def flight_status(self): 34 print("status got removed...") 35 36 f = Flight("CA980") 37 f.flight_status 38 f.flight_status = 2 #触发@flight_status.setter 39 del f.flight_status #触发@flight_status.deleter
注意以上代码里还写了一个@flight_status.deleter, 是允许可以将这个属性删除
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()
hasattr(obj,name_str): 判断一个对象obj里是否有相应的name_str字符串的属性或方法
getattr(obj,name_str): 根据字符串去获取obj对象里的对应的方法的内存地址或属性值
setattr(obj,'y',z): 修改属性值或方法 is equivalent to ''x.y = v''
delattr(obj,name_str) 删除方法或属性
1 def bark(self): 2 print("%s is barking..."%self.name) 3 4 class Dog(object): 5 def __init__(self,name): 6 self.name = name 7 8 def eat(self,food): 9 print("%s is eating...%s" %(self.name,food)) 10 11 d = Dog("Wangwei") 12 choice = input(">>") 13 #①print(hasattr(d,choice)) #判断对象里是否有属性或方法存在 14 #②print(getattr(d,choice)) #得到对象下某个属性或方法的内存地址或属性值 15 #③ 给对象加个属性 16 if(hasattr(d,choice)): 17 v1 = getattr(d,choice) 18 print(v1) 19 else: 20 setattr(d,choice,None) #不知道用户输入是什么,传值None 21 #print(d.choice) #Error choice是个字符串 22 v2 = getattr(d,choice) 23 print(v2) 24 25 #④修改对象方法 26 if(hasattr(d,choice)): 27 func = getattr(d,choice) 28 func("面包") 29 else: 30 setattr(d,choice,bark) #假设输入talk,相当于d.talk=bark #把bark内存地址赋值给d.talk 31 #d.talk() #不能这样写,因为你不知道用户输入的是什么,必须动态去获取 32 v = getattr(d,choice) 33 v(d)
异常处理
参考 http://www.cnblogs.com/wupeiqi/articles/5017742.html
1、异常处理
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是显示一个提示的页面,通俗来说就是不让用户看见大黄页!!!
try: pass except Exception,ex: pass 需求:将用户输入的两
2、异常种类
python中的异常种类非常多,每个异常专门用于处理某一项异常!!!
AttributeError 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x IOError 输入/输出异常;基本上是无法打开文件 ImportError 无法引入模块或包;基本上是路径问题或名称错误 IndentationError 语法错误(的子类) ;代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访问字典里不存在的键 KeyboardInterrupt Ctrl+C被按下 NameError 使用一个还未被赋予对象的变量 SyntaxError Python代码非法,代码不能编译 TypeError 传入对象类型与要求的不符合 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量, 导致你以为正在访问它 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
更多异常
l1 = ["wusong", 'ximenqing'] try: l1[5] except IndexError, e: print e
dic = {'k1':'v1'} try: dic['k2'] except KeyError, e: print e
s1 = 'hello' try: int(s1) except ValueError, e: print e
对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。
1 # 未捕获到异常,程序直接报错 2 3 s1 = 'hello' 4 try: 5 int(s1) 6 except IndexError as e: 7 print e
所以,写程序时需要考虑到try代码块中可能出现的任何异常,可以这样写:
1 s1 = 'hello' 2 try: 3 int(s1) 4 except IndexError as e: 5 print e 6 except KeyError as e: 7 print e 8 except ValueError as e: 9 print e
万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常,即:
1 s1 = 'hello' 2 try: 3 int(s1) 4 except Exception as e: 5 print e
接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!
答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。
1 s1 = 'hello' 2 try: 3 int(s1) 4 except KeyError as e: 5 print '键错误' 6 except IndexError as e: 7 print '索引错误' 8 except Exception as e: 9 print '错误'
3、异常其他结构
1 try: 2 # 主代码块 3 pass 4 except KeyError as e: 5 # 异常时,执行该块 6 pass 7 else: 8 # 主代码块执行完,执行该块 9 pass 10 finally: 11 # 无论异常与否,最终执行该块 12 pass
4、主动触发异常
1 try: 2 raise Exception('错误了。。。') 3 except Exception as e: 4 print e
5、自定义异常
1 class WupeiqiException(Exception): 2 3 def __init__(self, msg): 4 self.message = msg 5 6 def __str__(self): 7 return self.message 8 9 try: 10 raise WupeiqiException('我的异常') 11 except WupeiqiException as e: 12 print e
6、断言
1 # assert 条件 2 3 assert 1 == 1 4 5 assert 1 == 2
Socket
参考:http://www.cnblogs.com/wupeiqi/articles/5040823.html
对计算机通信底层的一些封装(编程只关注要发送什么,服务器接受什么,具体发送传输细节由socket封装好)
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。
socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭)
1 import socket 2 client = socket.socket() #声明socket类型,同时生成socket连接对象 3 client.connect(('localhost',6969)) #连接到服务器 4 client.send(b"hello world!") #发数据 5 data = client.recv(1024) #接受服务器返回,必须制定接受大小(字节) 6 print(data) 7 client.close()
1 import socket 2 server = socket.socket() 3 server.bind(('localhost',6969)) #绑定要监听端口 4 server.listen() #监听端口 5 6 print("等待接听电话") 7 conn,addr = server.accept() #等待电话进来 conn就是客户端连过来而在服务器端为其生成的一个连接实例 8 print("电话来了") 9 data = conn.recv(1024) 10 print("recv:",data) 11 server.send(data.upper()) 12 13 server.close()
如果需要客户端和服务端频繁通信呢?(类似于电话两端打通后就持续通话)如何实现?
客户端:
1 import socket 2 client = socket.socket() #声明socket类型,同时生成socket连接对象 3 client.connect(('localhost',6969)) #连接到服务器 4 while True: 5 client_msg = input("输入内容:>>").strip() 6 client.send(client_msg.encode("utf-8")) #发数据 7 data = client.recv(1024) #接受服务器返回,必须制定接受大小(字节) 8 print("recv:",data.decode()) 9 client.close()
服务端:
1 import socket 2 server = socket.socket() 3 server.bind(('localhost',6969)) #绑定要监听端口 4 server.listen() #监听端口 5 6 print("等待接听电话") 7 while True: 8 conn,addr = server.accept() #等待电话进来 conn就是客户端连过来而在服务器端为其生成的一个连接实例 9 print(conn,addr) 10 print("电话来了") 11 data = conn.recv(1024) 12 print("recv:",data) 13 conn.send(data.upper()) 14 15 server.close()
上面代码演示:
当客户端发送一次消息后,服务器接受并返回,当客户端再次发送,就会卡主,服务端无响应。因为服务端只接受了一次conn,这时服务端需要等待另一个电话进来,所以服务端代码需要修改:
---------------------------------------------------------------
服务端修改:
1 import socket 2 server = socket.socket() 3 server.bind(('localhost',6969)) #绑定要监听端口 4 server.listen() #监听端口 5 6 print("等待接听电话") 7 conn, addr = server.accept() # 等待电话进来 conn就是客户端连过来而在服务器端为其生成的一个连接实例 8 print(conn, addr) 9 print("电话来了") 10 while True: 11 data = conn.recv(1024) 12 print("recv:",data) 13 conn.send(data.upper()) 14 15 server.close()
客户端:
服务端:
这时又出现一个问题,当在linux上客户端断开连接,服务端接受不到数据,就会进入死循环,该如何解决?我的本意是这个客户端断开了,可以接受下一个(打电话时另一个电话进来,我可以接听另一个电话)
解决:加了两个循环,一个循环是和客户不断发送接受数据,这个客户如果断了,又回到大循环,大循环又开始接受新电话
1 import socket 2 server = socket.socket() 3 server.bind(('localhost',6969)) #绑定要监听端口 4 server.listen() #监听端口 5 6 print("等待接听电话") 7 while True: 8 conn, addr = server.accept() # 等待电话进来 conn就是客户端连过来而在服务器端为其生成的一个连接实例 9 print(conn, addr) 10 print("电话来了") 11 while True: 12 data = conn.recv(1024) 13 print("recv:",data) 14 if not data: 15 print("client has lost...") 16 break 17 conn.send(data.upper()) 18 19 server.close()