• 课时45:魔法方法:属性访问


    目录:

      一、属性访问

      二、课时45课后习题及答案

    ****************

    一、属性访问

    ****************

     通常可以通过(.)操作符的形式去访问对象的属性,在类与对象这一章的最后一节也有谈到如何通过几个BIF适当地去访问属性:

    >>> class C:
        def __init__(self):
            self.x = 'X-man'
    
            
    >>> c = C()
    >>> c.x
    'X-man'
    >>> getattr(c,'x','木有这个属性')
    'X-man'
    >>> getattr(c,'y','木有这个属性')
    '木有这个属性'
    >>> setattr(c,'y','Yellow')
    >>> getattr(c,'y','木有这个属性')
    'Yellow'
    >>> delattr(c,'x')
    >>> c.x
    Traceback (most recent call last):
      File "<pyshell#11>", line 1, in <module>
        c.x
    AttributeError: 'C' object has no attribute 'x'

    然后还介绍了一个叫做property()函数的用法,这个property()使得我们可以用属性去访问属性:

    >>> 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)
    
        
    >>> c = C()
    >>> c.x
    10
    >>> c.x = 12
    >>> c.x
    12
    >>> c.size
    12
    >>> del c.x
    >>> c.size
    Traceback (most recent call last):
      File "<pyshell#29>", line 1, in <module>
        c.size
    AttributeError: 'C' object has no attribute 'size'

    那么关于属性访问,肯定也有相应得魔法方法来管理。通过对这些魔法方法的重写,可以随心所欲的控制对象的属性访问。

    下表列举了属性相关的魔法方法。

    __getattr__(self, name)             定义当用户试图获取一个不存在的属性时的行为
    __getattribute__(self, name)       定义当该类的属性被访问时的行为
    __setattr__(self, name, value)     定义当一个属性被设置时的行为
    __delattr__(self, name)             定义当一个属性被删除时的行为

    做个小测试:

    class C:
        def __getattribute__(self, name):
            print('getattribute')
            # 使用 super() 调用 object 基类的 __getattribute__ 方法
            return super().__getattribute__(name)
    
        def __setattr__(self, name, value):
            print('setattr')
            super().__setattr__(name, value)
    
        def __delattr__(self, name):
            print('delattr')
            super().__delattr__(name)
    
        def __getattr__(self, name):
            print('getattr')
    >>> c = C()
    >>> c.x
    getattribute
    getattr
    >>> c.x = 1
    setattr
    >>> c.x
    getattribute
    1
    >>> del c.x
    delattr
    >>> setattr(c,'y','Yellow')
    setattr

    这几个魔法方法在使用上需要注意的是,有一个死循环的陷阱,初学者很容易中招,通过一个实例来讲解。

    写一个矩形类,默认有宽和高两个属性;
    如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长。

    class Rectangle:
        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
    >>> r1 = Rectangle(4,5)
    Traceback (most recent call last):
      File "<pyshell#0>", line 1, in <module>
        r1 = Rectangle(4,5)
      File "C:Users14158Desktoplalallalalal.py", line 3, in __init__
        self.width = width
      File "C:Users14158Desktoplalallalalal.py", line 11, in __setattr__
        self.name = value
      File "C:Users14158Desktoplalallalalal.py", line 11, in __setattr__
        self.name = value
      File "C:Users14158Desktoplalallalalal.py", line 11, in __setattr__
        self.name = value
      [Previous line repeated 987 more times]
      File "C:Users14158Desktoplalallalalal.py", line 7, in __setattr__
        if name == 'square':
    RecursionError: maximum recursion depth exceeded in comparison

    这是为什么呢?

    分析一下:实例化对象,调用__init__()方法,在这里self.width和self.heigth分别初始化赋值。一发生赋值操作,就会自动触发__setattr__()魔法方法,width和height两个属性被赋值,于是执行else的下边的语句,就变成了self.width = value,那么就相当于又触发了__setattr__(),那么这样就依赖基类的方法来实现赋值:

            else:
                super().__setattr__(name,value)
    >>> r1 = Rectangle(4,5)
    >>> r1.getArea()
    20
    >>> r1.square = 10
    >>> r1.getArea()
    100

    另一种方法就是给特殊属性__dict__赋值。对象有一个特殊属性,叫做__dict__,它的作用是以字典的形式显示出当前对象的所有属性以及相对应的值:

            else:
                self.__dict__[name] = value

    运行结果一样。

    *******************************

    二、课时45课后习题及答案

    *******************************

     

  • 相关阅读:
    通过 INotifyPropertyChanged 实现观察者模式(转)
    Asp.net MVC中的ViewData与ViewBag(转)
    FireFox地址栏百度搜索
    ZigBee设备类型
    Array.prototype.slice.call(arguments) (转)
    泛型方法扩展
    定义IE的文档兼容模式
    C# Lazy<T>(转)
    AutoCAD2010/2012去掉搜索框
    python 集合类型
  • 原文地址:https://www.cnblogs.com/DC0307/p/9534960.html
Copyright © 2020-2023  润新知