美文网首页
python--new方法,定制属性,描述器以及装饰器

python--new方法,定制属性,描述器以及装饰器

作者: 昆仑草莽 | 来源:发表于2019-03-28 13:51 被阅读0次

在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

相关文章

网友评论

      本文标题:python--new方法,定制属性,描述器以及装饰器

      本文链接:https://www.haomeiwen.com/subject/zepfbqtx.html