Python3基础-自定制property

 

一、类函数没有加@的执行结果

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height
    def type(self):
        return self.name

以上代码执行结果就为空,

二、若是在类函数type上一行加上@testproperty 则:

class testproperty:
    def __init__(self,func):
        self.func = func
        print('func===',func)

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name
@testproperty  相当于type=testproperty(type)  就相当于在类People 添加一个类属性;就是在实例化testproperty(type)

则运行结果如下
func=== <function People.type at 0x039CF780>

上面的代码再加上

p1 = People('SUSU',90,'1米65')
print(p1.type) 

则p1.type输出的结果是<__main__.testproperty object at 0x010901F0>  因为@testproperty 相当于type=testproperty(type) ;则type就是一个实例化对象

要输出type()函数的返回值,则 p1.type.func(p1)

print(p1.type.func(p1))  #输出的是SUSU

三、利用描述符自定制

#实例调用
class testproperty:
    def __init__(self,func):
        self.func = func
        #print('func===',func)

    def __get__(self, instance, owner):
        print(self)  #<__main__.testproperty object at 0x01155670>
        print(instance)  #<__main__.People object at 0x01155710>  即是p1
        print(owner)   #<class '__main__.People'>
        val = self.func(instance)
        return val

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name
p1 = People('SUSU',90,'1米65')
#实例调用
print(p1.type)  #输出的是SUSU
#类的调用
class testproperty:
    def __init__(self,func):
        self.func = func
        #print('func===',func)

    def __get__(self, instance, owner):
        print(self)  #<__main__.testproperty object at 0x01155670>
        print(instance)  #None
        print(owner)   #<class '__main__.People'>
        val = self.func(instance)  #报错 AttributeError: 'NoneType' object has no attribute 'name'
        return val

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name
p1 = People('SUSU',90,'1米65')
#类调用
print(People.type)

 类的调用 People.type, 传入get函数是 instance的值为空,则在val=self.func(instance) 则会出现报错AttributeError: 'NoneType' object has no attribute 'name'

 默认property的实例调用和类调用出现的情况:

class testproperty:
    def __init__(self,func):
        self.func = func
        #print('func===',func)

    def __get__(self, instance, owner):
        print(self)  #<__main__.testproperty object at 0x01155670>
        print(instance)  #None
        print(owner)   #<class '__main__.People'>
        val = self.func(instance)  #报错 AttributeError: 'NoneType' object has no attribute 'name'
        return val

#默认@property
class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name

    @property #eat = property(eat)   默认的
    def eat(self):
        return self.age
p1 = People('SUSU',90,'1米65')
# 实例调用
# print(p1.type)

#类调用
# print(People.type)
print(p1.eat) #@property  实例调用则输出 90
print(People.eat) #@property 类调用则输出 <property object at 0x02DB8450>

则自定制的testproperty;可以修改如下

class testproperty:
    def __init__(self,func):
        self.func = func
        #print('func===',func)

    def __get__(self, instance, owner):
        if instance is None:  #新增判断如果是类调用,则返回self
            return self
        val = self.func(instance)
        return val


class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name

    @property #eat = property(eat)   默认的
    def eat(self):
        return self.age
p1 = People('SUSU',90,'1米65')
print(p1.type) #@testproperty   实例调用则输出SUSU
print(People.type) #@testproperty  类的调用则输出<__main__.testproperty object at 0x02F25710>

四、自定制property实现延迟计算功能

class testproperty:
    def __init__(self,func):
        self.func = func

    def __get__(self, instance, owner):
        print('get方法')
        if instance is None:
            return self
        val = self.func(instance)
        setattr(instance,self.func.__name__,val)  #则将val 放置到p1字典里面,key的值为type
        #取一个函数的函数名称为 type.__name__  则在该类里面type为 self.func
        return val


class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name

    @property #eat = property(eat)   默认的
    def eat(self):
        return self.age
p1 = People('SUSU',90,'1米65')
print(p1.__dict__)
print(p1.type)
print(p1.__dict__)
print(p1.type) 
print(p1.type)

执行结果如下:

{'name': 'SUSU', 'age': 90, 'height': '1米65'}
get方法
SUSU
{'name': 'SUSU', 'age': 90, 'height': '1米65'}
get方法
SUSU
get方法
SUSU

由此可以看出以上代码p1.type执行了三次,则get方法也执行了三次

优化一下,get无需一直执行

class testproperty:
    def __init__(self,func):
        self.func = func

    def __get__(self, instance, owner):
        print('get方法')
        if instance is None:
            return self
        val = self.func(instance)
        setattr(instance,self.func.__name__,val)  #则将val 放置到p1字典里面,key的值为type
        #取一个函数的函数名称为 type.__name__  则在该类里面type为 self.func
        return val

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name
p1 = People('SUSU',90,'1米65')
print(p1.__dict__)
print(p1.type)
print(p1.__dict__)
print(p1.type)
print(p1.type)

以上执行的结果

{'name': 'SUSU', 'age': 90, 'height': '1米65'}
get方法
SUSU
{'name': 'SUSU', 'age': 90, 'height': '1米65', 'type': 'SUSU'}
SUSU  #因为p1字典里面有了type;则直接从实例字典里面读取
SUSU  

第一次运行时,实例属性字典没有该属性type,则运行非数据描述符,运行之后setattr(instance,self.func.__name__,val) #则将val 放置到实例属性字典里面,key的值为type

第二次运行时,因为实例属性优先级高于非数据描述符,则会先在实例属性字典里面找。{'name': 'SUSU', 'age': 90, 'height': '1米65', 'type': 'SUSU'};则就直接取该属性的值,就无需运行描述符类

如果描述符类加上set函数,则运行结果

class testproperty:
    def __init__(self,func):
        self.func = func

    def __get__(self, instance, owner):
        print('get方法')
        if instance is None:
            return self
        val = self.func(instance)
        setattr(instance,self.func.__name__,val)  #则将val 放置到p1字典里面,key的值为type
        #取一个函数的函数名称为 type.__name__  则在该类里面type为 self.func
        return val
    def __set__(self, instance, value):
        pass

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height

    @testproperty  #type=testproperty(type)  就相当于在类People 添加一个类属性
    def type(self):
        return self.name

p1 = People('SUSU',90,'1米65')
print(p1.__dict__)
print(p1.type)
print(p1.__dict__)
print(p1.type)
print(p1.type)

以上代码执行结果如下:

{'name': 'SUSU', 'age': 90, 'height': '1米65'}
get方法
SUSU
{'name': 'SUSU', 'age': 90, 'height': '1米65'}
get方法
SUSU
get方法
SUSU

是因为实例属性优先级低于数据描述符;每次运行查找数据描述符

 五、

property 的 getter,setter 和 deleter 方法同样可以用作装饰器

class People:
    def __init__(self,name,age,height):
        self.name = name
        self.age = age
        self.height = height
    @property  #read() 方法转化成同名只读属性的 getter 方法
    def read(self):
        print(self.name)
        return self.name
    @read.setter
    def read(self,val):
        self.name = val
        print(self.name)
        return  self.name
    @read.deleter
    def read(self):
        print('删除')
        del self.name
#只有在属性read定义property 后才能定义read.setter,read.deleter
p1 = People('susu',18,'hahh')
print(p1.__dict__)
p1.read
p1.read = 'xioa'
del p1.read
print(p1.__dict__)

 以上代码执行结果如下:

{'name': 'susu', 'age': 18, 'height': 'hahh'}
susu
xioa
删除
{'age': 18, 'height': 'hahh'}

 另外一种方法使用

property() 函数的作用是在新式类中返回属性值。

class property([fget[, fset[, fdel[, doc]]]])
  • fget -- 获取属性值的函数
  • fset -- 设置属性值的函数
  • fdel -- 删除属性值函数
  • doc -- 属性描述信息
class People:
    def __init__(self,name,age,height):
        self._name = name
        self.age = age
        self.height = height

    def get_name(self):
        print(self._name)
        return self._name

    def set_name(self,val):
        self._name = val
        print(self._name)
        return  self._name

    def del_name(self):
        print('删除')
        del self._name
    name = property(get_name,set_name,del_name,"I'm the 'x' property.")

p1 = People('susu',18,'hahh')
print(p1.__dict__)
p1.name
p1.name= 'xioa'
del p1.name
print(p1.__dict__)
"""
以上代码执行结果如下
{'_name': 'susu', 'age': 18, 'height': 'hahh'}
susu
xioa
删除
{'age': 18, 'height': 'hahh'}
"""
class property([fget[, fset[, fdel[, doc]]]])

 

posted @ 2019-11-27 17:50  槑槑DE  阅读(207)  评论(0编辑  收藏  举报