通过@staticmethod装饰器即可把其装饰的方法变为一个静态方法,什么是静态方法呢?其实不难理解,普通的方法,可以在实例化后直接调用,并且在方法里可以通过self.调用实例变量或类变量,但静态方法是不可以访问实例变量或类变量的,一个不能访问实例变量和类变量的方法,其实相当于跟类本身已经没什么关系了,它与类唯一的关联就是需要通过类名来调用这个方法
1classDog(object):23def__init__(self,name):4self.name=name56@staticmethod#把eat方法变为静态方法7defeat(self):8print("%siseating"%self.name)9101112d=Dog("嘻哈")13d.eat()
上面的调用会出以下错误,说是eat需要一个self参数,但调用时却没有传递,没错,当eat变成静态方法后,再通过实例调用时就不会自动把实例本身当作一个参数传给self了。
Traceback(mostrecentcalllast):File"/Users/jieli/PycharmProjects/python基础/面向对象高级/静态方法.py",line17,in
1.调用时主动传递实例本身给eat方法,即d.eat(d)
2.在eat方法中去掉self参数,但这也意味着,在eat中不能通过self.调用实例中的其它变量了
1classDog(object):23def__init__(self,name):4self.name=name56@staticmethod7defeat():8print("iseating")9101112d=Dog("ChenRonghua")13d.eat()类方法
类方法通过@classmethod装饰器实现,类方法和普通方法的区别是,类方法只能访问类变量,不能访问实例变量
1classDog(object):2def__init__(self,name):3self.name=name45@classmethod6defeat(self):7print("%siseating"%self.name)891011d=Dog("ChenRonghua")12d.eat()执行报错如下,name是个实例变量,类方法是不能访问实例变量的
Traceback(mostrecentcalllast):File"D:/编程学习/python/练习/基础/类/属性方法.py",line57,in
1classDog(object):2name="我是类变量"3def__init__(self,name):4self.name=name56@classmethod7defeat(self):8print("%siseating"%self.name)9101112d=Dog("ChenRonghua")13d.eat()141516#执行结果1718我是类变量iseating属性方法
属性方法的作用就是通过@property把一个方法变成一个静态属性
1classDog(object):23def__init__(self,name):4self.name=name56@property7defeat(self):8print("%siseating"%self.name)91011d=Dog("ChenRonghua")12d.eat()
调用会出以下错误,因为eat此时已经变成一个静态属性了,不是方法了,想调用就不需要加()号了,直接d.eat就可以了
Traceback(mostrecentcalllast):ChenRonghuaiseatingFile"D:/编程学习/python/练习/基础/类/属性方法.py",line75,in
1d=Dog("ChenRonghua")2d.eat34输出5ChenRonghuaiseating
那你就会问了,把一个方法变成静态属性有什么用呢?既然想要静态变量,那直接定义衣个静态变量不就好了吗?well,以后你会知道很多场景是不能简单通过定义静态变量来实现的,比如,你想知道一个航班当前的状态,是到达了、延迟了、取消了、还是飞走了,想知道这种状态你必须经历以下几步:
1.连接航空公司API查询
2.对查询结果进行解析
3.返回给你的用户
因此这个status属性的值是一系列动作后才得到的结果,所以每次调用时,其实它都要经过一系列的动作才返回你的结果,但这些动作过程不需要用户关心,用户只需要调用这个属性就可以了
1classFlight(object):2def__init__(self,name):3self.flight_name=name456defchecking_status(self):7print("checkingflight%sstatus"%self.flight_name)8return1910@property11defflight_status(self):12status=self.checking_status()13ifstatus==0:14print("flightgotcanceled...")15elifstatus==1:16print("flightisarrived...")17elifstatus==2:18print("flighthasdeparturedalready...")19else:20print("cannotconfirmtheflightstatus...,pleasechecklater")212223f=Flight("CA980")24f.flight_status航班查询
cool。那现在只能查询航班状态,现在这个flight-status已经是个属性了,那么就可以进行赋值
1f=Flight("CA980")2f.flight_status3f.flight_status=2
输出,报错,说是不能更改属性
1checkingflightCA980status2flightisarrived...3Traceback(mostrecentcalllast):4File"D:/编程学习/python/练习/基础/类/属性方法.py",line102,in
当然可以改,不过需要通过@proerty.setter装饰器再装饰一下,此时你需要写一个新方法,对flight_status进行修改
1classFlight(object):2def__init__(self,name):3self.flight_name=name456defchecking_status(self):7print("checkingflight%sstatus"%self.flight_name)8return191011@property12defflight_status(self):13status=self.checking_status()14ifstatus==0:15print("flightgotcanceled...")16elifstatus==1:17print("flightisarrived...")18elifstatus==2:19print("flighthasdeparturedalready...")20else:21print("cannotconfirmtheflightstatus...,pleasechecklater")2223@flight_status.setter#修改24defflight_status(self,status):25status_dic={260:"canceled",271:"arrived",282:"departured"29}30print("\033[31;1mHaschangedtheflightstatusto\033[0m",status_dic.get(status))3132@flight_status.deleter#删除33defflight_status(self):34print("statusgotremoved...")3536f=Flight("CA980")37f.flight_status38f.flight_status=2#触发@flight_status.setter39delf.flight_status#触发@flight_status.deleterViewCode
注意以上代码里还写了一个@flight_status.deleter,是允许可以将这个属性删除
类的特殊成员方法
1.__doc__表示类的描述信息
1classFoo:2"""描述类信息,这是用于看片的神奇"""34deffunc(self):5pass67printFoo.__doc__8#输出:类的描述信息ViewCode
2.__module__表示当前操作的对象在哪一个模块
__class__表示当前操作对象在哪一个类
1classC:23def__init__(self):4self.name='wupeiqi'lib/aa.py
1fromlib.aaimportC23obj=C()4printobj.__module__#输出lib.aa,即:输出模块5printobj.__class__#输出lib.aa.C,即:输出类index.py
3.__init__构造方法,通过类创建对象时,自行触发执行
4.__del__析构方法,当对象在内存中被释放时,自动触发执行
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的
5.__call__对象后面加括号,触发执行
注:构造方法的执行是由创建对象触发的,即:对象=类名();而对于__call__方法的执行是由对象后加括号触发的,即:对象()或者类()()
1classFoo:23def__init__(self):4pass56def__call__(self,*args,**kwargs):78print'__call__'91011obj=Foo()#执行__init__12obj()#执行__call__ViewCode
6.__dict__查看类或对象中的所有成员
1classProvince:23country='China'45def__init__(self,name,count):6self.name=name7self.count=count89deffunc(self,*args,**kwargs):10print'func'1112#获取类的成员,即:静态字段、方法、13printProvince.__dict__14#输出:{'country':'China','__module__':'__main__','func':
7.__str__如果一个类中定义了__str__方法,那么在打印对象时,默认输出该方法的返回值
1classFoo:23def__str__(self):4return'hello'567obj=Foo()8printobj9#输出:helloViewCode
8.__getitem__、__setitem__、__delitem__用于索引操作,如字典。它们分别表示获取、设置、删除数据
1classFoo(object):23def__getitem__(self,key):4print('__getitem__',key)56def__setitem__(self,key,value):7print('__setitem__',key,value)89def__delitem__(self,key):10print('__delitem__',key)111213obj=Foo()1415result=obj['k1']#自动触发执行__getitem__16obj['k2']='alex'#自动触发执行__setitem__17delobj['k1']ViewCode
9.__new__、__metaclass__
1classFoo(object):234def__init__(self,name):5self.name=name678f=Foo("alex")
上述的代码中,obj是通过Foo类实例化的对象,其实,不仅obj是一个对象,Foo类本身也是一个对象,因为在python中一切事物都是对象
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的构造方法创建
1printtype(f)#输出:
所以,f对象是Foo类的一个实例,Foo类对象是type类的一个实例,即;Foo类对象是通过type类的构造方法创建。那么创建类就有两种方式:
a.普通方式
1classFoo(object):23deffunc(self):4print'helloalex'
b.特殊方式
1deffunc(self):2print'hellowupeiqi'34Foo=type('Foo',(object,),{'func':func})5#type第一个参数:类名6#type第二个参数:当前类的基类7#type第三个参数:类的成员
1deffunc(self):2print("hello%s"%self.name)34def__init__(self,name,age):5self.name=name6self.age=age7Foo=type('Foo',(object,),{'func':func,'__init__':__init__})89f=Foo("jack",22)10f.func()
所以,类是type类实例化产生的
问:类默认是由type实例化产生的,type类中如何实现创建类?类又是如何创建对象?
答:类中有一个属性__metaclass__,其表示该类由谁来实例化创建,所以,我们可以为__metaclass__设置一个type类的派生类,从而查看类创建的过程。
1classMyType(type):2def__init__(self,*args,**kwargs):34print("Mytype__init__",*args,**kwargs)56def__call__(self,*args,**kwargs):7print("Mytype__call__",*args,**kwargs)8obj=self.__new__(self)9print("obj",obj,*args,**kwargs)10print(self)11self.__init__(obj,*args,**kwargs)12returnobj1314def__new__(cls,*args,**kwargs):15print("Mytype__new__",*args,**kwargs)16returntype.__new__(cls,*args,**kwargs)1718print('here...')19classFoo(object,metaclass=MyType):202122def__init__(self,name):23self.name=name2425print("Foo__init__")2627def__new__(cls,*args,**kwargs):28print("Foo__new__",cls,*args,**kwargs)29returnobject.__new__(cls)3031f=Foo("Alex")32print("f",f)33print("fname",f.name)自定义元素
类的生成、调用顺序依次是__new__-->__init__-->__call__
通过字符串映射或修改程序运行时的状态、属性、方法,有以下4种方法
1defgetattr(object,name,default=None):#knownspecialcaseofgetattr2"""3getattr(object,name[,default])->value45Getanamedattributefromanobject;getattr(x,'y')isequivalenttox.y.6Whenadefaultargumentisgiven,itisreturnedwhentheattributedoesn't7exist;withoutit,anexceptionisraisedinthatcase.8"""9passgetattr(object,name,default=None)
1判断object中有没有一个name字符串对应的方法或属性hasattr(object,name)
1defsetattr(x,y,v):#realsignatureunknown;restoredfrom__doc__2"""3Setsthenamedattributeonthegivenobjecttothespecifiedvalue.45setattr(x,'y',v)isequivalentto``x.y=v''setattr(x,y,v)
1defdelattr(x,y):#realsignatureunknown;restoredfrom__doc__2"""3Deletesthenamedattributefromthegivenobject.45delattr(x,'y')isequivalentto``delx.y''6"""delattr(x,y)
1classFoo(object):23def__init__(self):4self.name='wupeiqi'56deffunc(self):7return'func'89obj=Foo()1011#####检查是否含有成员####12hasattr(obj,'name')13hasattr(obj,'func')1415#####获取成员####16getattr(obj,'name')17getattr(obj,'func')1819#####设置成员####20setattr(obj,'age',18)21setattr(obj,'show',lambdanum:num+1)2223#####删除成员####24delattr(obj,'name')25delattr(obj,'func')反射代码示范
1.异常基础
在编程过程中为了增加友好性,在程序出现bug时一般不会将错误信息显示给用户,而是显示一个提示的页面,通俗来说就是不让用户看见大红页。
1try:2pass3exceptExceptionasex:4pass
需求:将用户输入的两个数字相加
1whileTrue:2num1=raw_input('num1:')3num2=raw_input('num2:')4try:5num1=int(num1)6num2=int(num2)7result=num1+num28exceptExceptionase:9print'出现异常,信息如下:'10print(e)
2.异常种类
python中的异常种类非常多,每个异常专门用于处理某一项异常
1AttributeError试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x2IOError输入/输出异常;基本上是无法打开文件3ImportError无法引入模块或包;基本上是路径问题或名称错误4IndentationError语法错误(的子类);代码没有正确对齐5IndexError下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5]6KeyError试图访问字典里不存在的键7KeyboardInterruptCtrl+C被按下8NameError使用一个还未被赋予对象的变量9SyntaxErrorPython代码非法,代码不能编译(个人认为这是语法错误,写错了)10TypeError传入对象类型与要求的不符合11UnboundLocalError试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,12导致你以为正在访问它13ValueError传入一个调用者不期望的值,即使值的类型是正确的常见异常
1ArithmeticError2AssertionError3AttributeError4BaseException5BufferError6BytesWarning7DeprecationWarning8EnvironmentError9EOFError10Exception11FloatingPointError12FutureWarning13GeneratorExit14ImportError15ImportWarning16IndentationError17IndexError18IOError19KeyboardInterrupt20KeyError21LookupError22MemoryError23NameError24NotImplementedError25OSError26OverflowError27PendingDeprecationWarning28ReferenceError29RuntimeError30RuntimeWarning31StandardError32StopIteration33SyntaxError34SyntaxWarning35SystemError36SystemExit37TabError38TypeError39UnboundLocalError40UnicodeDecodeError41UnicodeEncodeError42UnicodeError43UnicodeTranslateError44UnicodeWarning45UserWarning46ValueError47Warning48ZeroDivisionError其它异常
1dic=["wupeiqi",'alex']2try:3dic[10]4exceptIndexErrorase:5print(e)实例:IndexError
1dic={'k1':'v1'}2try:3dic['k20']4exceptKeyErrorase:5print(e)实例:KeyError
1s1='hello'2try:3int(s1)4exceptValueErrorase:5print(e)实例:ValueError
对于上述实例,异常类只能用来处理指定的异常情况,如果非指定异常则无法处理。
1#未捕获到异常,程序直接报错23s1='hello'4try:5int(s1)6exceptIndexErrorase:7print(e)
所以,写程序时需要考虑到try代码块中可能出现的任意异常,可以这样写:
1s1='hello'2try:3int(s1)4exceptIndexErrorase:5print(e)6exceptKeyErrorase:7print(e)8exceptValueErrorase:9print(e)
万能异常在python的异常中,有一个万能异常:Exception,它可以捕获任何异常,即
1s1='hello'2try:3int(s1)4exceptExceptionase:5print(e)
问:既然有了万能异常,其它异常是不是就可以忽略了?
答:当然不是,对于特殊处理或提醒的异常需要先定义,最后定义Exception来确保程序正常运行。
1s1='hello'2try:3int(s1)4exceptKeyErrorase:5print('键错误')6exceptIndexErrorase:7print('索引错误')8exceptExceptionase:9print('错误')
3.其它异常结构
1try:2#主代码块3pass4exceptKeyErrorase:5#异常时,执行该块6pass7else:8#主代码块执行完,执行该块9pass10finally:11#无论异常与否,最终执行该块12pass
4.主动触发异常
1try:2raiseException('错误了。。。')3exceptExceptionase:4print(e)
5.自定义异常
1classliuminException(Exception):2def__init__(self,msg):3self.message=msg45def__str__(self):6returnself.message78try:9raiseliuminException("我的异常:数据库连不上")10exceptliuminExceptionase:11print(e)