PYTHON成员变量定义在模块代码中的几个不同位置时的属性表现

自己10几年前有过C++的编程能力,现在在学习PYTHON时也没注意过代码中变量定义在不同位置时的表现,造成运行时出现许多不可理解的错误或跟预期值不相符,这才发现自己对PYTHON中的变量定义在不同位置时的表现是不全了解的,故临时作了一个示例程序,分别将两种不同的变量:整数变量和列表变量分别放在模块头(类外),类头部(init构造初如化代码前部),类中间(init类初始化或其其他函数体中间), 以了解各种位置的成员变量在作赋值运算时的行为,可能不太全面,应基本表达了对成员变量定义时选用位置的方式和注意的问题,同小白共同探讨学习

示例代码如下:

#本示例演示各种变量定义的位置不同时的引用及值结果
import copy    #使用深度COPY,以解决PYTHON列表,字典类变量使用=号赋值后的绑定共用内存现象
import g       #假如其他模块文件头部的全局变量本模块要用,import此模块文件名(如g.py模块文件头部有全局变量定义g_num=13579),如采用此种方式,则g.py中的全局变量使方法:g.g_num即可
#另一种方式导入g.py中的全局变量g_num ,则用以下代码来实现对g.py中的全局变量g_num的使用
from g import g_num      #使用golbal g_num定义好象无效?
g_ID=1                   #本模块定义的数字类型全局变量
g_lst=['文本顶部定义的列表类型变量','abc'] #本模块定义的列表类型全局变量

#定义父类ABC
class ABC():
    global g_num #好象无用,只能用g.g_num 或from g import g_num后直接用g_num才行
    ABC_ID=0           #即此变量为类ABC全部实例化对象共有,使用方法:ABC.ABC_ID ,此区域定义变量可用作整个类实例化对象公用的变量,如作为类对象实例化的数量计数等等
    ABC_lst=['父类在init初始化类对象前定义的列表变量',''] #即此变量为类A全部实例化对象共有,使用方法:A.A_lst(但因列表的绑定关系, 此值的同最后一次绑定的列表有关,要分清)
    def __init__(self,id,lst,parent=None): #父类实例化对象时首先调用的函数(函数中的参数同子类要相对应)
        #global g_ID1
        g_ID=id  #将函数体引来的id变量分别赋值给三种整数类型的变量,看结果
        g_lst=lst
        print(f'1父类ABC以外(文件头部)的全局变量g_ID={g_ID}')  #结果,值等于函数传递过来的id值
        print(f'1父类ABC以外(文件尾部)的全局变量g_ID={g_ID1}')  #调用文件尾部又定义的一全局变量
        print(f'2父类ABC以外(文件头部)的全局变量g_lst={g_lst}')    #结果:同函数参数lst共用内存绑定,本类更改或调用处更改结果会同步,即其实是一个变量
        print(f'3父类:其他模块文件如g.py中的的全局变量{g_num}')    #调用其他模块文件如g.py中的全局变量
        ABC_ID=222     #不加self前缀,给init外的类共用变量赋值(不会报错)
        self.ABC_ID=id   #在加上self前缀单独进行赋值一道(注意:此self.ABC_ID 同ABC_ID不是一个变量,只是名称相同)
        self.ABC_lst=lst #必须在列表及字典类的变量前在加self前缀,否则报错(即同init前的类成员定义无关),此语名将self.ABC_lst也同函数列表变量lst共用内存绑定
        self.ABC_name='父类成员变量self.ABC_name' #此成员变量没有通过init初始化时传入

        print(F'4父类ABC在init后的本类中的两种变量变化情况:')
        print(f'5父类init外部的ABC_ID={ABC_ID}')    #值为函数传过来的值111
        print(f'6父类init内部的self.ABC_ID={self.ABC_ID}') #父类任何一个实例化对象都可更改此类init外定义的全局变量,除特殊要求一般不用,避免类对象更改后的值不可预料
        print(f'7父类init外列表对象ABC_lst={ABC.ABC_lst}') #对init之前定义的对象使用方式为:类名.变量名
        print(f'8父类init内部列表对象self.ABC_lst={self.ABC_lst}') #对init之前定义的对象使用方式为:类名.变量名

        #对init中定义的列表类变量重新赋值,看结果
        self.ABC_lst[0]='8父类重新赋值self.ABC_lst[0]'
        print(f'9父类重新赋值self.ABC_lst后,init外的列表变量的值ABC_lst={ABC.ABC_lst}') #变量名前必须加类名,结果同self.ABC_lst相同,表示这两个列表变量共用内存,实际是一个变量,对其中一个更改,另一个同步变化
        newlst=['10父类新定义一个列表,让init内的self.ABC_lst同其绑定','']
        self.ABC_lst[0]=newlst     #此方法又将self.ABC_lst[0]同newlst绑定了,变化其中一个另一个也要变
        self.ABC_lst[0]=copy.deepcopy(newlst) #此方法不会将self.ABC_lst[0]同newlst绑定,变化一个另一个不会变化
        print(f'11父类重新绑定self.ABC_lst后,init外的列表变量的值ABC_lst={ABC.ABC_lst}') #结果,init内的self.ABC_lst不再同init外的ABC_lst值相同了(无关联了)4
    
    def ABC_test(self):
        print(f'12父类test函数:ABC中的init以外的变量ABC_ID={ABC.ABC_ID},父类ABC中的init成员变量self.ABC_ID={self.ABC_ID}')
        print(f'13父类test函数:在子类中更必父类的self.ABC_name内容后= {self.ABC_name}')
        self.newID=9876 #父类临时增加一个全对象周期的成员变量self.newI

    def ABC_getID(self):
        return self.ABC_ID

#定义继承ABC类的子类A 
class A(ABC):
    A_ID=999        #即此变量为类A全部实例化对象共有,使用方法:A.A_ID
    A_lst=['子类A init外的列表变量',''] #即此变量为类A全部实例化对象共有,使用方法:A.A_lst(但因列表的共用绑定特性, 此值的同最后一次绑定的列表量有关,要分清楚)
    def __init__(self,id,lst,addv,parent=None): #子类初始化函数,参数可以多过父类
        super().__init__(id,lst,parent) #必须同先调用父类中的初始化函数,传入2个参数,另一个不传入子类自用

        #子类要使用父类ABC中的self.ABC_ID等变量,必须用同时初始化父类变量super().__init__(id...,传入
        self.addv=addv   #子类初化比父类多出的变量,为子类独有
        pid0=super().ABC_ID  #此方法调用的是父类init之外的变量ABC_ID,不是父类self.ABC_ID
        pid1=self.ABC_getID()  #真接使用父类中的函数得到父类中成员self.ABC_ID的值
        print(f"14子类A中的得到的父类ABC.ABC_ID={pid0},self.ABC_ID={pid1}") #两值不相同,表示子类中的self.ABC_ID并没有继承父类中的self.ABC_ID属性,是不同的变量

    #子类重载父类函数ABC_test()
    def ABC_test(self):
        self.ABC_ID=123456       #此成员变量为继承父类的(且此变量是通过init初始化构造时传入的)
        self.ABC_name='子类A中更改父类对象ABC_name' #此成员变量为继承父类的(且此变量不是通过init初始化构造时传入的)
        self.newID=6789 #子类先于父类增加一个本子类实例用的变量self.newID,看是否同下面父类新增的同名变量冲突:结果来不论在哪里创建,只要名称相同,父类子类就可通用
        super().ABC_test()       #如要父类同时调用同名函数应用super(),否则系统不会自动调用父类的同名函数的,调用时,父类临时增加了一变量self.newID
        print(f'15子类test函数:子类A中的init以外的变量A_ID={A.A_ID},子类A中的init成员变量self.A_ID={self.A_ID}')
        print(f'16当前self.newID={self.newID}')
    #类成员实例化init完成后供类成员调用的示例函数 
    def Atest(self):
        #self.ABC_ID=1234 #更新实例化后的对象属性值
        print(f'17当前子类A中的的成员变量(实际是继承父类的)self.ABC_ID={self.ABC_ID}')

#代码尾部再定义一个全局变量
g_ID1=2024

if __name__ == "__main__":
    lst1=['父类调用:函数参数1:列表对象,传入类中同类中的类外变量ABC_lst绑定,列表及字典对象传递时共用内存,同其他变量不同','']
    #实例化一个父类ABC对象cABC01
    cABC01=ABC(111,lst1)
    lst2=['子类调用:函数参数1:列表对象,传入类中同类中的类外变量ABC_lst绑定,列表及字典对象传递时共用内存,同其他变量不同','']
    #实例化一个子类A对象cA01
    cA01=A(666,lst2,777) #id初始化为666,后面被更改了几次
    cA01.ABC_test() #调用子类中重载父类的函数
    cA01.Atest()   #调用子类中定义的函数

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mr_LuoWei2009

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值