面向对象高级语法部分
经典类vs新式类
1 、静态方法、类方法、属性方法
1.1静态方法 @staticmethod
只是名义上归类管理,实际上在静态方法里访问不了类或实例中的类的任何方法
通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,其变为普通的方法,可以在实例化后直接调用,并且在方法里可以通过self,调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没有什么关系了,它唯一的关联就是需要通过类名来调用这个方法。
1.2类方法 @classmethod
只能访问类变量,不能访问实例变量
出错
可以访问
1.3属性方法 @property
把一个方法变成一个静态属性
1.3.1删除
1处是修改
2处是删除
1.3.2用途
以后你就会需要很多场景是不能简单通过定义静态属性来实现的,比如,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是飞走了。想知道这种状态你必须经历以下几步:
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")
@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
2、类的特殊方法
2.1__doc__ 表示类的描述信息
2.2_module_ 和 _class _
___module _表示当前操作的对象在那个模块
_class _ 表示当前操作的对象的类是什么
2.3_init__ 构造方法,通过类创建对象时,自动触发执行。
2.4 _del_析构方法 当对象在内存中被释放时,自动触发执行
注:此方法一般无需定义,因为python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
2.5 _call_对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象= 类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象() 或者类()()
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__')
obj = Foo() #执行__init__
obj() #执行__call__
还可以传入参数
class Foo:
def __init__(self):
pass
def __call__(self, *args, **kwargs):
print('__call__',args,kwargs)
obj = Foo() #执行__init__
obj(124,name=24) #执行__call__
如何判断一个对象能是否能被调用,可以用callable()函数,若能被调用,则返回Ture
print(callable(obj))
结果:True
2.6__dict__ 查看类或对象中的所有成员
通过类调用,打印类中的所有属性,不包括实例属性
通过对象调用,打印所有的实例属性,不包括类属性
2.7 __ str__
如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值。
2.8__getitem__ setitem delitem
用于索引操作,如字典。以上分别表示获取、设置、删除数据
可以用于自己封装一个字典
class Foo(object):
def __init__(self):
self.name ={}
def __getitem__(self, item):
print('__getitem__',item)
def __setitem__(self, key, value):
print('__setitem__',key,value)
self.name[key] = value
def __delitem__(self, key):
print('__delitem__',key)
obj = Foo()
result = obj['K1']
obj['k2'] = 'alex'
print(obj.name)
del obj['k1']
2.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类的一个实例,即:Foo类对象是通过type类的构造方法创建。
2.9.1 类的两种创建方式
a)普通类
class Foo(object):
def func(self):
print("hello aliex")
b)特殊方式
def func(self):
print("hello alex")
Foo = type('Foo',(object,),{'func':func})
type 第一个参数:类名
type 第二个参数:当前类的基类(元组)
type第三个参数:类的成员
带有初始化函数的:
def func(self):
print("hello alex")
def __init__(self,name,age):
self.name = name
self.age = age
Foo = type('Foo',(object,),{'func':func,'__init__':__init__})
f= Foo('jack',22)
类是由type类实例化产生的
类默认是由type类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 metaclasss,其用来表示该类由谁来实例化创建,所以,我们可以为__mataclass__设置有个type类的派生类,从而查看类的创建的过程
__ new__()函数执行先于__init__()函数,其中__new__()函数是用来创建实例的,可以不写(大多数不用写)若是写的话,也就是重构的__new__()函数,需要继承父类的这个函数的
class MyType(type):
def __init__(self,*args,**kwargs):
print("Mytype __init__",*args,**kwargs)
def __call__(self, *args, **kwargs):
print("Mytype __call__", *args, **kwargs)
obj = self.__new__(self)
print("obj ",obj,*args, **kwargs)
print(self)
self.__init__(obj,*args, **kwargs)
return obj
def __new__(cls, *args, **kwargs):
print("Mytype __new__",*args,**kwargs)
return type.__new__(cls, *args, **kwargs)
print('here...')
class Foo(obj ect,metaclass=MyType):
def __init__(self,name):
self.name = name
print("Foo __init__")
def __new__(cls, *args, **kwargs):
print("Foo __new__",cls, *args, **kwargs)
return object.__new__(cls) #去继承父类的__new__()函数,必须是返回
f = Foo("Alex")
print("f",f)
print("fname",f.name)
此代码执行过程
其中__new__()函数 是被(MyType)__ call__()函数调用执行的
3、反射
hasattr(obj,name_str) ,判断一个对象里是否有对应的name_str字符串的方法,有的话返回True
getattr(obj,name_str),根据字符串去获取obj对象里的对应的方法的内存地址
setattr(obj,’y’,z),is equivalent to x.y=z
delattr(obj,name_str),删掉对象里的name_str字符串的方法或者属性
class Foo(object):
def __init__(self):
self.name = 'alex'
def func(self):
return 'func'
obj = Foo()
# #### 检查是否含有成员 ####
hasattr(obj, 'name')
hasattr(obj, 'func')
# #### 获取成员 ####
getattr(obj, 'name')
getattr(obj, 'func')
# #### 设置成员 ####
setattr(obj, 'age', 18)
setattr(obj, 'show', lambda num: num + 1)
# #### 删除成员 ####
delattr(obj, 'name')
delattr(obj, 'func')
可以实现内存的动态分配:
4、异常处理
结构:
try:
data
except (Error1,Error2) as e:
pass
except Exception as e: #抓所有错误 ,不建议开始使用,用在最后,表示未知错误
data = {}
try:
data["name"]
except KeyError as e:
print("没有这个key",e)
except KeyError as e: 这个e是获取错误的信息
name=[1,2]
data = {}
try:
name[3]
data["name"]
except (KeyError,IndexError) as e:
print("没有这个key",e)
name=[1,2]
data = {}
try:
name[3]
data["name"]
except KeyError as e:
print("没有这个key",e)
except IndexError as e:
print("列表",e)
except Exception as e:
print("出现未知错误",e)
else:
print("一切正常")
finally:
print("不管有没有错,都执行")
4.1常见的错误类型
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)ValueError 传入一个调用者不期望的值,即使值的类型是正确的
4.2自己定义异常
class AlexException(Exception):
def __init__(self,name):
self.name =name
#def __str__(self):
#return self.name
try:
raise AlexException("数据库连不上")
except AlexException as e:
print(e)
4.3 断言
assert
5、 Socket开发基础
5.1计算机之间的通信
OSI七层模式:物理层、数据链路层(mac)、网络层(IP)、传输层、会话层、表示层、应用层。
通信协议:TCP/IP(三次握手,四次断开) UDP
所有协议的数据的收和发都是通过socket,socket可以实现两种通信协议
5.2 TCP/IP通信过程
IP;计算机的IP地址
PORT:一个计算机上最多有65535个端口
伪代码
5.3 Socket概念:
Socket本质上就是在2台网络互通的电脑之间,架设一个通道,两台电脑通过这个通道来实现数据的互相传递。我们知道网络通信都是基于IP+PORT方能定位到目标的具体机器上的具体服务,操作系统有0-65535个端口,每个端口都可以独立对外提供服务,如果,把一个公司比作一台电脑,那么公司的总机号码就相当于IP地址,每个员工的分机号就相当于端口,你想找公司某个人,必须先打电话到总机,然后再转分机。
建立一个socket必须至少有2端,一个服务端,一个客户端,服务端被动等待并接收请求,客户端主动发起请求,连接建立之后,双方可以互发数据。
服务端:
1)声明socket实例Server = socket.socket(AF.INET,SOCK.SOCK_STREAM)
2)绑定端口 server.blind()
3)监听 server.listen()
while True:
4)阻塞 conn,addr = server.accept() 接进来创建一个实例
While True:
print(“new conn”,addr)
data = conn.recv(1024) #官方建议最大 #recv默认是阻塞的
if not data:
break #客户端已断开
print(data)
conn.send(data.upper())
客户端
1)实例化client = socket.socket(AF.INET,SOCK.SOCK_STREAM
2)连接 client.connect(serverip,9999)
3)发数据 client.send(data)
5.4 socket Families(地址簇)
socket.AF_UNIX unix本机进程间通信
socket.AF_INET IPV4
socket.AF_INET6 IPV6
5.5 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头。
Socket.SOCK_RDM #是一种可靠的UDP形式,即保证交付数据,但不保证顺序。SOCK_RDM用来提供对原始协议的低级访问,在需要执行某些特殊操作时使用,如发送ICMP报文。SOCK_RAM通常仅限于高级用户或管理员运行的程序使用。
socket.SOCK_SEQPACKET #废弃了
5.6 socket 通信
Socket通信时,数据的传输必须是byte类型,并且不能发送空,recv是有默认的接收大小
Server端
import socket
server = socket.socket() #声明socket类型,同时生成socket连接对象
server.bind(('localhost',6969)) #绑定要监听端口
server.listen()#监听
print("start wait")
conn,addr =server.accept()#等电话打进来 conn是一个接进来的客户端,在服务器端为其生成的一个实例,addr表示地址
print("accept wait")
data = conn.recv(1024)
print('recv:',data)
conn.send(data.upper())
server.close()
客户端
import socket
client = socket.socket() #声明socket类型,同时生成socket连接对象
client.connect(('localhost',6969))
client.send(b"hello word!")
data = client.recv(1024)
print("recy:",data)
client.close()
排队通信
Socket端
import socket
server = socket.socket() #声明socket类型,同时生成socket连接对象
server.bind(('localhost',6969)) #绑定要监听端口
server.listen(5)#监听
print("start wait")
while True:
conn,addr =server.accept()#等电话打进来 conn是一个接进来的客户端,在服务器端为其生成的一个实例,addr表示地址
print("accept wait")
while True:
try :
data = conn.recv(1024)
print('recv:',data.decode())
conn.send(data.upper())
except ConnectionResetError:
break
server.close()
client端:
import socket
client = socket.socket() #声明socket类型,同时生成socket连接对象
client.connect(('localhost',6969))
while True:
message = input(">>:")
client.send(message.encode('utf-8'))
data = client.recv(1024)
print("recy:",data.decode())
client.close()
6、动态导入模块
解释器自己用的
lib = __import__("lib.aa") #导入的是lib
obj = lib.aa.C()
官方建议:
import importlib
aa = importlib.import_module('lib.aa') #官方建议
print(aa.C().name)