一、面向对象编程进阶
静态方法只是名义上归类管理,实际上在静态方法里访问不了类或实例中的任何属性
1 class Dog(object): 2 def __init__(self,name): 3 self.name=name 4 @staticmethod #实际上跟类没什么关系了,调用时用到类名 5 def eat(): 6 print("s is eating %s"%("dd")) 7 d=Dog("ChenRonghua") 8 d.eat()
类方法只能访问类变量,不能访问实例变量
1 class Dog(object): 2 #n=333 3 name="huazai" 4 def __init__(self,name): 5 self.name=name 6 self.n=333 7 #@staticmethod #实际上跟类没什么关系了,调用时用到类名 8 @classmethod 9 def eat(self): 10 print("%s is eating %s"%(self.name,"dd")) 11 d=Dog("ChenRonghua") 12 d.eat()
属性方法把一个方法变成一个静态属性(隐藏实现细节)
1 class Dog(object): 2 def __init__(self,name): 3 self.name=name 4 self.__food=None 5 #@staticmethod #实际上跟类没什么关系了,调用时用到类名 6 #@classmethod 7 @property #attribute 8 def eat(self): 9 print("%s is eating %s"%(self.name,self.__food)) 10 @eat.setter #修改 11 def eat(self,food): 12 print("set to food:",food) 13 self.__food=food 14 @eat.deleter #删除 15 def eat(self): 16 del self.__food 17 print("删完了") 18 d=Dog("ChenRonghua") 19 d.eat 20 d.eat="baozi" 21 d.eat 22 del d.eat
好吧,把一个方法变成静态属性有什么卵用呢?既然想要静态变量,那直接定义成一个静态变量不就得了么?well, 以后你会需到很多场景是不能简单通过 定义 静态属性来实现的, 比如 ,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是已经飞走了, 想知道这种状态你必须经历以下几步:
1. 连接航空公司API查询
2. 对查询结果进行解析
3. 返回结果给你的用户
因此这个status属性的值是一系列动作后才得到的结果,所以你每次调用时,其实它都要经过一系列的动作才返回你结果,但这些动作过程不需要用户关心, 用户只需要调用这个属性就可以,明白 了么?
1 class Flight(object): 2 def __init__(self,name): 3 self.flight_name = name 4 def checking_status(self): 5 print("checking flight %s status " % self.flight_name) 6 return 2 7 @property 8 def flight_status(self): 9 status = self.checking_status() 10 if status == 0 : 11 print("flight got canceled...") 12 elif status == 1 : 13 print("flight is arrived...") 14 elif status == 2: 15 print("flight has departured already...") 16 else: 17 print("cannot confirm the flight status...,please check later") 18 @flight_status.setter 19 def flight_status(self,status): 20 print("flight %s has changed status to %s"%(self.flight_name,status)) 21 22 23 f = Flight("CA980") 24 f.flight_status 25 f.flight_status=0
(一)、类的特殊成员方法
1. __doc__ 表示类的描述信息
1 class Foo: 2 """ 描述类信息 """ 3 def func(self): 4 pass 5 print(Foo.__doc__)# 输出:描述类信息
2. __module__ 和 __class__
1 class C: 2 def __init__(self): 3 self.name = 'wupeiqi'
1 from lib.aa import C 2 obj = C() 3 print( obj.__module__) # 输出 lib.aa,即:输出模块 4 print(obj.__class__) # 输出 lib.aa.C,即:输出类
3. __init__ 构造方法,通过类创建对象时,自动触发执行。
4.__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
5. __call__ 对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
1 class Foo: 2 def __init__(self): 3 pass 4 5 def __call__(self, *args, **kwargs): 6 print('__call__',args,kwargs) 7 8 obj = Foo() # 执行 __init__ 9 obj(1,2,3,name=333) # 执行 __call__
6. __dict__ 查看类或对象中的所有成员
1 class Dog(object): 2 def __init__(self,name): 3 self.name=name 4 self.__food=None 5 #@staticmethod #实际上跟类没什么关系了,调用时用到类名 6 #@classmethod 7 @property #attribute 8 def eat(self): 9 print("%s is eating %s"%(self.name,self.__food)) 10 @eat.setter #修改 11 def eat(self,food): 12 print("set to food:",food) 13 self.__food=food 14 @eat.deleter #删除 15 def eat(self): 16 del self.__food 17 print("删完了") 18 print(WindowsError.__dict__)#打印类里的所有属性,不包括实例属性 19 d=Dog("ChenRonghua") 20 print(d.__dict__)#打印所有实例属性,不包括类属性
7.__str__ 如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
1 class Foo: 2 def __str__(self): 3 return 'alex li' 4 obj = Foo() 5 print(obj) 6 # 输出:alex li
8.__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
1 class Foo(object): 2 def __init__(self): 3 self.data={} 4 def __getitem__(self, key): 5 print('__getitem__', key) 6 return self.data.get(key) 7 def __setitem__(self, key, value): 8 print('__setitem__', key, value) 9 self.data[key]=value 10 def __delitem__(self, key): 11 print('__delitem__', key) 12 obj = Foo() 13 obj["name"]="alex"# 自动触发执行 __setitem__ 14 print(obj["name"]) # 自动触发执行 __getitem__ 15 print(obj.data) 16 del obj["name"] #不是真正的删除 17 print(obj["name"])
9. __new__ \ __metaclass__
1 # class Foo(object): 2 # def __init__(self, name): 3 # self.name = name 4 # f = Foo("alex") 5 # print(type(f)) 6 # print(type(Foo)) #来自于type 7 8 9 def func(self): 10 print('hello %s'%self.name) 11 def __init__(self,name,age): 12 self.name=name 13 self.age=age 14 Foo = type('Foo',(object,),{'func':func,"__init__":__init__})#boject,表示元组 15 16 # type第一个参数:类名 17 # type第二个参数:当前类的基类 18 # type第三个参数:类的成员 19 f=Foo("chrn",22) 20 f.func() 21 print(type(Foo))
上述代码中,f 是通过 Foo 类实例化的对象,其实,不仅 f 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:f对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
所以,f对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:普通方式和特殊方式
So ,孩子记住,类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
1 class MyType(type): 2 def __init__(self,*args,**kwargs): 3 print("Mytype __init__",*args,**kwargs) 4 def __call__(self, *args, **kwargs): 5 print("Mytype __call__", *args, **kwargs) 6 obj = self.__new__(self) 7 print("obj ",obj,*args, **kwargs) 8 print(self) 9 self.__init__(obj,*args, **kwargs) 10 return obj 11 def __new__(cls, *args, **kwargs): 12 print("Mytype __new__",*args,**kwargs) 13 return type.__new__(cls, *args, **kwargs) 14 print('here...') 15 class Foo(object,metaclass=MyType): 16 def __init__(self,name): 17 self.name = name 18 print("Foo __init__") 19 def __new__(cls, *args, **kwargs): 20 print("Foo __new__",cls, *args, **kwargs) 21 return object.__new__(cls) #继承父类的__new__方法 22 f = Foo("Alex") 23 print("f",f) 24 print("fname",f.name)
类的生成 调用 顺序依次是 __new__ --> __init__ --> __call__
metaclass 详解文章:http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python 得票最高那个答案写的非常好
(二)、反射
hasattr(obj,name_str),判断一个对象obj里是否有对应的name_str字符串的方法
getattr(obj,name_str),根据字符串去获取obj对象里的对应的方法的内存地址
setattr(obj,"y",z), is equivalent to ``obj.y = v''
delattr(obj,"y") ,is equivalent to ``del obj.y''
1 def bulk(self): 2 print("%s is yelling..."%self.name) 3 class Dog(object): 4 def __init__(self,name): 5 self.name=name 6 def eat(self,food): 7 print("%s is eating %s"%(self.name,food)) 8 9 d=Dog("NiuHanYang") 10 choice=input(">>:").strip() 11 # print(hasattr(d,choice)) 12 # print(getattr(d,choice)) 13 if hasattr(d,choice): 14 15 #func=getattr(d,choice) 16 #func("chenronghua") 17 18 # attr=getattr(d,choice)#没有也一样 19 # setattr(d,choice,"Ronghua") 20 21 delattr(d.choice) 22 else: 23 setattr(d,choice,bulk) #d.talk=bulk 24 func=getattr(d,choice) 25 func(d) 26 # setattr(d,choice,22) 27 # print(getattr(d,choice)) 28 print(d.name)
(三)、异常处理
1、异常基础
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大黄页!!!
try:
code
except (Error1,Error2) as e:
print(e)
except Exception:抓住所有错误,不建议一开始就用
1 names=['alex',"jack"] 2 data={} 3 try: 4 open("tes.txt") 5 # a=1 6 # print(a) 7 except (KeyError,IndexError) as e: 8 print("没有这个key",e) #e就是错误的详细信息 9 except Exception as e: 10 print("未知错误",e) 11 else: #没有错误,执行这个 12 print("一切正常") 13 finally: 14 print("不管有没有错,都执行")
2、异常种类
python中的异常种类非常多,每个异常专门用于处理某一项异常!!!
1 AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
2 IOError 输入/输出异常;基本上是无法打开文件
3 ImportError 无法引入模块或包;基本上是路径问题或名称错误
4 IndentationError 语法错误(的子类) ;代码没有正确对齐
5 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]
6 KeyError 试图访问字典里不存在的键
7 KeyboardInterrupt Ctrl+C被按下
8 NameError 使用一个还未被赋予对象的变量
9 SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
10 TypeError 传入对象类型与要求的不符合
11 UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
12 导致你以为正在访问它
13 ValueError 传入一个调用者不期望的值,即使值的类型是正确的
万能异常 在python的异常中,有一个万能异常:Exception,他可以捕获任意异常。
接下来你可能要问了,既然有这个万能异常,其他异常是不是就可以忽略了!
答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。
1 s1 = 'hello' 2 try: 3 int(s1) 4 except KeyError,e: 5 print '键错误' 6 except IndexError,e: 7 print '索引错误' 8 except Exception, e: 9 print '错误'
3、异常其他结构
1 try:
2 # 主代码块
3 pass
4 except KeyError,e:
5 # 异常时,执行该块
6 pass
7 else:
8 # 主代码块执行完,执行该块
9 pass
10 finally:
11 # 无论异常与否,最终执行该块
12 pass
4、主动触发异常
try:
raise Exception('错误了。。。')
except Exception as e:
print (e)
5、自定义异常
1 class AlexException(Exception):
2 def __init__(self, msg):
3 self.message = msg
4 # def __str__(self):
5 # return "sfadad"
6 try:
7 raise AlexException('数据库连不上') #触发异常
8 except AlexException as e:
9 print(e)
6、断言
1 # assert 条件
2
3 assert 1 == 1
4
5 assert 1 == 2
参考 http://www.cnblogs.com/wupeiqi/articles/5017742.html
二、Socket 编程
协议类型就叫地址簇
进程之间默认不可通信
Socket Families(地址簇)
socket.
AF_UNIX unix本机进程间通信
socket.
AF_INET IPV4
socket.
AF_INET6 IPV6
Socket Types
socket.
SOCK_STREAM #for tcp
socket.
SOCK_DGRAM #for udp
socket.
SOCK_RAW #原始套接字,普通的套接字无法处理ICMP、IGMP等网络报文,而SOCK_RAW可以;其次,SOCK_RAW也可以处理特殊的IPv4报文;此外,利用原始套接字,可以通过IP_HDRINCL套接字选项由用户构造IP头。(伪造ip地址,洪水攻击)
socket.
SOCK_RDM #是一种可靠的UDP形式,即保证交付数据报但不保证顺序。SOCK_RAM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.
SOCK_SEQPACKET #废弃了
客户端
1 #客户端 2 import socket 3 client=socket.socket() #声明socket类型,同时生成socket连接对象 4 client.connect(("localhost",6969)) 5 client.send("我的a".encode("utf-8")) 6 data=client.recv(1024) 7 print("recv:",data.decode()) 8 client.close()
服务器端
1 #服务器端 2 import socket 3 server=socket.socket() 4 server.bind(("localhost",6969)) #绑定要监听的端口 5 server.listen() #监听 6 print("我要开始等电话了") 7 conn,addr=server.accept() #等电话打进来 8 #conn就是客户端连过来而在服务器端为其生成的一个连接实例 9 print(conn,addr) 10 11 print("电话来了") 12 data=conn.recv(1024) 13 print("recv:",data) 14 conn.send(data.upper()) 15 16 server.close()
多用户客户端
1 #客户端 2 import socket 3 client=socket.socket() #声明socket类型,同时生成socket连接对象 4 client.connect(("localhost",6969)) 5 6 while True: 7 msg=input(">>:").strip() 8 if len(msg)==0: 9 continue 10 client.send(msg.encode("utf-8"))#如果没有上面的if,不能send"空",会卡住 11 data=client.recv(1024)#recv大小有限制 12 print("recv:",data.decode()) 13 client.close()
多用户服务器端
1 #服务器端 2 import os 3 import socket 4 server=socket.socket() 5 server.bind(("localhost",6969)) #绑定要监听的端口 6 server.listen(5) #监听,最多可以挂起..个链接(排队) 7 print("我要开始等电话了") 8 while True: 9 conn,addr = server.accept() # 等电话打进来 10 # conn就是客户端连过来而在服务器端为其生成的一个连接实例 11 print(conn, addr) 12 print("电话来了") 13 while True: 14 data=conn.recv(1024)#服务器端接收的大小也有限制 15 print("recv:",data) 16 if not data: 17 print("client has lost") 18 break 19 res=os.popen(data).read 20 conn.send(res)#conn.sendall(data)循环send,send大小也有限制(缓冲区的大小),与系统有关 21 server.close()
windows中不好使...
socket概念
socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。 我们知道网络 通信 都 是基于 ip+port 方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果 把一个公司比做一台电脑 ,那公司的总机号码就相当于ip地址, 每个员工的分机号就相当于端口, 你想找公司某个人,必须 先打电话到总机,然后再转分机 。
建立一个socket必须至少有2端, 一个服务端,一个客户端, 服务端被动等待并接收请求,客户端主动发起请求, 连接建立之后,双方可以互发数据