|
|

楼主 |
发表于 2018-5-26 22:03:18
|
显示全部楼层
搞了一天,自问自答一下:
以下是代码段
class C():
def __init__(self,size=10):
self.size = size
def getSize(self):
return self.size
def setSize(self,value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
class D():
def getSize(self):
return self.size
def setSize(self,value):
self.size = value
def delSize(self):
del self.size
x = property(getSize, setSize, delSize)
class E():
def getSize():
return size
def setSize(value):
size = value
def delSize():
del size
x = property(getSize, setSize, delSize)
以下为运行结果
>>>
RESTART: C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py
>>> c1=C
>>> type(c1)
<class 'type'>
>>> type(C)
<class 'type'>
>>> c1.x
<property object at 0x00BE50C0>
>>> C.x
<property object at 0x00BE50C0>
#开始的时候,C和c1都是类对象,而C.x和c1.x是内存地址相同的同一个property对象
>>> c1.x=5
>>> c1.size
Traceback (most recent call last):
File "<pyshell#28>", line 1, in <module>
c1.size
AttributeError: type object 'C' has no attribute 'size'
#总结一下上面报错的问题:表达式x = property(getSize, setSize, delSize)是个将property类实例化给x并把getSize, setSize,和delSize三个函数作为参数传给这个类的过程。此时的C.x是一个property类的实例化对象。这一点小甲鱼的课程里可能没有讲清楚。之后的代码,c1.x = 5 是一个将c1.x以及C.x重新赋值为5的过程,因为c1和C都是指向同一个类的类对象。在这之后,c1.x和 C.x不再具有通过x = property()的方式把5这个值传给 getSize, setSize, delSize这三个函数能力了。此时的x只是一个整数型变量而已,和property函数没有任何关系。所以说, c1 = C和c1=C()这两个表达式是有着本质上的区别的。前者是一个通过等号赋值的过程,而后者则是一个将类对象实例化的过程
>>> c1.x
5
>>> C.x
5
>>> type(c1.x)
<class 'int'>
>>> type(C.x)
<class 'int'>
# 此时 c1.x和C.x的类型都变成了整数,证明c1和C在内存里可能是同一个东西
>>> c1 = C()
>>> c1.x = 5
>>> c1.size
10
>>>
# 现在重新将类对象C实例化给c1之后,c1.x的值也不能通过property影响到getSize, setSize, delSize这三个函数了。这就是因为类对象C的x已经被修改了,它只是一个值为5的整数型变量,而不再具有通过x = property()的方式把5这个值传给 getSize, setSize, delSize这三个函数能力了。
#接下来重载程序:
>>>
RESTART: C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py
>>> c1 = C()
>>> c1.x=5
>>> c1.size
5
# 重载程序,现在c1是C的一个实例化对象,c1可以正常工作了
#接下来重载程序:
>>>
RESTART: C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py
>>> c1 = C
>>> type(c1)
<class 'type'>
>>> type(C)
<class 'type'>
>>> c1.getSize()
Traceback (most recent call last):
File "<pyshell#56>", line 1, in <module>
c1.getSize()
TypeError: getSize() missing 1 required positional argument: 'self'
>>> >>>
#这时的报错的类型上次不同了,说的是c1.getSize(),都需要把类对象自身传入self所代表的那个位置作为一个必要的参数。这个情况是因为,c1=C是个语法错误,这句虽然能执行没有报错,但是这只是把类对象赋值给了c1,C和c1是同一个东西。但是,由于C或c1都是类对象而没有被实例化,所以__init__()没有被调用,所以即使在__init__()里有过self.size = size=10这样的缺省设置,变量self.size在其他函数里也没有被赋值。
>>> C.setSize(5)
Traceback (most recent call last):
File "<pyshell#57>", line 1, in <module>
C.setSize(5)
TypeError: setSize() missing 1 required positional argument: 'value'
>>>
# 这时调用setSize()也不行。因为setSize()有两个形式参数需要赋值,而C.setSize(5)只赋值了一个。
>>> c1.getSize(self)
Traceback (most recent call last):
File "<pyshell#58>", line 1, in <module>
c1.getSize(self)
NameError: name 'self' is not defined
#在这里如果你只是传入一个叫做self的变量肯定会报错的,会告诉你self未定义。因为self这个参数只是用来标记这个特殊位置的形参。它叫什么名字都可以,但是在使用它的时候,要求传入的必须是类对象或者实例化对象本身,当然你也可以传入另一个类对象,但是会得到不同的结果,接下来我们会继续讨论。
>>> c1.getSize(c1)
Traceback (most recent call last):
File "<pyshell#59>", line 1, in <module>
c1.getSize(c1)
File "C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py", line 5, in getSize
return self.size
AttributeError: type object 'C' has no attribute 'size'
#由于c1.size尚未通过c1.setSize进行赋值,所以此处报错
>>> c1.setSize(c1,10)
#这句写成C.setSize(C,10),或者c1.setSize(C,10),或则C.setSize(c1,10)都可以得到相同的结果。类对象的内部函数的工作机制和需要传入参数,我们会在后面测试和讨论。
>>> c1.size
10
>>> C.size
10
>>> c1.getSize()
Traceback (most recent call last):
File "<pyshell#63>", line 1, in <module>
c1.getSize()
TypeError: getSize() missing 1 required positional argument: 'self'
>>> c1.getSize(c1)
10
>>>
#这句写成C.getSize(C),或者c1.getSize(C),或则C.getSize(c1)都可以得到相同的结果。
#上面的代码说明,由于没有经过实例化的过程,__init__()方法就没有被调用,每次使用类的内部函数时,都需要把类对象自身传入self所代表的那个位置作为一个必要的参数。而且每次调用内部方法都可能会对这个类对象本身进行修改。
#接下来重载程序:
>>>
RESTART: C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py
>>> c1 = C()
>>> c1.setSize(5)
>>> c1.size
5
>>> d1 = D()
>>> d1.setSize(11)
>>> d1.size
11
>>> c1.x = 20
>>> c1.getSize()
20
>>> c1.size
20
>>> d1.x= 15
>>> d1.getSize()
15
>>> d1.size
15
#类对象D和C的唯一区别就是有没有重新定义__init__()这个内置方法的区别。在将D实例化给d1之后,d1一样可以使用d1.setSize()的内置方法给size赋值,self参数仍然是自动传入给setSize()的,而不需要额外输入。但是,d1也同样可以通过x=property的方法给getSize, setSize, delSize这三个函数赋值。说明是否调用__init__(),与x=property这句是否能正常工作无关
#接下来看看类对象本身的情况
>>> d2 = D
>>> d2.getSize(d2)
Traceback (most recent call last):
File "<pyshell#110>", line 1, in <module>
d2.getSize(d2)
File "C:\Documents and Settings\Administrator\桌面\works and exampliaries\使用property函数的一个例外情况.py", line 16, in getSize
return self.size
AttributeError: type object 'D' has no attribute 'size'
#这个报错还是由于没有经过setSize()方法给d2.size赋值造成系统认为d2的size属性不存在
>>> d2.setSize(12)
Traceback (most recent call last):
File "<pyshell#74>", line 1, in <module>
d2.setSize(12)
TypeError: setSize() missing 1 required positional argument: 'value'
#这个报错还是因为setSize()方法需要传两个参数,而这时的self位置的没有自动的把类对象本身传入给self位置的形参
>>> d2.setSize(d2,12)
>>> d2.size
12
#和类对象C一样,类对象D或d2本身在调用setSize()时,仍然需要将D或d2输入作为首参数,传入到self所标记的那个形参的位置。
>>> d2.x
<property object at 0x017891B0>.
>>> d2.x=13
>>> d2.size
12
#在这里 d2.x只是被单纯的赋值为13,而没有通过x = property(getSize, setSize, delSize)去设置getSize, setSize, delSize这三个函数。所以,上面一系列代码说明,x = property(getSize, setSize, delSize)只能在类的实例化对象里,对类对象的三个方法进行设置。
#所以,在有实例化的情况下,d1和c2的使用没有什么不同
#所以,在没有实例化的情况下,d2和c1在使用内置函数方面没有什么不同。
#接下来重载程序:
>>> D.setSize(D,12)
>>> D.size
12
>>> C.getSize(D)
12
>>> C.setSize(D,13)
>>> C.size
Traceback (most recent call last):
File "<pyshell#92>", line 1, in <module>
C.size
AttributeError: type object 'C' has no attribute 'size'
>>> D.size
13
>>>
#在使用内置方法时,如果C把D作为参数传入了到了setSize(),结果就是D的D.size被赋值为13而C的C.size并没变化。等于说类的内部函数进行的是地址操作,并且真的会影响到外部的类。
#接下来是类对象E的操作
>>> e1=E()
>>> e1.setSize(10)
Traceback (most recent call last):
File "<pyshell#119>", line 1, in <module>
e1.setSize(10)
TypeError: setSize() takes 1 positional argument but 2 were given
#这里的报错说的是,setSize(10)传入了两个参数,但是setSize()只需要一个参数传入。这说明每次给类的一个内部参数传入参数时,系统都会默认把类对象或类的实例化对象本身作为第一个参数传入并工作。但是只要想类对象D那样的格式,每次都先把内部函数的第一个形参用self标记,然后再写别的形式参数就没有问题了。
|
|