• Python魔法方法(magic method)细解几个常用魔法方法(下)


    接上文,再介绍最后几个常用的魔法方法。

    关于__dict__:

    先上个例子:

    class Test(object):
        fly = True
    
        def __init__(self, age):
            self.age = age

    __dict__魔法方法可以被称为系统,他是存储各分层属性的魔法方法。__dict__中,键为属性名,值为属性本身。可以这样理解,在平时我们给类和实例定义的那些属性,都会被存储到__dict__方法中用于读取。而我们平时使用的类似这样的语法Test.fly 其实就是调用了类属性,同样可以写成Test.__dict__['fly']。除了类属性,还有实例属性。当我们用类实例化一个实例,例如上文我们使用p = Test(2)实例化类Test,p也会具有__dict__属性。这里会输出:

    {'age': 2}

    由上可以发现,python中的属性是进行分层定义的。/object/Test/p这样一层一层下来的。当我们需要调用某个属性的时候,python会一层一层往上面遍历上去。先从实例,然后实例的__class__的__dict__,然后是该类的__base__。这样__dict__一路找上去。如果最后都没有找到,就抛出AttributeError错误。

    这里可以延伸一下,没记错的话,我前面有篇文章讲了一个方法__slot__。__slots__方法就是通过限制__dict__,只让类实例初始化__slots__里面定义的属性,而且让实例不再拥有__dict__方法,来达到节约内存的目的。我将会就上面的那个例子重写一下,来说明这个问题。

     class Test(object):
         __slots__ = ['age']
    
         fly = True
    
         def __init__(self, age):
             self.age = age

    output:

    In [25]: Test.__dict__
    Out[25]:
    dict_proxy({'__doc__': None,
                '__init__': <function __main__.__init__>,
                '__module__': '__main__',
                '__slots__': ['age'],
                'age': <member 'age' of 'Test' objects>,
                'fly': True})
    
    
    In [36]: p.__dict__
    ---------------------------------------------------------------------------
    AttributeError                            Traceback (most recent call last)
    <ipython-input-36-3a1cec47d020> in <module>()
    ----> 1 p.__dict__
    
    AttributeError: 'Test' object has no attribute '__dict__'
    
    In [37]: p.age
    Out[37]: 3
    
    In [38]: p.fly
    Out[38]: True

    可以看到,__slots__方法并没有阻止由下至上的属性查找方法,只是不会再允许没有包含在__slots__数组中的属性再被赋值给实例了。但这并不妨碍,继续调用允许访问的属性,以及类属性。

    关于__get__, __set__, __del__:

    在前面的文章里面我也介绍过这三个魔法方法,虽然一般是用不到的,但是在写库的时候它们有特别的用途。他们是python另外一个协议descriptor的根基。

    同一个对象的不同属性之间可能存在依赖关系。当某个属性被修改时,我们希望依赖于该属性的其他属性也同时变化。在这种环境下面__dict__方法就无法办到。因为__dict__方法只能用来存储静态属性。python提供了多种即时生成属性的方法。其中一种就是property。property是特殊的属性。比如我们为上面的例子增加一个property特性,使得他能够动态变化。来看这个例子:

    class Test(object):
        fly = True
    
        def __init__(self, age):
            self.age = age
    
        def whether_fly(self):
            if self.age <= 30:
                return True
            else:
                return False
    
        def just_try_try(self, other):
            pass
    
        whether_fly = property(whether_fly)
    
    p = Test(20)
    print p.age
    print p.whether_fly
    p.age = 40
    print p.age
    print p.whether_fly

    output:

    20
    True
    40
    False

    可以看到 我们可以使用这种手段,动态修改属性值。property有四个参数。前三个参数为函数,分别用于处理查询特性、修改特性、删除特性。最后一个参数为特性的文档,可以为一个字符串,起说明作用。这里我只是要到了第一个参数,查询的时候动态修改他的返回值,而第二个参数是在修改值的时候就会体现出来。

    Reference:

    http://www.cnblogs.com/vamei/archive/2012/12/11/2772448.html

  • 相关阅读:
    一个用于录制用户输入操作并实时回放的小工具
    Ubuntu 14.04 下安装wiznote客户端
    lombok @EqualsAndHashCode 注解的影响
    初始化数据库和导入数据
    com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别 serverTimezone设定
    fastjson如何指定字段不序列化
    Mybatis 查询tinyint(1)的数据库字段时会自动转换成boolean类型
    Maven中settings.xml的配置项说明
    logback的使用和logback.xml详解
    解决Eureka Server不踢出已关停的节点的问题
  • 原文地址:https://www.cnblogs.com/piperck/p/6362203.html
Copyright © 2020-2023  润新知