深入理解python对象及属性

系统 1591 0

类属性和实例属性

首先来看看类属性和类实例的属性在python中如何存储,通过__dir__方法来查看对象的属性

            
              
                >>
              
              
                >
              
              
                class
              
              
                Test
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                pass
              
              
                >>
              
              
                >
              
               test 
              
                =
              
               Test
              
                (
              
              
                )
              
              
                # 查看类属性
              
              
                >>
              
              
                >
              
              
                dir
              
              
                (
              
              Test
              
                )
              
              
                [
              
              
                '__class__'
              
              
                ,
              
              
                '__delattr__'
              
              
                ,
              
              
                '__dict__'
              
              
                ,
              
              
                '__doc__'
              
              
                ,
              
              
                '__format__'
              
              
                ,
              
              
                '__getattribute__'
              
              
                ,
              
              
                '__hash__'
              
              
                ,
              
              
                '__init__'
              
              
                ,
              
              
                '__module__'
              
              
                ,
              
              
                '__new__'
              
              
                ,
              
              
                '__reduce__'
              
              
                ,
              
              
                '__reduce_ex__'
              
              
                ,
              
              
                '__repr__'
              
              
                ,
              
              
                '__setattr__'
              
              
                ,
              
              
                '__sizeof__'
              
              
                ,
              
              
                '__str__'
              
              
                ,
              
              
                '__subclasshook__'
              
              
                ,
              
              
                '__weakref__'
              
              
                ]
              
              
                # 查看实例属性
              
              
                >>
              
              
                >
              
              
                dir
              
              
                (
              
              test
              
                )
              
              
                [
              
              
                '__class__'
              
              
                ,
              
              
                '__delattr__'
              
              
                ,
              
              
                '__dict__'
              
              
                ,
              
              
                '__doc__'
              
              
                ,
              
              
                '__format__'
              
              
                ,
              
              
                '__getattribute__'
              
              
                ,
              
              
                '__hash__'
              
              
                ,
              
              
                '__init__'
              
              
                ,
              
              
                '__module__'
              
              
                ,
              
              
                '__new__'
              
              
                ,
              
              
                '__reduce__'
              
              
                ,
              
              
                '__reduce_ex__'
              
              
                ,
              
              
                '__repr__'
              
              
                ,
              
              
                '__setattr__'
              
              
                ,
              
              
                '__sizeof__'
              
              
                ,
              
              
                '__str__'
              
              
                ,
              
              
                '__subclasshook__'
              
              
                ,
              
              
                '__weakref__'
              
              
                ]
              
            
          

我们主要看一个属性__dict__,因为 __dict__保存的对象的属性,看下面一个例子

            
              
                >>
              
              
                >
              
              
                class
              
              
                Spring
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
                   season 
              
                =
              
              
                "the spring of class"
              
              
                .
              
              
                .
              
              
                .
              
              
                # 查看Spring类保存的属性
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
dict_proxy
              
                (
              
              
                {
              
              
                '__dict__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__dict__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                'season'
              
              
                :
              
              
                'the spring of class'
              
              
                ,
              
              
                '__module__'
              
              
                :
              
              
                '__main__'
              
              
                ,
              
              
                '__weakref__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__weakref__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__doc__'
              
              
                :
              
              
                None
              
              
                }
              
              
                )
              
              
                # 通过两种方法访问类属性
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
              
                [
              
              
                'season'
              
              
                ]
              
              
                'the spring of class'
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              season

              
                'the spring of class'
              
            
          

发现__dict__有个’season’键,这就是这个类的属性,其值就是类属性的数据.
接来看,看看它的实例属性

            
              
                >>
              
              
                >
              
               s 
              
                =
              
               Spring
              
                (
              
              
                )
              
              
                # 实例属性的__dict__是空的
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                }
              
              
                # 其实是指向的类属性
              
              
                >>
              
              
                >
              
               s
              
                .
              
              season

              
                'the spring of class'
              
              
                # 建立实例属性
              
              
                >>
              
              
                >
              
               s
              
                .
              
              season 
              
                =
              
              
                "the spring of instance"
              
              
                # 这样,实例属性里面就不空了。这时候建立的实例属性和类属性重名,并且把它覆盖了
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                'season'
              
              
                :
              
              
                'the spring of instance'
              
              
                }
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__
              
                [
              
              
                'season'
              
              
                ]
              
              
                'the spring of instance'
              
              
                >>
              
              
                >
              
               s
              
                .
              
              season

              
                'the spring of instance'
              
              
                # 类属性没有受到实例属性的影响
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
              
                [
              
              
                'season'
              
              
                ]
              
              
                'the spring of class'
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
dict_proxy
              
                (
              
              
                {
              
              
                '__dict__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__dict__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                'season'
              
              
                :
              
              
                'the spring of class'
              
              
                ,
              
              
                '__module__'
              
              
                :
              
              
                '__main__'
              
              
                ,
              
              
                '__weakref__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__weakref__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__doc__'
              
              
                :
              
              
                None
              
              
                }
              
              
                )
              
              
                # 如果将实例属性删除,又会调用类属性
              
              
                >>
              
              
                >
              
              
                del
              
               s
              
                .
              
              season

              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                }
              
              
                >>
              
              
                >
              
               s
              
                .
              
              season

              
                'the spring of class'
              
              
                # 自定义实例属性,对类属性没有影响
              
              
                >>
              
              
                >
              
               s
              
                .
              
              lang 
              
                =
              
              
                "python"
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                'lang'
              
              
                :
              
              
                'python'
              
              
                }
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__
              
                [
              
              
                'lang'
              
              
                ]
              
              
                'python'
              
              
                # 修改类属性
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              flower 
              
                =
              
              
                "peach"
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
dict_proxy
              
                (
              
              
                {
              
              
                '__module__'
              
              
                :
              
              
                '__main__'
              
              
                ,
              
              
                'flower'
              
              
                :
              
              
                'peach'
              
              
                ,
              
              
                'season'
              
              
                :
              
              
                'the spring of class'
              
              
                ,
              
              
                '__dict__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__dict__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__weakref__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__weakref__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__doc__'
              
              
                :
              
              
                None
              
              
                }
              
              
                )
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
              
                [
              
              
                'flower'
              
              
                ]
              
              
                'peach'
              
              
                # 实例中的__dict__并没有变化
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                'lang'
              
              
                :
              
              
                'python'
              
              
                }
              
              
                # 实例中找不到flower属性,调用类属性
              
              
                >>
              
              
                >
              
               s
              
                .
              
              flower

              
                'peach'
              
            
          

下面看看类中包含方法,__dict__如何发生变化

            
              
                # 定义类
              
              
                >>
              
              
                >
              
              
                class
              
              
                Spring
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                def
              
              
                tree
              
              
                (
              
              self
              
                ,
              
               x
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
                       self
              
                .
              
              x 
              
                =
              
               x

              
                .
              
              
                .
              
              
                .
              
              
                return
              
               self
              
                .
              
              x

              
                .
              
              
                .
              
              
                .
              
              
                # 方法tree在__dict__里面
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
dict_proxy
              
                (
              
              
                {
              
              
                '__dict__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__dict__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__weakref__'
              
              
                :
              
              
                <
              
              attribute 
              
                '__weakref__'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                ,
              
              
                '__module__'
              
              
                :
              
              
                '__main__'
              
              
                ,
              
              
                'tree'
              
              
                :
              
              
                <
              
              function tree at 
              
                0xb748fdf4
              
              
                >
              
              
                ,
              
              
                '__doc__'
              
              
                :
              
              
                None
              
              
                }
              
              
                )
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __dict__
              
                [
              
              
                'tree'
              
              
                ]
              
              
                <
              
              function tree at 
              
                0xb748fdf4
              
              
                >
              
              
                # 建立实例,但是__dict__中没有方法 
              
              
                >>
              
              
                >
              
               t 
              
                =
              
               Spring
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               t
              
                .
              
              __dict__

              
                {
              
              
                }
              
              
                # 执行方法
              
              
                >>
              
              
                >
              
               t
              
                .
              
              tree
              
                (
              
              
                "xiangzhangshu"
              
              
                )
              
              
                'xiangzhangshu'
              
              
                # 实例方法(t.tree('xiangzhangshu'))的第一个参数(self,但没有写出来)绑定实例 t,透过 self.x 来设定值,即给 t.__dict__添加属性值。
              
              
                >>
              
              
                >
              
               t
              
                .
              
              __dict__

              
                {
              
              
                'x'
              
              
                :
              
              
                'xiangzhangshu'
              
              
                }
              
              
                # 如果没有将x 赋值给 self 的属性,而是直接 return,结果发生了变化
              
              
                >>
              
              
                >
              
              
                class
              
              
                Spring
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                def
              
              
                tree
              
              
                (
              
              self
              
                ,
              
               x
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                return
              
               x

              
                >>
              
              
                >
              
               s 
              
                =
              
               Spring
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               s
              
                .
              
              tree
              
                (
              
              
                "liushu"
              
              
                )
              
              
                'liushu'
              
              
                >>
              
              
                >
              
               s
              
                .
              
              __dict__

              
                {
              
              
                }
              
            
          

需要理解python中的一个观点,一切都是对象,不管是类还是实例,都可以看成是对象,符合object.attribute ,都会有自己的属性

使用__slots__优化内存使用

默认情况下,python在各个实例中为名为__dict__的字典里存储实例属性,而字典会消耗大量内存(字典要使用底层散列表提升访问速度), 通过__slots__类属性,在元组中存储实例属性,不用字典,从而节省大量内存

            
              
                # 在类中定义__slots__属性就是说这个类中所有实例的属性都在这儿了,如果几百万个实例同时活动,能节省大量内存
              
              
                >>
              
              
                >
              
              
                class
              
              
                Spring
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
                   __slots__ 
              
                =
              
              
                (
              
              
                "tree"
              
              
                ,
              
              
                "flower"
              
              
                )
              
              
                .
              
              
                .
              
              
                .
              
              
                # 仔细看看 dir() 的结果,还有__dict__属性吗?没有了,的确没有了。也就是说__slots__把__dict__挤出去了,它进入了类的属性。
              
              
                >>
              
              
                >
              
              
                dir
              
              
                (
              
              Spring
              
                )
              
              
                [
              
              
                '__class__'
              
              
                ,
              
              
                '__delattr__'
              
              
                ,
              
              
                '__doc__'
              
              
                ,
              
              
                '__format__'
              
              
                ,
              
              
                '__getattribute__'
              
              
                ,
              
              
                '__hash__'
              
              
                ,
              
              
                '__init__'
              
              
                ,
              
              
                '__module__'
              
              
                ,
              
              
                '__new__'
              
              
                ,
              
              
                '__reduce__'
              
              
                ,
              
              
                '__reduce_ex__'
              
              
                ,
              
              
                '__repr__'
              
              
                ,
              
              
                '__setattr__'
              
              
                ,
              
              
                '__sizeof__'
              
              
                ,
              
              
                '__slots__'
              
              
                ,
              
              
                '__str__'
              
              
                ,
              
              
                '__subclasshook__'
              
              
                ,
              
              
                'flower'
              
              
                ,
              
              
                'tree'
              
              
                ]
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              __slots__

              
                (
              
              
                'tree'
              
              
                ,
              
              
                'flower'
              
              
                )
              
              
                # 实例化
              
              
                >>
              
              
                >
              
               t 
              
                =
              
               Spring
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               t
              
                .
              
              __slots__

              
                (
              
              
                'tree'
              
              
                ,
              
              
                'flower'
              
              
                )
              
              
                # 通过类赋予属性值
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              tree 
              
                =
              
              
                "liushu"
              
              
                # tree这个属性是只读的, 实例不能修改
              
              
                >>
              
              
                >
              
               t
              
                .
              
              tree 
              
                =
              
              
                "guangyulan"
              
              
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
  File 
              
                "
                
                  "
                
              
              
                ,
              
               line 
              
                1
              
              
                ,
              
              
                in
              
              
                <
              
              module
              
                >
              
              
AttributeError
              
                :
              
              
                'Spring'
              
              
                object
              
               attribute 
              
                'tree'
              
              
                is
              
               read
              
                -
              
              only

              
                >>
              
              
                >
              
               t
              
                .
              
              tree

              
                'liushu'
              
              
                # 对于用类属性赋值的属性,只能用来修改
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              tree 
              
                =
              
              
                "guangyulan"
              
              
                >>
              
              
                >
              
               t
              
                .
              
              tree

              
                'guangyulan'
              
              
                # 对于没有用类属性赋值的属性,可以通过实例来修改
              
              
                >>
              
              
                >
              
               t
              
                .
              
              flower 
              
                =
              
              
                "haitanghua"
              
              
                >>
              
              
                >
              
               t
              
                .
              
              flower

              
                'haitanghua'
              
              
                # 实例属性的值并没有传回到类属性,你也可以理解为新建立了一个同名的实例属性
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              flower

              
                <
              
              member 
              
                'flower'
              
               of 
              
                'Spring'
              
               objects
              
                >
              
              
                # 如果再给类属性赋值
              
              
                >>
              
              
                >
              
               Spring
              
                .
              
              flower 
              
                =
              
              
                "ziteng"
              
              
                >>
              
              
                >
              
               t
              
                .
              
              flower

              
                'ziteng'
              
            
          

如果使用的当,__slots__可以显著节省内存,按需要注意一下问题

  • 在类中定义__slots__之后,实例不能再有__slots__所列名称之外的其他属性
  • 每个子类都要定义__slots__熟悉,因为解释器会忽略继承__slots__属性
  • 如果不把__werkref__加入__slots__,实例不能作为弱引用的目标

属性的魔术方法

来看几个魔术方法

  • __setattr__(self,name,value):如果要给 name 赋值,就调用这个方法。
  • __getattr__(self,name):如果 name 被访问,同时它不存在的时候,此方法被调用。
  • __getattribute__(self,name):当 name被访问时自动被调用(注意:这个仅能用于新式类),无论 name 是否存在,都要被调用。
  • __delattr__(self,name):如果要删除 name,这个方法就被调用。
            
              
                >>
              
              
                >
              
              
                class
              
              
                A
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                def
              
              
                __getattr__
              
              
                (
              
              self
              
                ,
              
               name
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                print
              
              
                "You use getattr"
              
              
                .
              
              
                .
              
              
                .
              
              
                def
              
              
                __setattr__
              
              
                (
              
              self
              
                ,
              
               name
              
                ,
              
               value
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                print
              
              
                "You use setattr"
              
              
                .
              
              
                .
              
              
                .
              
                       self
              
                .
              
              __dict__
              
                [
              
              name
              
                ]
              
              
                =
              
               value

              
                # a.x,按照本节开头的例子,是要报错的。但是,由于在这里使用了__getattr__(self, name) 方法,当发现 x 不存在于对象的__dict__中的时候,就调用了__getattr__,即所谓“拦截成员”。
              
              
                >>
              
              
                >
              
               a 
              
                =
              
               A
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               a
              
                .
              
              x
You use 
              
                getattr
              
              
                # 给对象的属性赋值时候,调用了__setattr__(self, name, value)方法,这个方法中有一句 self.__dict__[name] = value,通过这个语句,就将属性和数据保存到了对象的__dict__中
              
              
                >>
              
              
                >
              
               a
              
                .
              
              x 
              
                =
              
              
                7
              
              
You use 
              
                setattr
              
              
                # 测试__getattribute__(self,name)
              
              
                >>
              
              
                >
              
              
                class
              
              
                B
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                def
              
              
                __getattribute__
              
              
                (
              
              self
              
                ,
              
               name
              
                )
              
              
                :
              
              
                .
              
              
                .
              
              
                .
              
              
                print
              
              
                "you are useing getattribute"
              
              
                .
              
              
                .
              
              
                .
              
              
                return
              
              
                object
              
              
                .
              
              __getattribute__
              
                (
              
              self
              
                ,
              
               name
              
                )
              
              
                # 返回的内容用的是 return object.__getattribute__(self, name),而没有使用 return self.__dict__[name]。因为如果用这样的方式,就是访问 self.__dict__,只要访问这个属性,就要调用`getattribute``,这样就导致了无限递归
              
              
                # 访问不存在的成员,可以看到,已经被__getattribute__拦截了,虽然最后还是要报错的。
              
              
                >>
              
              
                >
              
               b 
              
                =
              
               B
              
                (
              
              
                )
              
              
                >>
              
              
                >
              
               b
              
                .
              
              y
you are useing getattribute
Traceback 
              
                (
              
              most recent call last
              
                )
              
              
                :
              
              
  File 
              
                "
                
                  "
                
              
              
                ,
              
               line 
              
                1
              
              
                ,
              
              
                in
              
              
                <
              
              module
              
                >
              
              
  File 
              
                "
                
                  "
                
              
              
                ,
              
               line 
              
                4
              
              
                ,
              
              
                in
              
               __getattribute__
AttributeError
              
                :
              
              
                'B'
              
              
                object
              
               has no attribute 
              
                'y'
              
            
          

Property函数

porperty可以作为装饰器使用把方法标记为特性

            
              
                class
              
              
                Vector
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                ,
              
               x
              
                ,
              
               y
              
                )
              
              
                :
              
              
                # 使用两个前导下划线,把属性标记为私有
              
              
        self
              
                .
              
              __x 
              
                =
              
              
                float
              
              
                (
              
              x
              
                )
              
              
        self
              
                .
              
              __y 
              
                =
              
              
                float
              
              
                (
              
              y
              
                )
              
              
                # porperty装饰器把读值方法标记为特性
              
              
    @
              
                property
              
              
                def
              
              
                x
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                return
              
               self
              
                .
              
              __x
        
    @
              
                property
              
              
                def
              
              
                y
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                return
              
               self
              
                .
              
              __y
        
vector 
              
                =
              
               Vector
              
                (
              
              
                3
              
              
                ,
              
              
                4
              
              
                )
              
              
                print
              
              
                (
              
              vector
              
                .
              
              x
              
                ,
              
               vector
              
                .
              
              y
              
                )
              
            
          

使用property可以将函数封装为属性

            
              
                class
              
              
                Rectangle
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                """
    the width and length of Rectangle
    """
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                )
              
              
                :
              
              
        self
              
                .
              
              width 
              
                =
              
              
                0
              
              
        self
              
                .
              
              length 
              
                =
              
              
                0
              
              
                def
              
              
                setSize
              
              
                (
              
              self
              
                ,
              
               size
              
                )
              
              
                :
              
              
        self
              
                .
              
              width
              
                ,
              
               self
              
                .
              
              length 
              
                =
              
               size
    
              
                def
              
              
                getSize
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                return
              
               self
              
                .
              
              width
              
                ,
              
               self
              
                .
              
              length


              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    r 
              
                =
              
               Rectangle
              
                (
              
              
                )
              
              
    r
              
                .
              
              width 
              
                =
              
              
                3
              
              
    r
              
                .
              
              length 
              
                =
              
              
                4
              
              
                print
              
               r
              
                .
              
              getSize
              
                (
              
              
                )
              
              
                # (3,4)
              
              
    r
              
                .
              
              setSize
              
                (
              
              
                (
              
              
                30
              
              
                ,
              
              
                40
              
              
                )
              
              
                )
              
              
                print
              
               r
              
                .
              
              width    
              
                # 30
              
              
                print
              
               r
              
                .
              
              length    
              
                # 40
              
            
          

这段代码可以正常运行,但是属性的调用方式可以改进,如下

            
              
                class
              
              
                Rectangle
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                """
    the width and length of Rectangle
    """
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                )
              
              
                :
              
              
        self
              
                .
              
              width 
              
                =
              
              
                0
              
              
        self
              
                .
              
              length 
              
                =
              
              
                0
              
              
                def
              
              
                setSize
              
              
                (
              
              self
              
                ,
              
               size
              
                )
              
              
                :
              
              
        self
              
                .
              
              width
              
                ,
              
               self
              
                .
              
              length 
              
                =
              
               size
    
              
                def
              
              
                getSize
              
              
                (
              
              self
              
                )
              
              
                :
              
              
                return
              
               self
              
                .
              
              width
              
                ,
              
               self
              
                .
              
              length
    
              
                # 使用property方法将函数封装为属性,更优雅
              
              
    size 
              
                =
              
              
                property
              
              
                (
              
              getSize
              
                ,
              
               setSize
              
                )
              
              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    r 
              
                =
              
               Rectangle
              
                (
              
              
                )
              
              
    r
              
                .
              
              width 
              
                =
              
              
                3
              
              
    r
              
                .
              
              length 
              
                =
              
              
                4
              
              
                print
              
               r
              
                .
              
              size     
              
                # (30, 40)
              
              
    r
              
                .
              
              size 
              
                =
              
              
                30
              
              
                ,
              
              
                40
              
              
                print
              
               r
              
                .
              
              width    
              
                # 30
              
              
                print
              
               r
              
                .
              
              length    
              
                # 40
              
            
          

使用魔术方法实现:

            
              
                class
              
              
                NewRectangle
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
                def
              
              
                __init__
              
              
                (
              
              self
              
                )
              
              
                :
              
              
        self
              
                .
              
              width 
              
                =
              
              
                0
              
              
        self
              
                .
              
              length 
              
                =
              
              
                0
              
              
                def
              
              
                __setattr__
              
              
                (
              
              self
              
                ,
              
               name
              
                ,
              
               value
              
                )
              
              
                :
              
              
                if
              
               name 
              
                ==
              
              
                'size'
              
              
                :
              
              
            self
              
                .
              
              width
              
                ,
              
               self
              
                ,
              
               length 
              
                =
              
               value
        
              
                else
              
              
                :
              
              
            self
              
                .
              
              __dict__
              
                [
              
              name
              
                ]
              
              
                =
              
               value
            
    
              
                def
              
              
                __getattr__
              
              
                (
              
              self
              
                ,
              
               name
              
                )
              
              
                :
              
              
                if
              
               name 
              
                ==
              
              
                'size'
              
              
                :
              
              
                return
              
               self
              
                .
              
              width
              
                ,
              
               self
              
                .
              
              length
        
              
                else
              
              
                :
              
              
                raise
              
               AttrubuteErrir
            

              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    r 
              
                =
              
               Rectangle
              
                (
              
              
                )
              
              
    r
              
                .
              
              width 
              
                =
              
              
                3
              
              
    r
              
                .
              
              length 
              
                =
              
              
                4
              
              
                print
              
               r
              
                .
              
              size     
              
                # (30, 40)
              
              
    r
              
                .
              
              size 
              
                =
              
              
                30
              
              
                ,
              
              
                40
              
              
                print
              
               r
              
                .
              
              width    
              
                # 30
              
              
                print
              
               r
              
                .
              
              length    
              
                # 40
              
            
          

属性的获取顺序

最后我们来看看熟悉的获得顺序:通过实例获取其属性,如果在__dict__中有相应的属性,就直接返回其结果;如果没有,会到类属性中找。
看下面一个例子:

            
              
                class
              
              
                A
              
              
                (
              
              
                object
              
              
                )
              
              
                :
              
              
    author 
              
                =
              
              
                "qiwsir"
              
              
                def
              
              
                __getattr__
              
              
                (
              
              self
              
                ,
              
               name
              
                )
              
              
                :
              
              
                if
              
               name 
              
                !=
              
              
                "author"
              
              
                :
              
              
                return
              
              
                "from starter to master."
              
              
                if
              
               __name__ 
              
                ==
              
              
                "__main__"
              
              
                :
              
              
    a 
              
                =
              
               A
              
                (
              
              
                )
              
              
                print
              
               a
              
                .
              
              author 
              
                # qiwsir
              
              
                print
              
               a
              
                .
              
              lang  
              
                # from starter to master.
              
            
          

当 a = A() 后,并没有为实例建立任何属性,或者说实例的__dict__是空的。但是如果要查看 a.author,因为实例的属性中没有,所以就去类属性中找,发现果然有,于是返回其值 “qiwsir”。但是,在找 a.lang的时候,不仅实例属性中没有,类属性中也没有,于是就调用了__getattr__()方法。在上面的类中,有这个方法,如果没有__getattr__()方法呢?如果没有定义这个方法,就会引发 AttributeError,这在前面已经看到了。


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论