Python中的属性Property-getter、setter、deleter

转自:https://www.cnblogs.com/crwy/p/6852347.html

通常,我们这样定义属性:

class Animal(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

即在实例初始化时,__init__函数中赋值,其中值可为实例访问:

a = Animal('black dog', 3)
print 'Name:', a.name
print 'Age:', a.age
a.color = 'Black'
print 'Color:', a.color

结果为:

Name: black dog
Age: 3
Color: Black

看到了吧?运行期,能动态为实例添加属性,比如color。但此方法所添加,只能作用于此实例,而无影响于类怎么限制它?
用__slots__这个东西。比如,__slots__ = ['name', 'age'],则类只能添加这两个属性,蛋疼,不好用如果想要在运行期给类添加属性,要用到MethodType这东西,例如:

def set_color(self, color):
    self.color = color
Animal.set_color = MethodType(set_color, None, Animal)

a1 = Animal('yellow dog', 3)
a1.set_color('Yellow')
print a1.color

……喔,有点凌乱,还是不好用!或者说,不好记,心里没谱儿。

3、@property(推荐)

习惯了高级语言的严谨,总想对属性加以访问控制,相对安全些,比如直接在__init__中定义公用属性,从封装性来说,它是不好的写法。
属性之访问,它亦有机制,其一便是@propery关键字。用此关键字,其获取、设置函数,须与属性名一致。
@property可以把一个实例方法变成其同名属性,以支持.号访问,它亦可标记设置限制,加以规范,如下代码:

class Animal(object):
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._color = 'Black'

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        if isinstance(value, basestring):
            self._name = value
        else:
            self._name = 'No name'

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        if value > 0 and value < 100:
            self._age = value
        else:
            self._age = 0
            # print 'invalid age value.'

    @property
    def color(self):
        return self._color

    @color.setter
    def color(self, value):
        self._color = value;
    

a = Animal('black dog', 3)
a.name = 'white dog'
a.age = 300
print 'Name:', a.name
print 'Age:', a.age

这样在设定值时候,总算有个判断取舍,是不是好一些?
私有变量以_开头,是种编码约定,当然也可以直接访问它。
不过既如此写,直接访问是不推荐的。
若真要为私有变量,则加双下划线,比如__name,也一样阻止不了访问,但让我们知道,它不想被直接用到,如下代码:

class Animal(object):
    def __init__(self, name):
        self.__name = name

a = Animal('black dog')
print a._Animal__name

4、property函数
它以一个函数形式,定义一个属性,与@property实现原理类似,或者就是它的的变异用法。
其原型为:

property(fget=None, fset=None, fdel=None, doc=None)

譬如上面Animal类,其可用此改为:

class Animal(object):
    def __init__(self, name, age):
        self._name = name
        self._age = age
        self._color = 'Black'

    def get_name(self):
        return self._name

    def set_name(self, value):
        if isinstance(value, basestring):
            self._name = value
        else:
            self._name = 'No name'

    name = property(fget=get_name, fset=set_name, fdel=None, doc='name of an animal')

    def get_age(self):
        return self._age

    def set_age(self, value):
        if value > 0 and value < 100:
            self._age = value
        else:
            self._age = 0
            # print 'invalid age value.'

    age = property(fget=get_age, fset=set_age, fdel=None, doc='name of an animal')
    

a = Animal('black dog', 3)
a.name = 'white dog'
a.age = 3
print 'Name:', a.name
print Animal.name.__doc__
print 'Age:', a.age

其输出结果一样,看来只是写法不同。

###################################################################################################

转自另外一篇:https://www.cnblogs.com/wangyongsong/p/6750454.html

1 什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

import math
class Circle:
    def __init__(self,radius): #圆的半径radius
        self.radius=radius

    @property
    def area(self):
        return math.pi * self.radius**2 #计算面积

    @property
    def perimeter(self):
        return 2*math.pi*self.radius #计算周长

c=Circle(10)
print(c.radius)
print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
'''
输出结果:
314.1592653589793
62.83185307179586
'''

注意:此时的特性arear和perimeter不能被赋值

c.area=3 #为特性area赋值
'''
抛出异常:
AttributeError: can't set attribute
'''

2 为什么要用property

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

除此之外,看下

ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    @property
    def name(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    @name.setter
    def name(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    @name.deleter
    def name(self):
        raise TypeError('Can not delete')

f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
class Foo:
    def __init__(self,val):
        self.__NAME=val #将所有的数据属性都隐藏起来

    def getname(self):
        return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置)

    def setname(self,value):
        if not isinstance(value,str):  #在设定值之前进行类型检查
            raise TypeError('%s must be str' %value)
        self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME

    def delname(self):
        raise TypeError('Can not delete')

    name=property(getname,setname,delname) #不如装饰器的方式清晰

一种property的古老用法

一种property的古老用法

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值