鱼C论坛

 找回密码
 立即注册
查看: 933|回复: 1

[求助]关于property 函数在定义类的时候的一个情况

[复制链接]
发表于 2018-5-25 22:44:46 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
代码如下:

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)

===========================================================
>>> c1=C
>>> 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'
>>> c1 = C()
>>> c1.x = 5
>>> c1.size
10
>>>
=============== RESTART: C:/Python34/try property function.py ===============
>>> c1 = C()
>>> c1.x=5
>>> c1.size
5
>>> c2 = C
>>> c2.x = 6
>>> c2.size
Traceback (most recent call last):
  File "<pyshell#37>", line 1, in <module>
    c2.size
AttributeError: type object 'C' has no attribute 'size'
>>> c2 = C()
>>> c2.x=6
>>> c2.size
10
>>> c1.x=7
>>> c1.size
5
>>>
>>> c1.getSize
<bound method C.getSize of <__main__.C object at 0x013785F0>>
>>> c1.getSize()
5
>>> c1.setSize(8)
>>> c1.x
7
>>> c1.size
8
>>> c3 = C()
>>> c3.size = 9
>>> c3.x
6
>>> c3.x = 11
>>> c3.size
9
>>>
+++++++++++++++++++++++
问题:
当输入c1=C之后,由于没有带小括号,所以c1的初始化不能完成,然后重新输入正确的格式:c1 = C()。但是,这时c1.x以及c1.size的值被固定为默认值10.

而且当使用         c1.setSize(8)        的方法来设定c1.size时也只能设定c1.size的值变成了8,但是c1.x的值还是7。另外c3.x和c3.size也不能正常定义类

请问这是什么原因?

+++++++++++++++++++++++
以下为重启代码后的结果
=============== RESTART: C:/Python34/try property function.py ===============
>>> c1 = C()
>>> c1.x = 2
>>> c1.size
2
>>> c1.size = 3
>>> c1.x
3
>>> C.x
<property object at 0x00BE50C0>
>>> C.size
Traceback (most recent call last):
  File "<pyshell#59>", line 1, in <module>
    C.size
AttributeError: type object 'C' has no attribute 'size'
>>>
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 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标记,然后再写别的形式参数就没有问题了。

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-12-30 11:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表