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
    >>> 
  • 相关阅读:
    csu 1141 节能
    WA:ZOJ 1025 Wooden Sticks
    UVa 531 Compromise
    UVa 437 The Tower of Babylon
    UVa 10285 Longest Run on a Snowboard
    在asp.net使用web.config身份验证
    掌握 Ajax,第 6 部分: 建立基于 DOM 的 Web 应用程序
    面向对象编程思想
    一步一步学Remoting之五:异步操作
    Asp.net 2.0 用 FileUpload 控件实现多文件上传 用户控件(示例代码下载)
  • 原文地址:https://www.cnblogs.com/frankruby/p/9912268.html
Copyright © 2011-2022 走看看