대화형 환경에 들어가세요:
1 >>> class A: 2 a=0 3 def __init__(self): 4 self.a=10 5 self.b=100 6 7 8 >>> a=A() 9 >>> a.a10 1011 >>> a.b12 10013 >>> A.a14 015 >>> A.b16 Traceback (most recent call last):17 File "<pyshell#10>", line 1, in <module>18 A.b19 AttributeError: type object 'A' has no attribute 'b'20 >>>
아래와 같이:
아직 대화형 환경에 있습니다:
1 >>> class A: 2 a=0 3 def __init__(self): 4 self.a=10 5 self.b=100 6 7 8 >>> a=A() 9 >>> getattr(a,'a')#用getattr()函数获取实例a中a属性的值10 1011 >>> setattr(a,'a',20)#设置实例a中a属性的值为2012 >>> getattr(a,'a')#用getattr()函数获取实例a中a属性的值13 2014 >>> hasattr(a,'b')#测试实例a中是否包含属性b15 True
사진 표시:
문자열을 사용하여 클래스 속성과 메서드를 작동하는 이 반사 메커니즘의 세 가지 기능은 일반적으로 사용되지 않습니다. 작성 프레임워크 및 기타 특수 프로젝트가 사용됩니다.
1 class Washer: 2 3 def __init__(self,water=10,scour=2): 4 self._water=water #不想让用户直接访问实例变量,可以标志成私有 5 self.scour=scour 6 #属性包装,将water属性包装成方法,用户使用water时实际是访问的方法 7 @property 8 def water(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性 9 return self._water10 11 def set_water(self,water):12 self.water=water 13 14 def set_scour(self,scour):15 self.scour=scour 16 17 def add_water(self):18 print('Add water:',self.water)19 20 def add_scour(self):21 print('Add scour:',self.scour)22 23 def start_wash(self):24 self.add_water()25 self.add_scour()26 print('Start wash...')27 28 if __name__=='__main__':29 w=Washer()30 #w.start_wash()31 print(w.water)# 可以像访问属性一样访问方法
하지만 이때 사용자는 여전히 w._water를 통해 인스턴스 속성에 액세스할 수 있습니다. 캡슐화가 좋지 않아 데이터가 부동 소수점인지 자동으로 확인하지 않습니다. 좋지 않다.
어떻게 해결하나요?
@property.setter 사용
1 class Washer: 2 3 def __init__(self,water=10,scour=2): 4 self._water=water #不想让用户直接访问实例变量,可以标志成私有 5 self.scour=scour 6 #属性包装,将water属性包装成方法,用户使用water时实际是访问的方法 7 @property 8 def water(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性 9 return self._water10 11 @water.setter #新添加代码12 def water(self,water):13 if 0<water<=500:14 self._water=water15 else:16 print('set Failure!')17 18 def set_water(self,water):19 self.water=water 20 21 def set_scour(self,scour):22 self.scour=scour 23 24 def add_water(self):25 print('Add water:',self.water)26 27 def add_scour(self):28 print('Add scour:',self.scour)29 30 def start_wash(self):31 self.add_water()32 self.add_scour()33 print('Start wash...')34 35 if __name__=='__main__':36 w=Washer()37 print(w.water)# 可以像访问属性一样访问方法38 #w._water=20 #为了不让用户这样直接给实例属性赋值,用下面的语句39 w.water=123 #可以像给属性赋值一样给方法赋值,并检测范围40 print(w.water)# 可以像访问属性一样访问方法
결과:
그리고 @water.setter water가 무엇인지 매우 궁금했는데, 새로운 인스턴스 속성으로 이해할 수 있다는 것을 알게 되었는데, 그리고 생성자의 형식 매개변수는 중요하지 않습니다. 예를 들어, 아래 그림
또 다른 예:
결과는 여전히:
삭제 변수 @water.delete
-------를 래핑할 수도 있습니다. ----- -----------
이 코드는 water 변수를 다시 작성할 수 있음을 나타냅니다.
--- --- ---------------------
위 코드는 water 속성이 읽을 수 있습니다.
--------------------------------------
마지막으로 한 가지 사용법은 속성 데코레이터 @property를 사용하여 가상 속성을 새로 정의하는 것입니다.
1 class Washer: 2 3 def __init__(self,water=10,scour=2): 4 self._water=water #不想让用户直接访问实例变量,可以标志成私有 5 self.scour=scour 6 self.year=2000#这是生产日期 7 #属性包装,将water属性包装成方法,用户使用water时实际是访问的方法 8 @property 9 def water1(self):#如果用户使用 实例.water相当于访问这个方法,而不是真的访问属性10 return self._water11 12 @water1.setter13 def water1(self,water):14 if 0<water<=500:15 self._water=water16 else:17 print('set Failure!')18 @property 19 def total_year(self): #定义一个虚拟实例属性,这个属性其实是一个方法,但是可以按照属性来用 20 return 2017-self.year21 22 def set_water(self,water):23 self.water=water 24 25 def set_scour(self,scour):26 self.scour=scour 27 28 def add_water(self):29 print('Add water:',self.water)30 31 def add_scour(self):32 print('Add scour:',self.scour)33 34 def start_wash(self):35 self.add_water()36 self.add_scour()37 print('Start wash...')38 39 if __name__=='__main__':40 w=Washer()41 print(w.water1)# 可以像访问属性一样访问方法42 #w._water=20 #为了不让用户这样直接给实例属性赋值,用下面的语句43 w.water1=12344 print(w.water1)# 可以像访问属性一样访问方法45 print(w.total_year)46 47
실행 결과:
설명자
설명자의 의미는 동일한 한정된 속성 정의 코드. 예를 들어 다음 예는 다음과 같습니다.
1 class NonNeg:#数据描述符 2 def __init__(self,default=0):#构造方法 3 self.default=default#一个实例属性 4 def __get__(self,instance,owner):#协议方法 5 return self.default 6 def __set__(self,instance,val):#协议方法 7 if val>0: 8 self.default=val 9 else:10 print('The value must be NonNegative!')11 def __delete__(self,instance):#协议方法12 pass13 class Movie:14 rating=NonNeg()#描述符类NonNeg作另一个类Movie的属性,rating是Movie的类属性。15 score=NonNeg()16 17 if __name__=='__main__':18 m=Movie()19 print('rating:',m.rating)20 print('score:',m.score)#输出默认值default21 m.rating=80#使用__set__协议方法22 print('rating:',m.rating)#使用到 __get__协议方法23 m.score=-324 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,也就是一个方法了。
1 class Tst: 2 def pr(self): 3 self.pr=10 4 print('Tst') 5 t1=Tst() 6 t1.pr()#输出Tst 7 t1.pr#啥都没有输出 8 print(t1.pr)#输出10 9 print('下面实例化后不访问t.pr()直接访问t.pr:')10 t2=Tst()11 t2.pr#啥都没输出12 print(t2.pr)#输出了bound method Tst.pr of <__main__.Tst object
但后来在实例下新定义的同名实例属性会覆盖原先类中定义的实例方法。优先级知道了吧。
扩展:
1 class Tst: 2 def __init__(self,default=1): 3 self.water=default 4 def __call__(self): 5 print('包含call函数的类,他的实例可以直接当做函数使用。') 6 def info(self): 7 print("pass") 8 9 t=Tst()10 t()
当调用t()时只调用类中__call__函数。
--------------------------------------------
解答如下:
1 class surfaceNum:#定义一个描述类 2 def __init__(self,default=1): 3 self.number=default 4 def __get__(self,instance,owner):#参数instance和owner暂时没有用到,只有self是固定名参数 5 return self.number 6 def __set__(self,instance,val):#参数instance暂时没有用到 7 if 0<val<7 and isinstance(val,int)==True: 8 self.number=val 9 Box.info_num(self)#Box类还没有创建,故不能引用Box.infor_num,哈哈,能创建啊10 else:11 print('please set the correct surface number!')12 def __delete__(self,instance):#协议方法13 pass14 15 class Box:#定义一个类名为Box,类名后不必有括号,类包含类属性和类方法,这个类没有定义类属性16 '''这是一个计算体积的类'''#这是这个类的__doc__属性,执行类后就可以在交互界面输入Box.__doc__查看这行说明文字了17 openstate=018 number=surfaceNum()19 def __init__(self):#这是类的构造函数,当实例化Box后会自动调用这个__init__方法20 self.length=0.0 #这是实例属性,在类内访问用self.length,在类外访问用 实例名.length21 self.width=0.022 self.height=0.023 self._color='red' 24 self.__valum=0.0#双下换线开头的变量表示私有变量,所以他为私有实例属性,只能在类内访问到25 26 @property27 def color(self):28 return self._color29 @color.setter30 def color(self,color):31 self._color=color32 33 def set_color(self,color):34 self._color=color 35 36 def computevalum(self):#定义了一个类方法。37 self.__valum=self.length*self.width*self.height38 print('长度=',self.length,'宽度=',self.width,'高度=',self.height,'valum=',self.__valum)39 40 def info_color(self):41 #self.set_color(self._color)#在类中,函数调用函数的方式42 print('Box的颜色为',self._color)43 44 def open_box(self):45 if Box.openstate==0:46 print('打开了Box')47 Box.openstate=148 else:49 print('Box已经打开了,不能重复打开')50 def info_num(self):51 #self.set_color(self._color)#在类中,函数调用函数的方式52 53 print('Box面上的数字为',Box.number)54 #定义 __call__ 函数,输出体积55 def __call__(self):56 self.__valum=self.length*self.width*self.height57 print('长度=',self.length,'宽度=',self.width,'高度=',self.height,'调用自身computa()输出:valum=',self.__valum)58 59 60 61 62 if __name__=='__main__': 63 computa=Box() #实例化Box类64 computa.number =265 computa.info_num()66 computa.length=167 computa.width=268 computa.height=369 computa.computevalum()70 computa()#实例名函数调用__call__函数直接输出体积71 computa.set_color ('yellow')72 computa.info_color()73 computa.open_box()74 computa.color='green'75 computa.info_color()76 print('')77 78 computb=Box()#实例化Box类79 computb.length=280 computb.width=281 computb.height=382 computb.computevalum()83 computb.set_color ('black')84 computb.info_color()85 computb.open_box()
这个题目是上节课题目的拔高,上节课题目及解答见链接:
위 내용은 클래스 속성에 대한 심층적인 소개와 활용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!