上一篇文章简要介绍了python类使用的基本框架,实际上已经简要介绍了类变量。本文再进一步介绍一下类变量相关的一些重要内容和类变量的使用。要注意一下类中定义的函数也叫方法哦,不要被搞懵了,因为我可能两种说法都在用。
讲的比较啰嗦,但是认真看的话会有收获的喔!
附上类使用专栏的其它文章的链接:
- python 类的使用(1) 之类使用的基本框架
- python 类的使用(2) 之类变量
- python 类的使用(3)之类中常用的三个装饰器@classmethod、@staticmethod、@property
- python 类的使用(4)之类常用的魔法方法
- python 类的使用(5)之类装饰器(类的装饰器和类作为装饰器)
- python 类的使用(6)之类的继承
- python 类的使用(7)之类的私有属性和方法 (类中以单下划线或双下划线开头的变量名或函数名)
类变量
类变量就是某个类中定义的在类方法之外独立存在的变量,由于类变量不存在于某个函数中,因此可以直接在使用某个类的时候被调用。在调用某个类时还能够在类的外部重新定义类变量的值或者新增某些类变量;除此外类变量还能够被类中定义的方法所使用及改变。一眼看到这些语句可能会有点懵,咱们一个一个看例子吧:
基础的类变量被函数使用的例子
class Worker: # 此处类命名也可以加上括号,不影响
raise_percent = 1.05
# 这样在类中独立定义的变量就是类变量,可以被类本身或者类方法直接调用 (此处的意义是涨工资的比例)
num_of_worker = 0 # 工人数量
def __init__(self, name, salary):
self.name = name
self.salary = salary
Worker.num_of_worker += 1
'''
在初始函数init中调用类本身的类变量,此处的意思是每传入一次类实例,就会增加一个工作人员,
也就是这里是对整个类来说的。而这里Worker.num_of_worker的Worker也最好不要使用self代替,
使用self的意思不是很明确,因为self本身只代表一个类实例,其不能代表整个类的情况。
'''
def raise_salary(self):
self.salary = self.salary * self.raise_percent
'''
这里的函数中传入了self,因此函数可以通过self.raise_percent获取到类变量,从而参与计算,
这里的意义是将类实例传入的工资乘以上涨工资的比例从而将工资提升。
当然要改变涨工资的比例即raise_percent这个类变量也是可以的,接下来会展示其它例子
'''
A = Worker('Jack',1000) # 传入一个类实例
print('Jack的初始工资:',A.salary)
print('涨工资的比例:',A.raise_percent) # 打印查看类实例的类变量
A.raise_salary() # 通过调用类中涨工资的函数给A实例涨工资
print('涨工资后Jack的工资是:',A.salary) # 查看工资是否涨成功
print('工作人员数:',A.num_of_worker) # 查看另一个类变量即工作人员数是否变化
运行上面代码的结果:
从这个结果中看出来,使用涨工资函数后,工资确实被涨了,工作人员数也从开始的0个变为了1个。应该也不需要什么解释啦。
在类的函数中改变类变量
使用类的时候,我们在某些函数调用后可能需要修改一下函数的类变量,这样的情况就可以在类函数中修改类的变量,其实使用方式很简单啦,就展示一下例子就好啦!
class Worker: # 此处类命名也可以加上括号,不影响
raise_percent = 1.05
def __init__(self, name, salary):
self.name = name
self.salary = salary
def raise_salary(self): # # 涨普通工资的方法
self.salary = self.salary * self.raise_percent
return self.salary
def raise_higher_salary(self): # 涨高工资的方法
self.raise_percent = 1.08
self.salary = self.salary * self.raise_percent
return self.salary
def raise_lower_salary(self): # 涨低工资的方法
self.raise_percent = 1.03
self.salary = self.salary * self.raise_percent
A = Worker('Jack', 1000)
B = Worker('Mary', 1000)
C = Worker('Lucy', 1000)
A.raise_salary()
print('A涨薪后的工资:',A.salary)
print(A.raise_percent)
print(Worker.raise_percent)
B.raise_higher_salary() # B涨的是高工资
print('B涨薪后的工资:', B.salary)
print(B.raise_percent)
print(Worker.raise_percent)
C.raise_lower_salary() # C涨的是低工资
print('C涨薪后的工资:', C.salary)
print(C.raise_percent)
print(Worker.raise_percent)
结果:
这里简单解释一下,可以看到上面的工资都改变了,同时A、B、C三者的涨薪比例也都不一样了,但是可以看到Worker类的涨薪比例未改变,这表明了在类函数中修改的类变量仅在函数中生效,是局部变量,不影响整个类的类变量,那么你可能会想我如果想让类方法中修改的类变量在整个类中生效的话要怎么办呢,这就可以用到后续的类方法装饰器也即classmethod啦,使用nonlocal或者global好像有点问题,类方法在下一篇博客哦。
在外部调用类时改变类变量
还是使用上面的代码,不过这次增加一些工作人员:
class Worker: # 此处类命名也可以加上括号,不影响
raise_percent = 1.05
num_of_workers = 0 # 工人数量
def __init__(self, name, salary):
self.name = name
self.salary = salary
Worker.num_of_workers += 1
def raise_salary(self):
self.salary = self.salary * self.raise_percent
A = Worker('Jack',1000)
B = Worker('Mary',1000)
C = Worker('Lucy',1000)
# 这里查看三个类实例是否是独立存在于内存中的
print(A)
print(B)
print(C)
# 接下来查看在类外部修改类变量后的结果及对类的影响,即A、B的涨薪比例
print('初始涨工资的比例:',A.raise_percent)
A.raise_salary()
print('A涨薪后的工资:',A.salary)
B.raise_percent = 1.1
B.raise_salary()
print('B涨薪后的工资:',B.salary)
print('A的涨薪比例:',A.raise_percent,'C的涨薪比例',C.raise_percent)
# 这里通过类实例和类本身来查看类变量的变化情况
print('工作人员数:',A.num_of_workers)
print('工作人员数:',B.num_of_workers)
print('工作人员数:',Worker.num_of_workers)
运行结果如下:
这里介绍一下上面的结果:
- 首先打印三个类实例对象,可以看出它们在内存中存在的位置不同,因此他们并不代表同一个东西哦。
- 首先类中的类变量即raise_percent默认设置为1.05,因此A在未调整涨薪比例的情况下涨的工资是在初始的比例下进行的,A涨薪后的工资就只有1050
- 但是接下来我将B的涨薪比例提高到了1.1,这样对B使用涨薪函数后,B的工资涨到了1100,这是按照1.1的比例来得到的
- 之后再尝试查看A和C的涨薪比例,两者没有发生变化,代表对B的类变量的改变没有影响到A和C的类变量
- 但接下来查看工作人员数即num_of_workers,发现无论通过A、B或者是Worker类来查看得到的结果都是3。但是我实际上创建A、B、C三个类实例的时候是分开创建的,上面的内存位置也显示他们的储存位置不同,但这里他们的类变量却混用了。
- 这是咋回事呢?经过查看网上的博客和反复思考,个人认为原因如此:由于A、B、C分开创建,它们各自的创建使用的类变量是公用的,也就是每创建一个类实例,整个类的类变量(包含类实例所能访问到的类变量)会被更新(init函数中设定的更新)。也就是说通过类创建的类实例都共用类变量,每次创建类实例时使用的类变量是上一次创建类实例更新后的类变量,而创建类实例后的类变量也就成为了之前所有类实例和整个类的类变量。这样也就能解释上面的现象了。而查看num_of_workers的内存地址也发现它们都是一样的(如下)。
- 但是上面的B的类变量raise_percent被改变了后为什么A与C的类变量raise_percent没有被改变呢?这是因为,在类外部对某个类实例拥有的类变量进行直接的修改相当于只改变了这个特定类实例的类变量属性,这是不会影响到其它的类实例和类变量的。即使不是直接修改,如使用A.num_of_worker += 1这样的方式也是只会改变A的类变量属性哦(可以自己试一下)。
- 还有另外的一些情况在类外部操作类变量也不会改变整个类的类变量,那就是列表、集合、字典、自定义类等这些类变量,这些情况下的类变量也是可以在外部进行增删的操作的,但是要注意不能直接修改哦,修改的话就和上面修改类变量无异了。
看下例子:
class new_list:
l = []
A = new_list()
B = new_list()
C = new_list()
A.l.append('yes')
print(A.l)
print(B.l)
print(C.l)
代码运行结果为:
而如果是改的情况:
class new_list:
l = []
A = new_list()
B = new_list()
C = new_list()
A.l = 'no'
print(A.l)
print(B.l)
print(C.l)
结果如下:
这样就能看出来类变量若是是列表之类的形式,那么所有的类实例就都是共用一个内存地址了吧。以后一定不要搞混啦!
总结
感觉内容有点散,需要总结一下。
- 首先类变量的定义,是在类中独立定义的不在类方法中的变量
- 其次若无特殊情况(比如外部对类实例的修改等情况),所有创建的类实例都使用同一个共用的类变量,其在内存中的地址相同。
- 在类的方法(即函数)中对类变量进行修改是不会影响到类本身的变量的,其修改仅在函数中局部有效。
- 若某个类实例对类变量修改,那么只是这个实例的类变量被修改,其它类实例及类本身的类变量不改变。
- 列表、字典等变量形式可以在不改变类变量的公用性的情况下进行增删操作,即某个类实例对列表或字典类的类变量进行增删操作是会同时操作到其它类实例的类变量的,它们使用的类变量是共用的。
叮!
最近忙呀,没啥时间写。今天的文章写的可能也不好,因为写的太冗长了,读起来可能较花时间。但是还是花功夫认真写了,若是认真读下来我觉得还是会有收获的。大家一起加油吧!
参考:https://blog.youkuaiyun.com/xuzhexing/article/details/93915962
参考:Corey Schafer的python视频教程