django提供了内置装饰器

@staticmethod\@classmethod\property

在OSQA中,@property的使用频率是非常高的。下面就是它的使用方法:

@property 可以将python定义的函数“当做”属性访问,从而提供更加友好访问方式,和java中的setter和getter类似。

models.py中如下:

from django.db import models

class Person(models.Model):
G=(('chen','jian'),('hong','yi'),('rt','ju'))
gender=models.CharField(max_length=20,choices=G) @property
def Gender(self):
return self.gender @Gender.setter
def Gender(self,new_value):
self.gender=new_value

在views.py中使用:

from django.http import HttpResponse
from mytest.models import *
def index(request):
print Person.objects.all()[0].Gender
b=Person.objects.all()[0]
b.Gender='adfasfasd'
print b.Gender
b.save()
return HttpResponse(Person.objects.all()[0].Gender)

@property提供的是一个只读的属性,如果需要对属性进行修改,那么就需要定义它的setter。

#########python3中

@staticmethod:静态方法,静态方法是不可以访问实例变量或类变量的,这个类方法实际上跟类没有什么关系,它只是类下面的一个函数,跟类本身没关系,只是名义上归类管。
它与类唯一的关联就是需要通过类名来调用这个方法
如果非要传参数,只有传自己
@classmethod:类方法只能访问类变量,不能访问实例变量
@property :属性方法,属性方法的作用就是通过@property把一个方法变成一个静态属性
例如:
1 class Dog(object):
2 def __init__(self,name):
3 self.name=name
4 @property #把一个方法变成一个静态属性
5 def eat(self):
6 print('%s is eating %s' %(self.name,'包子'))
7 d1=Dog('Jack')
8 d1.eat #不加(),输出:Jack is eating 包子
 1 #如果要传参数
2 class Dog(object):
3 def __init__(self,name):
4 self.name=name
5 self.__food=None
6 @property
7 def eat(self):
8 print('%s is eating %s' %(self.name,self.__food))
9
10 @eat.setter
11 def eat(self,food):
12 print('要传的参数:',food)
13 self.__food=food
14 d1=Dog('Jack')
15 d1.eat
16 d1.eat='包子'
17 d1.eat #self.__food=food把参数传值了再执行属性方法

摘自其他人笔记

定义类Student,拥有变量名name和score

1 class Student(object):
2 def __init__(self,name,score):
3 self.name = name
4 self.score = score

但是,上述这样定义score是不会进行参数检查的,也就意味着我们不能执行必要的参数以及错误处理。

我们可以定义相应的set和get成员函数来访问成员变量score,并且进行参数检查。如下所示:

 1 class Student(object):
2 def __init__(self,name,score):
3 self.name = name
4 self.score = score
5 def get_score(self):
6 return self.score
7 def set_score(self,score):
8 if not isinstance(score, int):
9 raise ValueError(”invalid score!!!”)
10 if score < 0 or score > 100:
11 raise ValueError(”score must be between [0,100]!!!”)
12 self._score = score

上述代码定义了score成员的set和get函数。(可能实际应用时,修改分数比较常见)

现在,我们改变参数的代码是这样的:

1 s1 = Student()
2 s1.set_score(9999) #这里会抛出异常

上述的第二种方式实现了set函数的参数检查,但是修改score的代码从简单的 s1.score = 90 变成了 s1.set_score(90) .我们怎么样才能做到既检验输入的参数又使得修改score的代码不变呢?

@Property便是这个作用。

下面,我们讨论Python的高级特性 @Property。简单的说@Properyty就是将成员函数的调用变成属性赋值。

于是有了下面的代码:

 1 class Student(object):
2 def __init__(self,name,score):
3 self._name = name
4 self._score = score
5 @property
6 def score(self):
7 return self._score
8 @score.setter
9 def score(self,score):
10 if not isinstance(score,int):
11 raise ValueError(”invalid score!!!”)
12 if score < 0 or score > 100:
13 raise ValueError(”score must be between [0,100]!!!”)
14 self._score = score
15 @property
16 def name(self):
17 return self._name
18
19 s1 = Student(”Lily”, 90)
20 s1.name = ”Luly”
21 s1.score = 100

关于上述代码的说明:

  • 可能你已经发现了,我的成员变量改成了_name 与 _score,这里首先是为了增加可读性,这两个变量是私有的。其次的原因见下面的误区分析。
  • 上述代码中的 s1.name = “Luly” 行会出现编译错误 AttributeError: can’t set attribute ,也就是说这里不能直接这样改变,这是为什么呢?可以看到,在代码中,我并没有提供名称为name的set函数, 这里值得注意的是,s1._name = “Lucy” 是可以运行通过的。但是我们之前说过了,假设用户足够自觉,不会去操作 _xxx 或者 __xxx这样的变量名。
  • 按照上述代码的初衷,也就是说name是类的只读的属性。score是可修改的。
  • 关于@property 修饰的函数 score 就是个简单的get函数,该函数不需要任何参数(self不需要传入值),因此我们可以这样来调用这个函数 ,即 s1.score 即可。(这就是Property的用处,将函数调用转化为属性访问),相当于给score加了一层包裹。
    • 关于@score.setter 便是针对与 score函数包裹的成员变量的的set函数。当我们需要修改_score的值时,使用score函数,但是就像score是类的成员属性一样使用,例如上面的: s1.score = 100,实际上等价于 s1.score(100).

      注意,这里的函数名不一定要是score,可以是任何的字符串,这里只是为了方面说score函数是_score的包裹,例如下面的代码:我们将score改成了AA,但是这样在:

  •  1 class Student(object):
    2
    3 def __init__(self,name,score):
    4 self._name = name
    5 self._score = score
    6
    7 @property
    8 def AA(self):
    9 return self._score
    10 @AA.setter
    11 def AA(self,score):
    12 if not isinstance(score,int):
    13 raise ValueError(“invalid score!!!”)
    14 if score < 0 or score > 100:
    15 raise ValueError(“score must be between [0,100]!!!”)
    16 self._score = score
    17 @property
    18 def name(self):
    19 return self._name
    20
    21 s1 = Student(”Lily”, 90)
    22 s1.name = ”Luly”
    23 s1.AA = 100 # 这里相当于是 s1.AA(100)
     

    好了,关于@Property的概念与用法就讲完了。本质上是定义了新的函数,该函数们执行set与get的功能,并且有@Property的包裹。并且将这些定义的函数当作属性一样来赋值。

    可能存在的陷阱:

    下面的代码是个大的陷阱,因为现在的函数已经不再是单纯的函数,而是可以直接用 = 来调用,例如上面的 score函数 的调用竟然是 s1.score = 100 .这样就会出现下面的问题:

  •  1 class Student(object):
    2 def __init__(self,name,score):
    3 self.name = name
    4 self.score = score
    5 @property
    6 def score(self):
    7 return self.score
    8 @score.setter
    9 def score(self,score):
    10 if not isinstance(score,int):
    11 raise ValueError(”invalid score!!!”)
    12 if score < 0 or score > 100:
    13 raise ValueError(”score must be between [0,100]!!!”)
    14 self.score = score
    15 @property
    16 def name(self):
    17 return self.name
    18 def func(self):
    19 self.score = score
    20
    21 s1 = Student(”Lily”, 90)
    22 s1.func()
     

    上面的代码有两个很大的错误,

    • 你会发现,你无法定义Student的任何实例,为什么呢? 首先@property把score和name两个成员函数可以当作成员变量来访问,那么在定义实例时,调用init函数的时候,self.name = name,这一句,Python会将左端的self.name当作函数调用,然而我们并未给name变量 定义set函数,于是错误信息为:AttributeError: can’t set attribute.
    • 好的,我们接下来注释掉
  • 1 @property
    2 def name(self):
    3 return self.name

    这两行,那么接下来的运行还是错误的,为什么呢?是因为init函数代码的第二行 self.score = score, 很庆幸我们定义了score的set函数, 那么self.score调用score函数,当执行到score函数的最后一句self.score = score时, 我们回发现,式子的左端还是score函数调用, 如此往复,最终以函数递归深度达到上限退出程序。

    这里其实是一个很好的代码习惯,那就是尽量不要让函数名与变量名同名,便可以避免这些错误。所以,比如说,这里的变量名self.score改为:self._score就可以避免递归错误。

 
 

python3与django中@property详解的更多相关文章

  1. django中模型详解-字段类型与约束条件

    这片博文来详细说明django模型的使用,涉及到django模型的创建,字段介绍,以及django模型的crud操作,以及一对一等操作. 在使用模型之前,我们首先设置数据库选项,django的默认数据 ...

  2. Django中ModelForm详解

    1.ModelForm组件介绍:这个组件的功能就是把model和form组合起来 2.ModelForm的使用 1.首先需要导入ModelForm from django.forms import M ...

  3. (转)python中@property详解

    转:https://www.cnblogs.com/zhangfengxian/p/10199935.html

  4. Objective-C中的@Property详解

    Objective-C中的@Property详解 @Property (属性) class vairs 这个属性有nonatomic, strong, weak, retain, copy等等 我把它 ...

  5. iOS中-Qutarz2D详解及使用

    在iOS中Qutarz2D 详解及使用 (一)初识 介绍 Quartz 2D是二维绘图引擎. 能完成的工作有: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成 ...

  6. Python中dict详解

    from:http://www.cnblogs.com/yangyongzhi/archive/2012/09/17/2688326.html Python中dict详解 python3.0以上,pr ...

  7. Django入门基础详解

    本次使用django版本2.1.2 安装django 安装最新版本 pip install django 安装指定版本 pip install django==1.10.1 查看本机django版本 ...

  8. 【转】angular中$parse详解教程

    原文: https://yq.aliyun.com/ziliao/40516 ------------------------------------------------------------- ...

  9. 第五篇Django URL name 详解

    Django URL name 详解 利用Django开发网站,可以设计出非常优美的url规则,如果url的匹配规则(包含正则表达式)组织得比较好,view的结构就会比较清晰,比较容易维护. Djan ...

随机推荐

  1. uvm_tlm——TLM1事务级建模方法(一)

    TLM(事务级建模方法,Transaction-level modeling)是一种高级的数字系统模型化方法,它将模型间的通信细节与函数单元或通信架构的细节分离开来.通信机制(如总线或者FIFO)被建 ...

  2. python3基础11(正则表达式及re模块)

    #生成re对象 compile# 之后再期调用 match search 返回匹配到的字符串# findall 返回匹配结果的列表#如果要对匹配的结果进行分组,可加(),并可通过\数字 去应用

  3. Visual Studio 更改护眼颜色

  4. linux下获取外网IP

    使用阿里云或者有多个网卡IP的机器需要取外网IP时,可以用下面这种 wget -qO - ifconfig.co 更多方法参考:https://yq.aliyun.com/ziliao/105999

  5. [转] python 远程主机强迫关闭了一个现有的连接 socket 超时设置 errno 10054

    python socket.error: [Errno 10054] 远程主机强迫关闭了一个现有的连接.问题解决方案: 前几天使用python读取网页.因为对一个网站大量的使用urlopen操作,所以 ...

  6. samba性能调优,调优后,性能增加30%

    global中增加下面内容. [global]    use sendfile = yes    write raw = yes    read raw = yes    max xmit = 655 ...

  7. Java不同对象之间复制属性

    // 导入包import org.springframework.beans.BeanUtils; /** * 调用工具复制2个对象之间的属性 2个JavaBean对象复制的属性名相同 * @para ...

  8. IntelliJ IDEA中激活JRebel插件

    1. 下载激活软件:https://github.com/ilanyu/ReverseProxy/releases/tag/v1.0 我下载的是 2. 双击文件运行 3. 点击change licen ...

  9. CUDA:Supercomputing for the Masses (用于大量数据的超级计算)-第六节

    原文链接 第六节:全局内存和CUDA RPOFILER  Rob Farber 是西北太平洋国家实验室(Pacific Northwest National Laboratory)的高级科研人员.他在 ...

  10. js表单序列化时,非空判断

    在项目中,对于数据的传输一般需要非空的判断,而数据字段较多时一般直接将表单序列化,此时如何判断非空,如下 因为将表单序列化时,数据格式为 trainKind=1&trainKindCode=1 ...