类的方法,其实就是类的函数,Python中的面向对象可以分为:普通方法,类方法,静态方法。方法和属性一样,也是属于类的成员,所以也具有运行中修改的特效,但一般不建议这样做。
Python内置方法,方法名以两个下划线(__)开头,同时以两个下划线(__)结尾,也称魔法方法,不需要主动调用,其目的是为了给Python的解释器进行调用,几乎每个魔法方法都有一个对应的内置函数,或者运算符,当对对象使用这些函数或者运算符时就会调用类中的对应的“魔法方法”。
(一)类的常用内置方法1.构造和初始化
__init__已很熟悉了,它在对象初始化的时候调用,一般将它理解为“构造函数”。
实际上,当调用x=SomeClass()的时候,__init__并不是第一个执行的,__new__才是第一个执行的。所以准确地说,是__new__和__init__共同构成了“构造函数”。
__new__在___init__触发前,自动触发。__new__是用来创建类并返回这个类的实例,而__init__只是将传入的参数来初始化该实例。
__new__在创建一个实例的过程中必定会被调用,但__init__就不一定,比如通过pickle。load的方式反序列化一个实例时就不会调用__init__。
__new__方法总是需要返回该类的一个实例,而__init__不能返回除了None的任何值。
执行结果:
此处是__new__方法的执行#先自动触发__new__
此处是__init__方法的执行#再自动触发__init__
__main__.Demoobjectat0x5E48#Demo对象在内在地址
2.获取对象属性
__getattr__在通过“对象.属性”获取属性时,若“属性没有”时触发。
执行结果:
此处是__getattr__方法的执行
x#print结果
#return结果
如去掉上例如中x=10的注释符号“#”,执行结果为10,并不会触发__getattr__。
3.拦截对对象属性的直接访问
__getattribute__在通过“对象.属性”获取属性时自动触发执行。
该方法可以拦截对对象属性的直接访问,当属性被访问时,自动调用该方法(只适用于新式类)。因此常用于实现一些访问某属性时执行一段代码的特性。
需要注意的是,正是由于它拦截对所有属性的访问(包括对__dict__的访问),在使用中要避开无限循环陷阱。在__getattribute__方法中访问当前实例的属性时,唯一安全的方式是使用基类(超类)的方法__getattribute__(使用super)。
执行结果:
此处是__getattribute__方法的执行
x--打印属性名字
注意:只要__getattr__与__getattribute__同时存在类的内部,只会触发__getattribute__。若执行到__getattribute__发现raiseAttributeError(抛出异常),则再触发__getattr__。
4.设置、添加和析构属性
__setattr__当“对象.属性=属性值”,添加或修改属性时触发执行。__delattr__当删除“对象.属性”属性的时候会触发执行。
执行结果:
此处是__setattr__方法的执行
x10
{x:10}
10
执行结果:
此处是__delattr__方法的执行
此处是__delattr__方法的执行
5.转化为字符串
l=list(hello)#l是list类的实例化出来的一个实例,即一个对象
print(l)#结果是[h,e,l,l,o]
[h,e,l,l,o]
classFoo:
pass
f1=Foo()
print(f1)#结果是__main__.Fooobjectat0xFD,ID会变
__main__.Fooobjectat0xFD
以上所知,所以Python内部肯定有内化机制进行过处理,其实质原理如下:
__str__在打印(输出)对象时触发。
注意:该方法必须要有一个“字符串”返回值。
执行结果:
此处是__str__方法的执行
自定义的对象显示方式
6.设置、获取、删除键值
__getitem__在对象通过“对象[key]”获取属性时触发。
执行结果:
__main__.Demoobjectat0xD9EC88--打印的对象
此处是__getitem__方法的执行
name#print(item)的结果
zhang#return的结果
__setitem__在对象通过“对象[key]=value值”设置属性时触发。
执行结果:
{}
此处是__setitem__方法的执行
{name:ruilin}
__delitem__在对象通过del“对象[key]”属性时触发。
执行结果:
{}
此处是__setitem__方法的执行
{name:ruilin}
此处是__delitem__方法的执行
{}
7.函数调用
__call__在调用对象“对象+()”(即函数)时触发。
执行结果:
此处是__call__方法的执行
[1,2,3,4]
Python内置方法,也称魔法方法,还称为特殊方法,Python类有大量的特殊方法.其中比较常见的是构造函数和析构函数(见前述)。Python中类的构造函数是__init__(),析构函数是__del__(),一般用来释放对象占用的资源,在Python删除对象和收回对象空间时被自动调用和执行。如果用户没有编写析构函数,Python将提供一个默认的析构函数进行必要的清理工作。
在Python中除了构造函数和析构函数之外,还有大量的特殊方法支持更多的功能,表1列出了其中一部分Python类特殊方法,前面1~7已结合实例介绍了其中的一部分。
表1Python类特殊方法
方法
功能说明
__init__()
构造函数,生成对象时调用
__del__()
析构函数,释放对象时调用
__add__()、__radd__()
左+、右+
__sub__()
-
__mul__()
*
__div__()、__truediv__()
/,Python2.x使用__div__(),Python3.x使用__truediv__()
__floordiv__()
整除,//
__mod__()
取余,%
__pow__()
**
__cmp__()
比较运算
__repr__()
打印、转换
__setitem__()
按照索引赋值
__getitern__()
按照索引获取值
__len__()
计算长度
__call__()
函数调用
__contains__()
测试是否包含某个元素
__eq__()、__ne__()、__lt__()、__le__()、__gt__()、__ge__()
==、!=、、=、、=
__str__()
转化为字符串
__lshift__()、__rshift__()
、
__and__()、__or__()、__invert__()
、
、~
__iadd__(),__isub__()
+=、-=
(二)方法的访问控制1.魔术方法实现属性访问控制
Python通过魔术方法来实现封装,实现属性访问控制。
__getattr__(self,name)
该方法定义了试图访问一个不存在的属性时的行为。因此,重载该方法可以实现捕获错误拼写然后进行重定向,或者对一些废弃的属性进行警告。
__setattr__(self,name,value)
__setattr__是实现封装的解决方案,它定义了对属性进行赋值和修改操作时的行为。
不管对象的某个属性是否存在,它都允许为该属性进行赋值,因此可以为属性的值进行自定义操作。有一点需要注意,实现__setattr__时要避免“无限递归”的错误,下面的代码示例中会提到。
__delattr__(self,name)
__delattr__与__setattr__很像,只是它定义的是你删除属性时的行为。实现__delattr__时同时也要避免“无限递归”的错误。
__getattribute__(self,name)
__getattribute__定义了属性被访问时的行为,相比较,__getattr__只有该属性不存在时才会起作用。
因此,在支持__getattribute__的Python版本中,调用__getattr__前必定会调用__getattribute__。__getattribute__同样要避免“无限递归”的错误。
需要提醒的是,最好不要尝试去实现__getattribute__,因为很少见到这种做法,而且很容易出“bug”。
例8:说明__setattr__的无限递归错误。
def__setattr__(self,name,value):
self.name=value
#每次属性赋值时,__setattr__都会被调用,因此不断调用自身导致无限递归
因此正确的写法应该是:
def__setattr__(self,name,value):
self.__dict__[name]=value
__delattr__如果在其实现中出现delself.name这样的代码也会出现“无限递归”错误,这是一样的原因。
2.描述器对象实现方法访问控制
用例9来介绍什么是描述符,并介绍__get__,__set__,__delete__的使用。
例9:距离既可以用单位“米”表示,又可以用单位“英尺”表示。试定义一个类来表示距离,它有两个属性:米和英尺。
说明:1英寸(吋)=2.54厘米,1英尺=12英寸=12*2.54=30.48厘米,1米=厘米=/30.48=3.英尺
执行结果:
0.00.0
1.03.
2.06.
在例9中,在还没有对Distance的实例赋值前,可以认为Meter和Foot应该是各自类的实例对象,但是输出却是数值。这是因为__get__发挥了作用。
我们只是修改了meter,并且将其赋值成为int,但foot也修改了。这是__set__发挥了作用。
描述器对象(Meter、Foot)不能独立存在,它需要被另一个所有者类(Distance)所持有。
描述器对象可以访问到其拥有者实例的属性,比如例9中Foot的instance.meter。
在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙地组织逻辑。
一个类要成为描述器,必须实现__get__,__set__,__delete__中的至少一个方法。
__get__在其拥有者对其读值的时候调用。
语法结构:
__get__(self,instance,owner)
instance——拥有者类的实例
owner——拥有者类本身
__set__在其拥有者对其进行修改值的时候调用。
语法结构:
__set__(self,instance,value)
__delete__在其拥有者对其进行删除的时候调用。
语法结构:
__delete__(self,instance)
(三)方法的的装饰器Python方法有普通方法、静态方法、类方法之分,静态方法、类方法使用了装饰器。
1.三种方法的比较
普通方法:默认有个self参数,且只能被对象(实例)调用。
静态方法:用
staticmethod装饰的不带self参数的方法叫做静态方法,类的静态方法可以没有参数,可以直接使用类名调用。类方法:默认有个cls参数,可以被类和对象调用,需要加上
classmethod装饰器。例10:普通方法、类方法、静态方法的比较。
进行测试一
tst=Tst()
tst.data=这是我的数据!
tst.normalMethod(name)
tst.classMethod(name)
tst.staticMethod(name)
执行结果:
这是我的数据!name
这是类数据!name
name
使用普通方法、类方法和静态方法都可以通过对象(tst)进行调用,但是静态方法和类方法无法访问对象的属性,所以更改对象(tst)的属性仅仅只是对普通方法起作用。
进行测试二
Tst.normalMethod(name)
Tst.classMethod(name)
Tst.staticMethod(name)
执行结果:
Traceback(mostrecentcalllast):
File"C:/Users/Administrator/AppData/Local/Programs/Python/Python37/classTst.py",line23,inmodule
Tst.normalMethod(name)
TypeError:normalMethod()missing1requiredpositionalargument:name
出错原因是普通方法无法通过类名调用,但静态方法和类方法是可以的。注销Tst.normal_method(name)后重新执行。
#Tst.normalMethod(name)
Tst.classMethod(name)
Tst.staticMethod(name)
执行结果:
这是类数据!name
name
普通方法、静态方法、类方法三种方法都可以通过对象进行调用,但类方法和静态方法无法访问对象属性,类方法通过对象调用获取的仍是类属性(并非对象属性);普通方法无法通过类名调用,类方法和静态方法可以,但静态方法不能进行访问,仅仅只是通过传值的方式(与函数调用相同)。
2.三种方法的应用
例11:用类来实现部分计算器功能,并计算任意两个整数的平方和。
(1)普通方法
执行结果:
25
(2)类方法(
classmethod)执行结果:
25
(3)静态方法(
staticmethod)classTest:
def__init__(self,num1,num2):
self.num1=num1
self.num2=num2
defplus(self):
result=self.num1+self.num2
returnresult
defmultiply(self):
result=self.num1*self.num2
returnresult
staticmethoddefsum(num1,num2):
s=num1*num1+num2*num2
print(s)
Test.sum(3,4)
执行结果:
25
以上三种方法都能实现例11的功能要求。使用类方法时,求和功能的那部分代码并没有放在类(Test)中,而是作为类的一个成员方法,这样的好处是可以简化对象,增加可读性(直接通过参数num1、num2来实现最终功能),但整个过程仍须类(self)参与;使用静态方法时,仅仅需要通过传递两个参数即可实现,但最终结果仍可作为类方法进行访问。
classmethod装饰(类方法):它的作用就是有点像静态类,与静态类不一样的就是它可以传进来一个当前类作为第一个参数。staticmethod装饰(静态方法):经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法。比如更改环境变量或者修改其他类的属性等能用到静态方法。这种情况可以直接用函数解决,但这样同样会扩散类内部的代码,造成维护困难。至于静态方法就是写在类里的方法,必须用类来调用(极少数情况下使用,一般都在全局里直接写函数了)。预览时标签不可点收录于话题#个上一篇下一篇