python類屬性@property(全) tcy

1.屬性

屬性定義:
    python中屬性其實是普通方法的衍生

屬性操作:
    用@property裝飾器操作類屬性
    用類或實例直接操作類屬性obj.name,obj.age=18,del obj.age
    用python內置函數操作屬性

屬性意義:
    訪問屬性時類似訪問字段象,屬性由方法衍生而來,如Python沒有屬性,方法完全可代替其功能
    可動態獲取屬性值,應用更靈活;可制定屬性規則,防隨意修改屬性值

屬性函數:
    hasattr(object, name)                #判斷是否包含指定的屬性或方法
    getattr(object, name[,default])    #獲取對象屬性或方法;無拋AttributeError
    setattr(object, name, values)      #對象屬性賦值(修改或創建)
    delattr(obj, name):                  #刪除屬性無拋AttributeError,無返回值
    type.__dict__                            #類屬性-類實例變量
    dir                                            #返回當前範圍的所有屬性名稱列表

內置屬性:
     __dict__ :     #獲取類所有信息返回字典{屬性:屬性值}
    __doc__ :      #類文檔字符串
    __name__:    #類名
    __module__:  #類定義所在模塊 當前模塊返回’__main__’
    __bases__ :  #類所有父類元組   
    
property():
    語法:property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
    說明:
        fget 獲取屬性值方法
        fset 設置屬性值方法
        fdel 刪除屬性值方法
        doc 屬性描述信息;如省略,會把 fget 方法的docstring 拿來用(如果有話) 
    注意:
        類名.屬性.__doc__ #查看屬性文檔字符串Student.age.__doc__
    
屬性裝飾器:
    用途:把方法包裝成屬性;在獲取,設置,刪除屬性時需額外做一些工作
                實現getter,setter,deleter功能,對屬性的取值和賦值加以控制,提高代碼的穩定性
                @property 語法糖提供比 property() 函數更簡潔直觀寫法
    格式:
        @property      獲取屬性值的方法,被裝飾方法的名字會被用做 屬性名
        def func(self):僅有一個self參數,調用時無需括號
        
        @屬性名.setter 裝飾的方法是設置屬性值的方法
        @屬性名.deleter 裝飾的方法是刪除屬性值的方法
    
    注意:
        描述符只對實例方法有效,對於靜態方法、類方法都無法使用
        不能通過在__init__()和其他方法中創建描述符對象來爲每個實例創建描述符
2.實例:屬性操作

實例1:#用類或實例直接操作類屬性

#實例.屬性; 類.屬性   對類的屬性沒有操作控制規則,容易被修改
class Student:
    total = 10
    def __init__(self,name='Tom',age=22):
        self.name = name
        self.age=age
  
    def view(self):
        print(self.name,self.age)
        
    def add(self,x,y):
        return x+y
    
#屬性操作:查看賦值刪除    
s=Student()
hasattr(s, 'age')# True

s.age               # 等價:getattr(s,'age')      查找屬性調用obj.__getattrribute__(‘name’)
del s.age         # 等價:delattr(s,'age')      刪除屬性調用obj.__delattr__(‘name’)
s.age=20         # 等價:setattr(s,'age',20) 設置屬性調用obj.__setattr__(‘name’,value)
實例2:內置函數操作屬性
getattr(s,'age')
delattr(s,'age')
setattr(s,'age',20)

 

實例3:屬性裝飾器

實例3.1:
class Person(object):
    def __init__(self):
        self._age=None
        
    def get_age(self):    
        return self.age
        
    def set_age(self, value):
       if value <= 0 or value > 200:raise ValueError('age must between 0 ~ 200!')
       self.age = value
    
s = Person()
s.set_age(30);print(s.get_age(),end=',')
del s.age;print(hasattr(s, 'age')) # 30,False
實例3.2:
class Person():    #新式類
    def __init__(self):
        self._age=None
        
    @property        #getter方法變成屬性@property等同age = property(fget=age)
    def age(self):
        return self._age

    @age.setter      #把一個setter方法變成屬性賦值
    def age(self, value):
        if value <=0 or value > 200:raise ValueError('age must between 0 ~ 200!')
        self._age = value
        
    @age.deleter  # 刪除屬性
    def age(self):
        del self._age
        
s = Person()
s.age = 30                                # 實際轉化爲s.set_age(60)
print(s.age,end=',')                    # 實際轉化爲s.get_age()
del s.age;print(hasattr(s, 'age')) # 30,False
實例3.3:#舊版定義-不建議使用直接用@property
class Person(object):
    def __init__(self):
        self._age=None
        
    def get_age(self):
       return self._age
       
    def set_age(self,value):
       if value <=0 or value > 200:raise ValueError('age must between 0 ~ 200!')
       self._age=value
       
    def del_age(self):
        del self._age# raise TypeError("Can't delete age")

    age=property(get_age,set_age,del_age,'文檔')#增加property類

s = Person()
s.age = 30;print(s.age,end=',')               
del s.age;print(hasattr(s, 'age')) # 30,False
實例4:#查看類屬性

s.__dict__                       # {'name': 'Tom', 'age': 20}  類實例變量  
s.__dict__['id']=1020120   # 對實例的修改反應到局部__dict__屬性中
s.__dict__                       # {'name': 'Tom', 'age': 20, 'id': 1020120}

s.__class__                    # <class '__main__.Student'>

# __dict__ 獲取屬性列表:
Student.__dict__.keys()   # dict_keys(['__module__', 'total', '__init__', 'view', 'add', '__dict__', '__weakref__', '__doc__'])   

s.__dir__()                      # 等價dir(s)   ['name','age','id','total', 'view','add',...]
dir(Student)                    # [ 'add', 'total','view',...]
Student.__dir__(Student) # [ 'mro',...]

# 使用 inspect 包功能來過濾:
import inspect

#獲取屬性
[i for i in dir(s) if not callable(getattr(s, i)) and i[0]!='_']# ['age', 'id', 'name', 'total']

#獲取內置函數
[i for i in dir(s) if inspect.isbuiltin(getattr(s, i))]              # ['__dir__','__format__',...]

# 獲取函數:
[i for i in dir(s) if inspect.isfunction(getattr(s, i))]                # []

# 獲取可調用對象:
[i for i in dir(s) if inspect.isroutine(getattr(s, i)) and i[0]!='_']# ['add', 'view']
實例5:備註

實例5.1:特性的繼承--不建議使用

實例5.1.1:完全重寫父類property
#在子類中重新定義一個同名getter函數,再加上@propety裝飾器即可
class Student(Person):
    def __init__(self):
        self._age=None
        
    @property
    def age(self):
        return self.age
實例5.2.2:重寫父類property的某些方法
class Girl(Person):
    def __init__(self):
        self._age=None
        
    @property
    def age(self):
        return super().age
        
    @age.setter
    def age(self, value):
        super(Girl, Girl).age.__set__(self, value)
實例5.2:
class  PropertyTyped (object):#不建議使用-直接用@property
    '''
    定義一個描述符分配屬性進行類型檢查,如果嘗試刪除屬性,它將引發錯誤
    '''
    def __init__( self, name,type, default=None):
        self.name='_'+name
        self.type=type
        self.default=default if default else type()
        
    def __get__(self,instance,cls):
        return   getattr (instance, self.name, self. default)
        
    def __set__(self,instance, value):
        if not isinstance (value,self.type):
            raise  TypeError("Must be a%s"% self.type)
     
        setattr (instance, self.name, value)
        
    def __delete__(self, instance):
        raise  AttributeError ( "Can't  delete  attribute" )
        
class  Boy (object):
    name=PropertyTyped("name", str)
    num=PropertyTyped ("num", int, 42)
        
b=  Boy()
a= b.name          #隱式調用Boy.name.__get__(f,Foo)
b.name="Tom"    #調用Boy.name.__ set__(f, "Tom")
del b.name         #調用Boy.name.__delete__(f)
實例5.3:#純Python等效項property():
class Property(object):
    "Emulate PyProperty_Type() in Objects/descrobject.c"
    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc
    
    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章