python3與django中@property詳解

django提供了內置裝飾器java

@staticmethod\@classmethod\propertypython

 

在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就能夠避免遞歸錯誤。

相關文章
相關標籤/搜索