zoukankan      html  css  js  c++  java
  • python_魔法方法(四):属性访问

    通常可以通过点(.)操作符的形式去访问对象的属性,也可以通过BIF适当地去访问属性,看个例子吧

    >>> class A():
        def __init__(self):
            self.x = 'XYZ-xyz'
            
    >>> a = A()
    >>> a.x
    'XYZ-xyz'
    >>> getattr(a,'x','没有这个属性')
    'XYZ-xyz'
    >>> getattr(a,'z','没有这个属性')
    '没有这个属性'
    >>> setattr(a,'z','red')
    >>> getattr(a,'z','red')
    'red'
    >>> delattr(a,'x')
    >>> a.x
    Traceback (most recent call last):
      File "<pyshell#12>", line 1, in <module>
        a.x
    AttributeError: 'A' 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#30>", line 1, in <module>
        c.size
    AttributeError: 'C' object has no attribute 'size'

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

    来介绍下属性相关的魔法方法:

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

    好了,我们先来做个测试:

    >>> class A():
        def __getattribute__(self,name):
            print('getattribute')
            #使用super()调用object基类__getattribut__()方法
            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')
        
    >>> a = A()
    >>> a.x
    getattribute
    getattr
    >>> a.x = 1
    setattr
    >>> a.x
    getattribute
    1
    >>> del a.x
    delattr
    >>> setattr(a,'y','yellow')
    setattr

    这几个魔法方法在使用的时候要注意,防止进入死循环陷阱,下面通过实例来说明,写一个矩形类(Rectangle),默认有宽(width)和高(height)两个属性;如果为一个叫square的属性赋值,那么说明这是一个正方形,值就是正方形的边长,此时高宽都应该等于边长

    >>> class Rectangle():
        def __init__(self,width = 0,height = 0):
            self.width = width
            self.height = height
        def __setattr__(self,key,value):
            if key == 'square':
                self.width = value
                self.height = value
            else:
                self.key = value
        def getArea(self):
            return self.width *self.height
        
    >>> r1 = Rectangle(4,5)
    Traceback (most recent call last):
      File "<pyshell#65>", line 1, in <module> r1 = Rectangle(4,5)
      File "<pyshell#64>", line 3, in __init__ self.width = width
      File "<pyshell#64>", line 10, in __setattr__ self.key = value
      File "<pyshell#64>", line 10, in __setattr__  self.key = value
      File "<pyshell#64>", line 10, in __setattr__  self.key = value
      [Previous line repeated 325 more times]
      File "<pyshell#64>", line 6, in __setattr__  if key == 'square':
    RecursionError: maximum recursion depth exceeded in comparison

    出现这个循环的原因在于调用了__init__()方法,在这里给self.width和self.height分别初始化赋值。一旦发生赋值操作就会自动触发__setattr__()魔法方法,width和height两个属性被赋值,于是执行了else的下边的语句,就又变成了self.width=value,那么久相当于又触发了__setattr__()魔法方法,造成了死循环。

    解决方法一,就是和刚才的一样,使用super()来调用基类的__setattr__(),那么这样就依赖基类的方法来实现赋值:

    >>> class Rectangle():
        def __init__(self,width = 0,height = 0):
            self.width = width
            self.height = height
        def __setattr__(self,key,value):
            if key == 'square':
                self.width = value
                self.height = value
            else:
                super().__setattr__(key,value)
        def getArea(self):
            return self.width *self.height
        
    >>> r1 = Rectangle(4,5)
    >>> r1.getArea()
    20
    >>> r1.square = 10
    >>> r1.getArea()
    100

    解决方法二:给特殊属性__dict__赋值。对象有一个特殊的属性,__dict__,它的作用是以字典的形式显示出当前对象的所有属性以及相对于的值。

    调用死循环的类

    >>> r1.__dict__
    {'width': 10, 'height': 10}
    >>> class Rectangle():
        def __init__(self,width = 0,height = 0):
            self.width = width
            self.height = height
        def __setattr__(self,key,value):
            if key == 'square':
                self.width = value
                self.height = value
         else:
           self.__dict__[name] = value
    >>> r1 = Rectangle(4,5)
  • 相关阅读:
    如何在Android平台下进行Socket通信
    通过 按钮 bundle 传过来 变换Q币图片
    Android中focusable属性的妙用——底层按钮的实现
    Android与服务器交互的简单例子
    Microsoft Office SharePoint Server 2007介绍
    mathtype使用
    VS2010快捷键
    xxd
    gas 多文件组织
    612 根目录下vmlinux , compressed下的vmlinux,boot下的Image、zImage
  • 原文地址:https://www.cnblogs.com/pinpin/p/9911812.html
Copyright © 2011-2022 走看看