通过一个例子讨论python中类属性的一些性质

前言

    类属性和实例变量区别比较大,本文均为举例说明,为例实现变量值的动态变化,采用redis数据库,不过读者不用担心,对于涉及到redis数据库的地方都会通俗到极致。

正文

    首先,有这样一段代码。

import databases as db

class Test:
    mydb = db.DatabaseRun()    # 创建数据库实例
    data = mydb.redis_conn.get('test')    # 获取test的键值
    res = mydb.redis_conn_excute()

    def __init__(self, name):
        self.name = name

    def call(self):
        print(self.res)


if __name__ == '__main__':
    while True:
        r = Test('test')
        r.call()    # 在此处添加一个断点
        time.sleep(2)    # 在此处添加一个断点

解释一下,这里我预先写了一个操作数据库的py文件为databases,跟本文没啥关系,只要知道是操作数据库的就行。

这段代码,定义了一个类变量res,变量值读取了redis数据库中test的键值。

接下来,我们进入redis中,新建一个test键,值为a。

然后我们 debug运行python代码,来到第一个断点,此时已经创建了一个实例。

我们来看一下实例里各变量的值。

看到此时res类变量值为['a'],是我们在redis中设置的值,接下来,来到下一个断点,即将休眠2秒,此时我们修改redis中test的键值为b。

 接下来继续往下运行python,执行休眠2秒,循环完成一次,进入下一次循环,创建实例,来到断点

此时我们来看一下各变量的值。

神奇的事情出现了,res的值仍然为['a']而不是我们期待的['b']。

如果我们关闭程序,重新运行,则res的值为['b']

接下来我们加入实例变量,并将redis中test的值改回a。

更改代码:

 

import random
import databases as db
import pypinyin
import time


class Test:
    mydb = db.DatabaseRun()
    data = mydb.redis_conn.get('test')
    res = mydb.redis_conn_excute()

    def __init__(self, name):
        self.name = name
        self.mydb_2 = db.DatabaseRun()    # 建立数据库对象
        self.data_2 = self.mydb_2.redis_conn.get('test')    #查找test值
        self.res_2 = self.mydb_2.redis_conn_excute()    # 获取返回值,此为被观察变量

    def call(self):
        print(self.res)


if __name__ == '__main__':
    while True:
        r = Test('test')
        r.call()
        time.sleep(2)

这里增加了一个res_2变量来观察。

重设redis中test值为a:

接下来dubug运行至第一个断点,看一下各变量值。

 

此时类变量res和实例变量res_2值均为['a'],为redis数据库内test的值

接下来我们修改redis中test的键值为c。

 

继续往下运行python,休眠2秒后进入第二次循环,创建实例,来到第一个断点,看一下各变量的值。

 

神奇的一幕又出现了,类变量res值没变,实例变量res_2值变为了['c']。

接下来我们结束运行,重新debug,来到第一个断点,查看变量值。

 

此时类变量与实例变量值均为['c']。

分析与结论

    在python中类变量是在声明类时创建的,类声明完毕后即建立了变量,并存于内存之中,其值不会受任何实例的影响,变量为所有实例共用,在程序结束以前,不会因外界的改变而改变(例如本例中类变量获取途径为读取数据库,类变量的值不会因为数据库内值改变而改变),是静态的,用鞭子抽也不会动弹的变量,如果想修改类变量值,需在方法内运用global关键字(千万不要这么做,90%的风险被公司开除)。

    而实例变量则在创建实例时,由__init__方法进行初始化,每创建一次实例都会重新定义实例变量的值(本例中重新读取一次数据库)。

    所以,对于永远不会变的变量,还是写到类变量里面,例如某些常量(例如requests模块连接时用到的请求头字典),这样避免了多次实例化时浪费内存。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值