在交互式环境中输入:

 >>> class A:
a=0
def __init__(self):
self.a=10
self.b=100 >>> a=A()
>>> a.a
10
>>> a.b
100
>>> A.a
0
>>> A.b
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
A.b
AttributeError: type object 'A' has no attribute 'b'
>>>

如下图:


还是在交互式环境中:

 >>> class A:
a=0
def __init__(self):
self.a=10
self.b=100 >>> a=A()
>>> getattr(a,'a')#用getattr()函数获取实例a中a属性的值
10
>>> setattr(a,'a',20)#设置实例a中a属性的值为20
>>> getattr(a,'a')#用getattr()函数获取实例a中a属性的值
20
>>> hasattr(a,'b')#测试实例a中是否包含属性b
True

图片展示:

这种反射机制的用字符串来操作类的属性和方法的三个函数并不常用。编写框架等特殊项目是采用到。


 class Washer:

     def __init__(self,water=10,scour=2):
self._water=water #不想让用户直接访问实例变量,可以标志成私有
self.scour=scour
#属性包装,将water属性包装成方法,用户使用water时实际是访问的方法
@property
def water(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性
return self._water def set_water(self,water):
self.water=water def set_scour(self,scour):
self.scour=scour def add_water(self):
print('Add water:',self.water) def add_scour(self):
print('Add scour:',self.scour) def start_wash(self):
self.add_water()
self.add_scour()
print('Start wash...') if __name__=='__main__':
w=Washer()
#w.start_wash()
print(w.water)# 可以像访问属性一样访问方法

但这时用户仍然可以通过w._water来访问实例属性,封装的不好,也不会自动检查数据是不是浮点型,不好。

怎么解决?

用@属性.setter

 class Washer:

     def __init__(self,water=10,scour=2):
self._water=water #不想让用户直接访问实例变量,可以标志成私有
self.scour=scour
#属性包装,将water属性包装成方法,用户使用water时实际是访问的方法
@property
def water(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性
return self._water @water.setter #新添加代码
def water(self,water):
if 0<water<=500:
self._water=water
else:
print('set Failure!') def set_water(self,water):
self.water=water def set_scour(self,scour):
self.scour=scour def add_water(self):
print('Add water:',self.water) def add_scour(self):
print('Add scour:',self.scour) def start_wash(self):
self.add_water()
self.add_scour()
print('Start wash...') if __name__=='__main__':
w=Washer()
print(w.water)# 可以像访问属性一样访问方法
#w._water=20 #为了不让用户这样直接给实例属性赋值,用下面的语句
w.water=123 #可以像给属性赋值一样给方法赋值,并检测范围
print(w.water)# 可以像访问属性一样访问方法

结果:

另外,很好奇@water.setter这个water到底是个什么东西,发现可以理解成一个新的实例属性,跟构造函数的形参没有关系。比如下图

再比如:

结果仍为:

同样可以包装一个删除变量,@water.delete

-------------------------------------

这块代码表示water这个变量可以重写,

------------------------------------------

上面这块代码表示water属性可以读取。

---------------------------------------------

最后一个用法是用属性装饰器@property来新定义一个虚拟的属性。

 class Washer:

     def __init__(self,water=10,scour=2):
self._water=water #不想让用户直接访问实例变量,可以标志成私有
self.scour=scour
self.year=2000#这是生产日期
#属性包装,将water属性包装成方法,用户使用water时实际是访问的方法
@property
def water1(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性
return self._water @water1.setter
def water1(self,water):
if 0<water<=500:
self._water=water
else:
print('set Failure!')
18 @property
19 def total_year(self): #定义一个虚拟实例属性,这个属性其实是一个方法,但是可以按照属性来用
20 return 2017-self.year def set_water(self,water):
self.water=water def set_scour(self,scour):
self.scour=scour def add_water(self):
print('Add water:',self.water) def add_scour(self):
print('Add scour:',self.scour) def start_wash(self):
self.add_water()
self.add_scour()
print('Start wash...') if __name__=='__main__':
w=Washer()
print(w.water1)# 可以像访问属性一样访问方法
#w._water=20 #为了不让用户这样直接给实例属性赋值,用下面的语句
w.water1=123
print(w.water1)# 可以像访问属性一样访问方法
print(w.total_year)

运行结果:


描述符

描述符的意义是避免重复写具有相同限定属性的实例属性的定义代码。比如下面的例子:

 class NonNeg:#数据描述符
def __init__(self,default=0):#构造方法
self.default=default#一个实例属性
def __get__(self,instance,owner):#协议方法
return self.default
def __set__(self,instance,val):#协议方法
if val>0:
self.default=val
else:
print('The value must be NonNegative!')
def __delete__(self,instance):#协议方法
pass
class Movie:
rating=NonNeg()#描述符类NonNeg作另一个类Movie的属性,rating是Movie的类属性。
score=NonNeg() if __name__=='__main__':
m=Movie()
print('rating:',m.rating)
print('score:',m.score)#输出默认值default
m.rating=80#使用__set__协议方法
print('rating:',m.rating)#使用到 __get__协议方法
m.score=-3
print('score:',m.score)

输出结果:

---------------------------------------

下面说明所有的 类成员函数都是非数据描述符。

在这个交互式环境中可以看出pr这个类方法仅有__get__协议,三个不全,所以是非数据描述符。

----------------------------------------------------------------

同名的实例属性和非数据描述符(以类方法为例)同时出现时,访问的优先级是什么?

再看:

为啥结果还不一样了?再做一遍老师的例子:

重新打开idel之后重新写了一遍:

总结如下:

在交互式环境中,

若在类内实例方法中定义与此方法名想同的实例变量pr,则在类外实例化此类后,实例.pr 首先访问的是此实例变量,实例.pr() 肯定访问的是类内实例方法。若再类外实例中定义一个  实例.pr=20,则再访问 实例.pr时则访问的是刚定义的实例属性 实例.pr=20。

若在类内没有定义与类方法同名的实例属性,则实例.pr访问的是类内的实例方法,若又在类实例化后实例下定义同名的的实例属性pr,则 实例.pr访问的刚定义的。。。

感觉好混乱:若访问过t.pr()再访问t.pr,t.pr就为10了,若没有访问过t.pr()直接访问t.pr,这个就先访问的是method Tst.pr of <__main__.Tst object,也就是一个方法了。

 class Tst:
def pr(self):
self.pr=10
print('Tst')
t1=Tst()
t1.pr()#输出Tst
t1.pr#啥都没有输出
print(t1.pr)#输出10
print('下面实例化后不访问t.pr()直接访问t.pr:')
t2=Tst()
t2.pr#啥都没输出
print(t2.pr)#输出了bound method Tst.pr of <__main__.Tst object

但后来在实例下新定义的同名实例属性会覆盖原先类中定义的实例方法。优先级知道了吧。


扩展:

 class Tst:
def __init__(self,default=1):
self.water=default
def __call__(self):
print('包含call函数的类,他的实例可以直接当做函数使用。')
def info(self):
print("pass") t=Tst()
t()

当调用t()时只调用类中__call__函数。

--------------------------------------------


解答如下:

 class surfaceNum:#定义一个描述类
def __init__(self,default=1):
self.number=default
def __get__(self,instance,owner):#参数instance和owner暂时没有用到,只有self是固定名参数
return self.number
def __set__(self,instance,val):#参数instance暂时没有用到
if 0<val<7 and isinstance(val,int)==True:
self.number=val
Box.info_num(self)#Box类还没有创建,故不能引用Box.infor_num,哈哈,能创建啊
else:
print('please set the correct surface number!')
def __delete__(self,instance):#协议方法
pass class Box:#定义一个类名为Box,类名后不必有括号,类包含类属性和类方法,这个类没有定义类属性
'''这是一个计算体积的类'''#这是这个类的__doc__属性,执行类后就可以在交互界面输入Box.__doc__查看这行说明文字了
openstate=0
number=surfaceNum()
def __init__(self):#这是类的构造函数,当实例化Box后会自动调用这个__init__方法
self.length=0.0 #这是实例属性,在类内访问用self.length,在类外访问用 实例名.length
self.width=0.0
self.height=0.0
self._color='red'
self.__valum=0.0#双下换线开头的变量表示私有变量,所以他为私有实例属性,只能在类内访问到 @property
def color(self):
return self._color
@color.setter
def color(self,color):
self._color=color def set_color(self,color):
self._color=color def computevalum(self):#定义了一个类方法。
self.__valum=self.length*self.width*self.height
print('长度=',self.length,'宽度=',self.width,'高度=',self.height,'valum=',self.__valum) def info_color(self):
#self.set_color(self._color)#在类中,函数调用函数的方式
print('Box的颜色为',self._color) def open_box(self):
if Box.openstate==0:
print('打开了Box')
Box.openstate=1
else:
print('Box已经打开了,不能重复打开')
def info_num(self):
#self.set_color(self._color)#在类中,函数调用函数的方式 print('Box面上的数字为',Box.number)
#定义 __call__ 函数,输出体积
def __call__(self):
self.__valum=self.length*self.width*self.height
print('长度=',self.length,'宽度=',self.width,'高度=',self.height,'调用自身computa()输出:valum=',self.__valum) if __name__=='__main__':
computa=Box() #实例化Box类
computa.number =2
computa.info_num()
computa.length=1
computa.width=2
computa.height=3
computa.computevalum()
computa()#实例名函数调用__call__函数直接输出体积
computa.set_color ('yellow')
computa.info_color()
computa.open_box()
computa.color='green'
computa.info_color()
print('') computb=Box()#实例化Box类
computb.length=2
computb.width=2
computb.height=3
computb.computevalum()
computb.set_color ('black')
computb.info_color()
computb.open_box()

这个题目是上节课题目的拔高,上节课题目及解答见链接http://www.cnblogs.com/zhubinglong/p/6942289.html

python面向对象-2深入类的属性的更多相关文章

  1. Python面向对象静态方法,类方法,属性方法

    Python面向对象静态方法,类方法,属性方法 属性: 公有属性 (属于类,每个类一份) 普通属性 (属于对象,每个对象一份) 私有属性 (属于对象,跟普通属性相似,只是不能通过对象直接访问) 方法: ...

  2. Python面向对象06 /元类type、反射、函数与类的区别、特殊的双下方法

    Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 目录 Python面向对象06 /元类type.反射.函数与类的区别.特殊的双下方法 1. 元类type 2. 反射 3 ...

  3. Python面向对象之接口类(抽象类)

    Python面向对象之接口类(抽象类):就是制定一个规范. 比如定义了一个接口类(抽象类)(他们是不可以进行实例化的,这就是他为什么是制定一个规范的原因). 他的定义是需要abc模块,要变的就是他的方 ...

  4. Python面向对象 --- 新旧式类、私有方法、类属性和类方法、静态方法

    一.Python面向对象中的新旧式类 1)新式类(推荐使用):在定义类时,类后边括号里要继承基类(object).在python3.x中若没有指定父类,会默认使用的是object作为基类:在pytho ...

  5. python 面向对象:封装---对象的属性可以是另一个类创建的对象

    # 对象封装:对象的属性可以是另一个类创建的对象 # 案例需求: # 1.士兵许三多有一把AK47 # 2.士兵用枪射击标靶 # 3.枪能装填和发射子弹 class Gun: # 分析: # 枪的属性 ...

  6. Python面向对象1:类与对象

    Python的面向对象- 面向对象编程 - 基础 - 公有私有 - 继承 - 组合,Mixin- 魔法函数 - 魔法函数概述 - 构造类魔法函数 - 运算类魔法函数 # 1. 面向对象概述(Objec ...

  7. Python面向对象基础:设置对象属性

    用类存储数据 类实际上就是一个数据结构,对于python而言,它是一个类似于字典的结构.当根据类创建了对象之后,这个对象就有了一个数据结构,包含一些赋值了的属性.在这一点上,它和其它语言的struct ...

  8. Python面向对象编程、类

    一.面向对象编程 面向对象--Object Oriented Programming,简称oop,是一种程序设计思想.在说面向对象之前,先说一下什么是编程范式,编程范式你按照什么方式来去编程,去实现一 ...

  9. Python面向对象总结及类与正则表达式

    Python3 面向对象 一丶面向对象技术简介 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 方法:类中定义的函数. 类变 ...

随机推荐

  1. xslt基础学习

    今天下午工作完成没事,登w3c的网站学习了一下xslt的基础知识,主要是因为工作中xml用的比较多,xslt也有用到,所以在这里学习一下. XSLT:一种用于转换 XML 文档的语言. XSLT 用于 ...

  2. SecureCRT结合xmanager远程启动图形化界面程序

    我们很多操作都是可以通过命令行的形式来完成,但是由于不支持图形模式,在一些需要图形界面的时候就很麻烦.本次设置可以在secureCRT中直接使用netca\dbca命令,通过xmanager的pass ...

  3. inotify用法简介及结合rsync实现主机间的文件实时同步

    一.inotify简介 inotify是Linux内核2.6.13 (June 18, 2005)版本新增的一个子系统(API),它提供了一种监控文件系统(基于inode的)事件的机制,可以监控文件系 ...

  4. Boost.Coroutine2:学习使用Coroutine(协程)

    function(函数)routine(例程)coroutine (协程) 函数,例程以及协程都是指一系列的操作的集合. 函数(有返回值)以及例程(没有返回值)也被称作subroutine(子例程), ...

  5. TortoiseGit 使用 HTTP 方式每次 PUSH 无需输入密码的方法

    由于 BitBucket 被墙,导致使用时只能用HTTPS代理的方式,但TortoiseGit貌似没有记忆密码的功能,以至于每次push时都要求输入密码,很是麻烦!在网上搜到的保存密码的方式也有点笨. ...

  6. 漫谈四种神经网络序列解码模型【附示例代码】 glimpse attention

    漫谈四种神经网络序列解码模型[附示例代码] http://jacoxu.com/encoder_decoder/ [视觉注意力的循环神经网络模型]http://blog.csdn.net/leo_xu ...

  7. mysql安装笔记-rpm

    基本内容: 1.需要解决两个依赖 2.需要解决一个包冲突 3.安装mysql服务,以及客户端client 4.修改root的随机密码 5.授予root用户,从任何机器访问任何数据库的任何表的权限 1. ...

  8. 结对编程--fault,error,failure

    结对编程对象:叶小娟 对方博客地址:http://www.cnblogs.com/yxj63/ 双方贡献比例:1:1 结对照片: 结对题目:输入一定个数的数字,对其排序后输出最大值.   1 pack ...

  9. Coding Contest(费用流变形题,double)

    Coding Contest http://acm.hdu.edu.cn/showproblem.php?pid=5988 Time Limit: 2000/1000 MS (Java/Others) ...

  10. 转)MySQL日期与时间函数

    -- MySQL日期时间处理函数 -- 当前日期:2017-05-12(突然发现今天512,是不是会拉防空警报) SELECT NOW() FROM DUAL;-- 当前日期时间:2017-05-12 ...