zoukankan      html  css  js  c++  java
  • Python类属性访问的魔法方法

    Python类属性访问的魔法方法:

    1. __getattr__(self, name)
    - 定义当用户试图获取一个不存在的属性时的行为

    2. __getattribute__(self, name)
    - 定义当该类的属性被访问时的行为

    注意:当__getattr__与__getattribute__同时重写时,访问属性时,优先调用__getattribute__,只有当被访问的属性不存在时才触发__getattr__

    3. __setattr__(self, name, value)
    - 定义当一个属性被设置时的行为

    4. __delattr__(self, name)
    - 定义当一个属性被删除时的行为

    >>> class C:
        def __getattribute__(self, name):
            print("getattribute")
            return super().__getattribute__(name) #如果这里没有return语句,那么,c.x访问时__getattr__不会触发,因为相当于没有c.x这句话
        def __getattr__(self, name):
            print("getattr")
        def __setattr__(self, name, value):
            print("setattr")
            super().__setattr__(name, value) #同样的道理,这里必须执行,才能真正的设置成功。这里为啥不能这么写:self.name = value?请看下面关于__setattr__死循环陷阱的说明
        def __delattr__(self, name):
            print("delattr")
    #这里应该加一句 super().__delattr__(name),不然,删除指定对象是不会成功,看下面的执行结果就可以验证
    >>> c = C() >>> c.x getattribute getattr >>> c.x = 999 setattr >>> c.x getattribute 999 >>> del c.x delattr
    #上面已经删除了c.x,但下面访问时,还是访问到了,说明删除没有成功,因为__delattr__中没有
    super().__delattr__(name)这句话
    >>> c.x
    getattribute
    999
    >>>

     此外,__setattr__会有死循环陷阱:

    >>> class Rect():
        def __init__(self, width=0, height=0):
            self.width = width
            self.height = height
        def __setattr__(self, name, value):
            if name == 'square':
                self.width = value
                self.height = value
            else:
                self.name = value
        def getArea(self):
            return self.width * self.height
    
        
    >>> r = Rect(2,8)
    Traceback (most recent call last):
      File "<pyshell#144>", line 1, in <module>
        r = Rect(2,8)
      File "<pyshell#143>", line 3, in __init__
        self.width = width
      File "<pyshell#143>", line 10, in __setattr__
        self.name = value
      File "<pyshell#143>", line 10, in __setattr__
        self.name = value
      File "<pyshell#143>", line 10, in __setattr__
        self.name = value
      File "<pyshell#143>", line 10, in __setattr__
    ……

    为什么会这样?

    主要是在__init__内,给width与height赋值的时候,就会自动触发__setattr__方法,当参数2,8分别传入width与height的时候,初始化时,赋值触发__setattr__,因为2传给的是width属性,所以,不是suqare,就执行else的语句(self.name = value),然而,在else的语句又是一个赋值语句,又会自动触发__setattr__,所以,就会造成死循环。其解决方法有两种:

    1.self.name = value这句修改成:super().__setattr__(name, value),使用父类的__setattr__来赋值(这为啥就不会死循环?别问我,反正Python的设计者解决了这个问题)

    2.self.name = value这句修改成:self.__dict__[name] = value, 这样也是赋值,为啥不是死循环呢?哈哈,触发__setattr__的情况是访问访问对象的属性,而这里比较巧的是访问的是__dict__(对象的特殊属性,是用来存放当前对象所以的属性的字典)。

  • 相关阅读:
    poj3669 广搜
    检索所有课程都选修的的学生的学号与姓名
    UVA10160 Servicing Stations
    uva11205 The broken pedometer 子集生成
    poj1101 the game 广搜
    poj3009 Curling 2.0 深搜
    poj 1564 Sum It Up 搜索
    HDU 2268 How To Use The Car (数学题)
    codeforces 467C George and Job(简单dp,看了题解抄一遍)
    HDU 2267 How Many People Can Survive(广搜,简单)
  • 原文地址:https://www.cnblogs.com/paomaliuju/p/5132030.html
Copyright © 2011-2022 走看看