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__ #
# __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__)