在OSQA中,@property的使用频率是很是高的。下面就是它的使用方法:django
@property 能够将python定义的函数“当作”属性访问,从而提供更加友好访问方式,和java中的setter和getter相似。函数
models.py中以下:post
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中使用:spa
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。code
#########python3中blog
@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就能够避免递归错误。