在python中有一种魔术方式是十分重要的,就是 new 方法,new 方法也是魔术方法。下面来看看 new 方法的使用。
new方法
class Test():
def __init__(self,name):
self.name = name
print(self.name+'正在初始化')
def __new__(cls,*args,**kwargs)
print('new开始运行')
t = Test()
输出:new开始运行
t = Test('python')
输出:new开始运行
class Test():
def __init__(self,name):
self.name = name
print(self.name+'正在初始化')
t = Test('python')
输出:python正在初始化
上面的两段代码,我们可以看出,当类实例化的时候,首先运行的是 new 方法,之后才执行初始化。new方法,可以从四个方面理解:
1.__ new__方法是在类创建实例化的时候自动调用的。
2. 实例是通过类里面__ new__方法是在类创建出来的。
3.先调用__ new__方法创建实例,在通过__ init__方法初始化实例。
4.__ new__方法,在()里 cls 是代表类本身,就好像类方法()里面的 self 是代表实例本身一样,cls 代表类的本身。
类的单实例
class Test():
def __new__(cls,*args,**kwargs):
if not hasattr(cls,'nature'):
cls.nature = super().__new__(cls)
return cls.nature
def __init__(self,name):
self.name = name
a =Test('python')
b = Test('java')
print(id(a))
print(id(b))
输出:
2924851816096
2924851816096
从输出结果,可以看出,无论实例化多少实例,其内存空间是不变的,这和我们前面所学习的类实例化有些区别,前面的类实例化,没实例化一个实例都会占用一个不同的内存空间。这就是类的单实例。也是 new 方法的最重要作用。简单的说,就好像是有很多的电脑被制造出来,造好后好放在同一个仓库里。这个仓库就是 new 在类实例化之前建的房子,用来盛放实例化的实例。nature 是类属性,可自行定义名字。
new方法可以很方便的实现单实例。常用来实现类的单实例模式。
定制属性访问
在类中,要如何判断类有哪些属性,又怎么对类的属性做增删改查的操作呢,这就是定制属性访问的实质,下面看看具体操作:
class Rectangle():
def __init__(self,lenth,width):
self.lenth = lenth #类的属性
self.width = width
def getarea(self):
s = self.lenth*self.width
return '四边形的面积是:{}'.format(s)
rect = Rectangle(3,4)
定义一个求矩形面积的类,并实例化。以此来了解类的增删改查。
1.查
prin(hasattr(rect,'lenth')) #返回bool值,查询 lenth 属性,类有这个属性。
输出:True
prin(hasattr(rect,'hight')) #返回bool值,查询 hight 属性,类没有这个属性。
输出:False
print(getattr(rect,'lenth')) #返回 lenth 的值。传入的参数是3。
输出:3
print(getattr(rect,'hight')) #返回 hight 的值。由于没有high属性。所以会报错
输出:AttributeError: 'Rectangle' object has no attribute 'hight'
rect.__getattribute__('lenth') #和 getattr 相同,是 getattr 的底层方法,属于python的魔术方法之一。
2.增
rect.hight = 4 #一般的增加类属性方法,前面章节有过讲解。
setattr(rect,'hight',4) #有 hight 属性就修改,没有就增加。
rect.__setattr__('hight',4) #和 setattr 相同,是setattr的底层方法,属于python的魔法方法之一。
3.改
setattr(rect,'lenth',4) #有 lenth 属性就修改,没有就增加。
rect.__setattr__('lenth',6) #和 setattr 相同,是setattr的底层方法,属于python的魔法方法之一。
4.删除
delattr(rect,'lenth') #删除 lenth 属性
rect.__delattr__('lenth') #和 delattr 相同,是delattr的底层方法,属于python的魔法方法之一。
def rect #删除实例化。
综上所述:类的增删改查就是 has,get,set,del 后面加 attr (属性),组合即可。
$$$ hasattr: $$$
**********************************************************************************
def hasattr(object,name_string)
try:
getattr(object,name_string)
return Ture
execpt AttributeError
return False
**********************************************************************************
$$$ getattr: $$$
**********************************************************************************
getattr(object,'name',[default])
返回:object.name
**********************************************************************************
$$$ setattr: $$$
**********************************************************************************
setattr(object,'name',values)
返回:object.name = values
**********************************************************************************
$$$ delattr: $$$
**********************************************************************************
delattr(object,name)
返回:del object.name
**********************************************************************************
当使用 getattr 时候,没有属性时候会报错,我们可以在类中增加一个方法避免报错。这样,程序不会因为没有查询到属性而停止运行。
class Rectangle():
def __init__(self,lenth,width):
self.lenth = lenth #类的属性
self.width = width
def __getattr__(self, item):
print('查询属性不存在')
def getarea(self):
s = self.lenth*self.width
return '四边形的面积是:{}'.format(s)
rect = Rectangle(3,4)
getattr(rect,'hight')
输出:查询属性不存在
描述符
当在一个类中实例化另一个类,对这个属性访问,要怎么做呢。
class MyAttribute():
def __get__(self,'instance',owner): #instance 是类属性,可以自行定义名字
print('this is get')
def __set__(self,'instance',values):
print('this is set')
def __delete__(self,'instance'):
print('this is del')
class Test():
m = MyAtrribute() #实例化 MyAtrribute 类
def __get__(self,'name'):
print('get name')
t = Test()
t.m
输出:this is get
t.m = 3
输出:this is set
del t.m
输出:this is del
描述符协议:
python描述符是一个绑定行为的对象属性,在描述符协议中,他可以通过方法重写属性的访问,这些方法有__ get__(),__ set__(),__ delete__()。如果这三种方法中任何一种被定义在一个对象中,这个对象就是描述符。
装饰器
前面我们学习了闭包。
def outt():
def inn():
print('this is inn')
return inn
outt()()
输出:this is inn
闭包可以轻松的访问内层函数,并返回内层函数的值。那么闭包可以传入一个函数吗。
def test_outt(func):
def test_inn():
print('this is change function')
func()
return test_inn
@test_outt
def ask():
print('are you asking?')
ask()
输出:
this is change function
are you asking?
这就是装饰器。从上面例子可见,当闭包传入的是一个函数的时候,就是一个装饰器。他可以在不修改原函数或方法的情况下,增加函数或方法的功能。
def test_outt(func):
def test_inn():
print('--------------登陆验证---------------')
func()
print('--------------验证完毕---------------')
return test_inn
@test_outt
def land():
print('--------------输入账号---------------')
print('--------------输入密码---------------')
land()
输出:
--------------登陆验证---------------
--------------输入账号---------------
--------------输入密码---------------
--------------验证完毕---------------
python 自带的三个内置装饰器
class Rectangle():
lenth = 7
width = 8
def __init__(self,lenth,width):
self.lenth = lenth
self.width = width
@property # 第一个 属性方法 访问函数可以像访问属性一样
def getarea(self):
s = self.lenth*self.width
return '四边形的面积是:{}'.format(s)
@staticmethod # 第二个 静态方法,和class类断开联系
def sidelenth(): #注意,此处不能有 self ,否则会报错。
lenth = 5
width = 8
s = (lenth+width)*2
return '四边形的周长是:{}'.format(s)
@classmethod # 第三个 类方法 调用类自身 ,可以访问类属性。
def lenthadnwidth(cls): #注意,此处是cls,不是self。
s = cls.lenth * cls.width
print('四边形的面积是:{}'.format(s))
return '四边形的长和宽是: {} ,{}'.format(cls.lenth,cls.width)
rect = Rectangle(3,4)
print(rect.getarea)
print(rect.sidelenth())
print(rect.lenthadnwidth())
输出:
四边形的面积是:12
四边形的周长是:26
四边形的面积是:56
四边形的长和宽是: 7,8
******请注意访问的方式,以及方法内部的变化。******
rect.getarea
rect.sidelenth()
rect.lenthadnwidth()
类装饰器
方法或函数可以定义为装饰器,那么类可以定义为装饰器吗,答案是肯定的,python是高级语言,万物皆对象,所以,类也可以作为装饰器的,前提是,类定义为装饰器必须定义__ call__()方法。
class Test():
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print('john is reading')
return self.func()
@Test
def write():
print('smith is writing')
write()
输出:
john is reading
smith is writing









网友评论