zoukankan      html  css  js  c++  java
  • 【Python045-魔法方法:属性访问】

    一、属性的几种访问方式

    1、类.属性名

    >>> class C:
        def __init__(self):
            self.x = 'X-man'
    
            
    >>> c = C()
    >>> c.x
    'X-man'

    2、用内置函数getattr()访问属性

    >>> getattr(c,'x','莫有这个属性')
    'X-man'
    >>> getattr(c,'y','莫有这个属性')
    '莫有这个属性'
    >>> 

    3、用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=1
    >>> c
    <__main__.C object at 0x10c012f60>
    >>> c.x
    1
    >>> del c.x
    >>> c.x
    Traceback (most recent call last):
      File "<pyshell#19>", line 1, in <module> 
        c.x
      File "/Users/wufq/Desktop/property.py", line 6, in getsize
        return self.size
    AttributeError: 'C' object has no attribute 'size'

    4、各类内置函数访问属性

    *  __getattr__(self,name)

    定义当用户试图获取一个不存在的属性时的行为

    * __getattribute__(self,name)

    定义当该类的属性被访问时的行为

    * __setattr__(self,name,value)

    定义当一个属性被设置时的行为

    * __delattr__(self,name)

    定义当一个属性被删除时的行为

    class C:
        def __getattr__(self,nane):
            print("__getattr__")
            
        def __getattribute__(self,name):
            print("__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)
    
    >>> c = C()
    >>> c.x
    __getattribute__
    __getattr__
    >>> c.x =1
    __setattr__
    >>> c.x
    __getattribute__
    1
    >>> del c.x
    __delattr__
    >>> c.x

    '''
    代码解析:
    |--1、由第一个c.x先后打印出来__getattribute__和__getattr__,可以看出来,程序先找__getattribute__(定义当该类的属性被访问时的行为),然后
    |-- 在找__getattr__(属性不存在时的访问行为)
    |--2、由c.x =1 打印出来__setattr__,可以得知,当属性被设置时调用的是此方法
    |--3、由del c.x=1 打印出来__delattr__可以得知,当属性被删除时调用此方法
    '''

     5、写一个矩形类,默认有宽和高两个属性

    如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时宽和高都应该等于边长

    class Rectangle:
        def __init__(self,width=0,height=0):
            self.width = width
            self.height = height
        #用square这个属性来标记正方形
        def __setattr__(self,name,):
            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#15>", line 1, in <module>
        r1 = Rectangle(4,5)
      File "/Users/wufq/Desktop/正方形.py", line 4, in __init__
        self.width = width
      File "/Users/wufq/Desktop/正方形.py", line 12, in __setattr__
        self.name = value
      File "/Users/wufq/Desktop/正方形.py", line 12, in __setattr__
        self.name = value
      File "/Users/wufq/Desktop/正方形.py", line 12, in __setattr__
        self.name = value
      [Previous line repeated 987 more times]
      File "/Users/wufq/Desktop/正方形.py", line 8, in __setattr__
        if name == 'square':
    RecursionError: maximum recursion depth exceeded in comparison ''' 代码解析: |-- 为什么会报错:原因:首先实例化对象时给width和height赋值,赋值时就调用了__setattr__方法 |-- 进入__setattr__方法,会首先判断name有没有等于square,明显此时没有,则执行else里面的语句 |-- self.name = value,则又一次循环调用默认的__init__方法,依次这样就会进入死循环 '''

    改进的方法

    #第一种方法:采用super()方法调用基类
    #第二种方法:采用字典的方法,__dict__
    
    class Rectangle:
        def __init__(self,width=0,height=0):
            self.width = width
            self.height = height
        #用square这个属性来标记正方形
        def __setattr__(self,name,value):
            if name == 'square':
                self.width = value
                self.height = value
            else:
                #self.name = value
                #super().__setattr__(name,value)
                self.__dict__[name]=value #采用__dict__方法的原因是:给属性square所赋值存储到dict字典内
    
        def getArea(self):
            return self.width * self.height
    执行结果:
    >>> r1 = Rectangle(4,5)
    >>> r1.getArea()
    20
    >>> r1.square = 10
    >>> r1.getArea()
    100
    >>> r1.__dict__
    {'width': 10, 'height': 10}

     二、练习题

    1、对象的属性发生赋值操作时,将实际的的值+1赋值给相应的属性。

    def __setattr__(self,name,value):
        self.name = value + 1
    
    错误原因:属性被赋值时,__setattr__()会被调用,而里边的self.name = value +1又会再次触发__setattr__()调用,导致无限递归(死循环)

    正确的写法

    class C:
        def __init__(self,name):
            self.name = name
        def __setattr__(self,name,value):
            
            self.__dict__[name]=value+1
            print("name=",self.__dict__[name],"value=",value)
    
    执行结果:
    >>> c = C(2)
    name= 3 value= 2

     2、自定义该类的属性被访问的行为,你应该重写那个魔法方法

    答:__getattribute__(self,name)  :属性被访问时调用这个方法

    3、当访问一个不存在的属性时,不报错且提示“该属性不存在”

    class Demo:
        def __getattr__(self,name):
            return "该属性不存在"
    
    
    执行结果:
    >>> demo = Demo()
    >>> demo.x
    '该属性不存在'
    >>> 

    4、编写一个Demo类,使的下边代码可以正常执行

    class Demo:
        def __getattr__(self,name):
            self.name = 'FishC'
            return self.name
        def __getattribute__(self,name):
            return super().__getattribute__(name)
        def __setattr__(self,name,value):
            return super().__setattr__(name,value)
    
    执行结果:
    >>> d=Demo()
    >>> d.x
    'FishC'
    >>> d.x = "X-man"
    >>> d.x
    'X-man'
    >>> 

    5、编写一个Counter类,用于实时检查对象有多少个属性

    #需求:检测对象有多少个属性
    class Counter:
        def __init__(self):
            super().__setattr__('counter',0)
        def __setattr__(self,name,value):
            super().__setattr__('counter',self.counter + 1)
            super().__setattr__(name,value)
        def __delattr__(self,name):
            super().__setattr__('counter',self.counter - 1)
            super().__delattr__(name)
            
    执行结果:
    >>> c = Counter()
    >>> c.x=1
    >>> c.counter
    1
    >>> c.y =2
    >>> c.z = 3
    >>> c.m =4
    >>> c.counter
    4
    >>> del c.m
    >>> c.counter
    3
    >>> 
  • 相关阅读:
    CDH 2、Cloudera Manager的安装
    204 01 Android 零基础入门 03 Java常用工具类 04 Java集合 04 Map集合 01 Map概述
    203 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 07 删除宠物猫信息数据(引入泛型知识点)
    202 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 06 查找宠物猫信息数据
    201 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 05 添加重复的宠物猫信息数据
    200 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 04 添加和显式宠物猫信息
    199 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 03 宠物猫信息管理概述
    198 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 02 案例:在集合中插入字符串
    197 01 Android 零基础入门 03 Java常用工具类 04 Java集合 03 Set集合 01 Set概述
    196 01 Android 零基础入门 03 Java常用工具类 04 Java集合 02 List集合 05 案例:公告的删除和修改
  • 原文地址:https://www.cnblogs.com/frankruby/p/9912268.html
Copyright © 2011-2022 走看看