Discuss / Python / 有个问题请教一下

有个问题请教一下

Topic source

宫城诗丶

#1 Created at ... [Delete] [Delete and Lock User]

class Screen(object):

def __init__(self,width,height):
    self.width=width
    self.height=height
@property
def resolution(self):
    return self._resolution

@property
def width(self):
    return self._width

@width.setter
def width(self, value):
        self._width= value

@property
def height(self):
    return self._height

@height.setter
def height(self, value):
        self._height= value

a=Screen() a.width=5 print(a.width) a.height=23123 print(a.height)

如果我属性前面不加_,程序就会报错。 [Previous line repeated 993 more times] RecursionError: maximum recursion depth exceeded 这是为什么呢

青铜神裔

#2 Created at ... [Delete] [Delete and Lock User]

你的问题我不太清楚,但是我觉得你的对象初始化时会出问题吧,需要传入两个参数,你没传啊

关于 如果我属性前面不加_,程序就会报错。 这个问题

我的理解是: 因为@property会返回一个和你方法同名的属性,所以会发生冲突 论据:给返回的同名函数名自定义一下: class Test(): def init(self): self.name=1

@property
def othername(self):
    return self.name
@othername.setter
def othername(self,name):
    self.name=name

a=Test()
a.othername=10
print(a.othername)
‘--------------------’
10
用私有属性的话,返回的是xxx,操作的就是_xxx或__xxx,既不会冲突,看起来又方便,‘约定俗成’的魅力就是这样

可能能得到启发的引用:@property声明的属性默认会生成一个_类型的成员变量,同时也会生成setter/getter方法 
引用自https://www.cnblogs.com/huangzs/p/7508583.html

一楼的是递归调用了,相当于自己调用自己,而且是无限调用——默认值1000次吧就会报这个错误,添加一个_代表你这是创建了一个属性。

我关于这个问题的理解就是,init函数动态的添加属性与@property内部原理一致,如果用两种方式添加属性,且属性名相同,难道不会报错吗

天命破凰

#6 Created at ... [Delete] [Delete and Lock User]

init函数后的属性在创建实例时必须添加吧,运行试题的时候会报错

个人理解:

1.首先@property只是添加了getter,比如说返回了self.width(或者self._width),这里我们可以知道self目前是没有width(或者_width)的,那么这个属性是从哪儿来的呢?

2.@width.setter其实在创建实例的时候就会执行一次(应该是所有的setter都会在创建实例的时候都会执行一次),这样我们就获得了width(或者_width)

3.现在我们来研究一下为什么使用_width而不使用width: a.使用width:在创建实例的时候,会报一个递归的错误:RecursionError: maximum recursion depth exceeded,因为在创建实例时,会执行width.setter这个方法,这个方法的本质就是self.width,所以在执行赋值语句时(self.width = width),其中的=赋值时又会触发setter.width这个方法,所以就形成了无限递归死循环,导致堆栈溢出(内存溢出),python为了处理递归问题,作了次数限制,抛出了RecursionError这个错误提示。所以为了防止递归,我们不能使用内部已经存在的属性名

b.根据上面的推测:我们只要避免递归出现,不一定要使用seft.width这样的属性名,但是我实际测试了一下,上面结论确实是正确的,还有个前提条件,必须以开头,所以我们可以使用_a,_b...代替_widht

class Screen(object): @property def width(self): return self._a

@width.setter
def width(self, width):
    self._a = width

@property
def height(self):
    return self._b

@height.setter
def height(self, height):
    self._b = height

@property
def resolution(self):
    return self._a * self._b

因为_开头的属性肯定不会和setter方法重名,所以我们得到结论:只要以下划线开头就可以


  • 1

Reply