创建可管理的类属性

对实例属性的set或get进行额外的处理(例如,类型检查或验证)。
可以使用类property对属性进行set,get,delete的定制化。类签名如下:
class property(fget=None, fset=None, fdel=None, doc=None)
返回一个property的属性,fget是用于获取属性值的函数。 fset是用于设置属性值的功能。 fdel是用于删除属性值的函数。 doc为该属性创建一个docstring。
典型的用途是定义托管的属性x,如下:

class C:
    def __init__(self):
        self._x = None

    def getx(self):
        return self._x

    def setx(self, value):
        self._x = value

    def delx(self):
        del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")

如果c是C的实例,则c.x将调用getter,c.x = value将调用setter,而del c.x则是删除属性。

进一步的,可以使用property的装饰器,以下示例可以说明:

class Parrot:
    def __init__(self):
        self._voltage = 100000

    @property
    def voltage(self):
    """Get the current voltage."""
        return self._voltage

@property装饰器将voltage()方法转换为具有相同名称的只读属性的“getter”,并将voltage的文档字符串设置为“获取当前voltage”。
property对象具有可用作装饰器的getter,setter和deleter方法,这些方法创建属性的副本,并将相应的访问器函数设置为装饰函数。 最好用一个例子解释一下:

class Person:
    def __init__(self, first_name):
        self.first_name = first_name

    # Getter function
    @property
    def first_name(self):
        return self._first_name

    # Setter function
    @first_name.setter
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._first_name = value

    @Deleter function (optional)
    @first_name.deleter
    def first_name(self):
        raise AttributeError("Can't delete attribute")

在前面的代码中,有三个相关的方法,所有这些方法都必须具有相同的名称。 第一种方法是getter函数,并将first_name建立为属性。 另外两个方法将可选的setter和deleter函数附加到first_name属性。 需要强调的是,除非已使用@property将first_name设置为属性,否则将不会定义@ first_name.setter和@ first_name.deleter装饰器。

property的关键特征是它看起来像普通属性,但是访问会自动触发getter,setter和deleter方法。

>>> a  = Person('Guido')
>>> a.first_name    # Calls the getter
'Guido'
>>> a.first_name = 42   # Calls the setter
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-69-6341bdece797> in <module>
----> 1 a.first_name = 42

<ipython-input-64-2b97c0306ce4> in first_name(self, value)
      8     def first_name(self, value):
      9         if not isinstance(value, str):
---> 10             raise TypeError('Expected a string')
     11         self._first_name = value
     12     @first_name.deleter

TypeError: Expected a string

实现property时,底层数据(如果有)仍需要存储在某个地方。 因此,在get和set方法中,可以看到对_first_name属性的直接操作,这是实际数据所在的位置。 另外,可能会问为什么__init __()方法设置self.first_name而不是self._first_name。 在此示例中,属性的全部要点是在设置属性时应用类型检查。 因此,可能还希望在初始化期间进行此类检查。 通过设置self.first_name,设置操作将使用setter方法(而不是通过访问self._first_name来绕过它)。

property属性实际上是捆绑在一起的方法的集合。 如果检查带有property的类,则可以在property本身的fget,fset和fdel属性中找到原始方法。

>>> Person.first_name.fget
<function Person.first_name at 0x1006a60e0>
>>> Person.first_name.fset
<function Person.first_name at 0x1006a6170>
>>> Person.first_name.fdel
<function Person.first_name at 0x1006a62e0>
>>>

仅在确实需要对属性访问执行额外处理的情况下,才应使用property。

不要编写实际上不会添加任何额外内容的property。 一方面,它使代码更加冗长和混乱。 其次,这会使程序运行慢很多。 最后,它没有真正的设计优势。 具体来说,如果以后决定需要对普通属性添加额外的处理,则可以在不更改现有代码的情况下将其提升为property。 这是因为访问该属性的代码的语法将保持不变。

property也可以是定义计算属性的一种方式。 这些属性不是实际存储的,而是按需计算的。

import math
class Circle:
    def __init__(self, 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(4.0)
>>> c.radius 4.0
>>> c.area    # Notice lack of ()
50.26548245743669
>>> c.perimeter   # Notice lack of ()
25.132741228718345
>>>

在这里,property的使用形成一个非常统一的实例接口,因为半径,面积和周长都作为简单属性来访问,而不是简单属性和方法调用的混合。

最后,且重要的是:不要编写具有很多重复属性定义的Python代码。

原文地址:https://www.cnblogs.com/jeffrey-yang/p/12006167.html

时间: 2024-10-11 07:17:49

创建可管理的类属性的相关文章

python_如何创建可管理的对象属性

案例: 在面向对象编程中,我们把方法作为对象的接口,自己访问对象的属性可能是不安全的,或设计上不灵活,但是使用调用方法在形式上不如访问属性简洁 繁: circle.getRadius() circle.setRadius(5.0) #!/usr/bin/python3 from math import pi class Circle(): def __init__(self, radius): self.radius = radius # 获取半径接口 def get_radius(self):

创建可管理的对象属性

下面先创建一个计算面积的类: #!/usr/bin/env python #coding:utf-8 #Created by Andy @ 2017/7/1 from math import pi class Circle: def __init__(self, radius): self.radius = radius def get_radius(self): return self.radius def set_radius(self, value): if not isinstance(

7-4 如何创建可管理的对象属性

>>> help(property) Help on class property in module __builtin__: class property(object) | property(fget=None, fset=None, fdel=None, doc=None) -> property attribute | | fget is a function to be used for getting an attribute value, and likewise

谨慎修改Python的类属性

Python的类和类实例都是可变对象,可以随时给属性赋值,并且在原处修改. 在对类属性进行修改时需要特别小心,因为所有的类实例都继承共享类属性,除非实例本身存在和类属性同名的属性.对类属性进行修改,会影响到所有由这个类生成的实例. class CA(object): cls_pre = 'aaaaa' def __init__(self): self.obj_pre = 'bbbbb' a = CA() b = CA() print(a.cls_pre, a.obj_pre) print(b.c

【OC复合题】之定义一个学生类,需要有姓名,年龄,考试成绩三个成员属性,创建5个对象,属性可以任意值。(Objective-C)

题目: 定义一个学生类,需要有姓名,年龄,考试成绩三个成员属性,创建5个对象,属性可以任意值.(Objective-C) 1)    不使用@property,手动编写他们的访问器方法(getter和setter),注意内存管理(手动管理内存) 2)    增加一个便利构造器(快速构造器) 3)    使用NSLog输出学生对象时,输出信息格式为:My Name Is XXX  Age Is XXX Score Is XXX 4)    对5个学生对象按照成绩->年龄->姓名优先级排序(成绩相

django之创建第4-2个项目-访问class类属性和类方法

1.修改index <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>django之创建第4-2个项目</title> </head> <body> <h1>hello,{{test.name}}</h1> <!--模板 变量用变量定义--> &l

python3 速查参考- python基础 8 -&gt; 面向对象基础:类的创建与基础使用,类属性,property、类方法、静态方法、常用知识点概念(封装、继承等等见下一章)

基础概念 1.速查笔记: #-- 最普通的类 class C1(C2, C3): spam = 42 # 数据属性 def __init__(self, name): # 函数属性:构造函数 self.name = name def __del__(self): # 函数属性:析构函数 print("goodbey ", self.name) I1 = C1('bob') #-- Python的类没有基于参数的函数重载 class FirstClass: def test(self,

5.Swift枚举|结构体|类|属性|方法|下标脚本|继承

1. 枚举: ->在Swift中依然适用整数来标示枚举值,需搭配case关键字 enum  Celebrity{  case DongXie,XiDu,Nandi,BeiGai }  // 从左到右对应0,1,2,3 enum CompassPoint { case North case South case East case West //enum中可以定义方法 func show(){ print(self) } } //定义enum 变量 var p = CompassPoint.Nor

KVM虚拟化技术之使用Qemu-kvm创建和管理虚拟机

一.KVM简介 KVM(名称来自英语:Kernel-basedVirtual Machine的缩写,即基于内核的虚拟机),是一种用于Linux内核中的虚拟化基础设施,可以将Linux内核转化为一个hypervisor.KVM在2007年2月被导入Linux 2.6.20核心中,以可加载核心模块的方式被移植到FreeBSD及illumos上. KVM在具备Intel VT或AMD-V功能的x86平台上运行.它也被移植到S/390,PowerPC与IA-64平台上.在Linux内核3.9版中,加入A