python类变量与__init__声明变量的区别

枫铃3年前 (2021-09-30)Python238
  • 类变量:可在类的所有实例之间共享的变量
  • 实例类对象:类的实例是调用类对象来创建的。如:par = Parent(),par就是类Parent的一个实例类对象。
  • 实例变量(成员变量):同一个类对象可以创建多个实例类对象,类定义中有self标志的变量就是实例变量

一个例子,看下面的代码有个小问题

class MyObject(object):
    x = 1
    def __init__(self):
        objectNum = 99
    def changeNum(self, anotherNum):
        self.objectNum = anotherNum
    def showNum(self):
        print("self.num = ", self.objectNum)

什么问题呢,看似构造函数__init__中的变量object在实例化对象的时候会自动创建并初始化为99,其实不然,这里用一个小的测试代码就可以发现问题。

obj = MyObject()
obj.showNum()
Traceback (most recent call last):
  File "class.py", line 24, in <module>
    obj.showNum()
  File "class.py", line 20, in showNum
    print("self.num = ", self.objectNum)
AttributeError: 'MyObject' object has no attribute 'objectNum'

报错了,提示实例化对象MyObject并没有objectNum这个普通成员变量,为什么呢?

问题就在于,在Python中,类的成员变量必须使用self.propertName进行声明,这样才能完成创建,因为self的含义就是代表实例对象;

在这个类中,objectNum和self.objectNum就是两个完全不同的东西:

定义在__init__函数中的变量objectNum在这里是一个局部变量,不是类变量

接下来我们可以再写一段代码,调用changNum()方法,来生成这个成员变量self.objectNum:

obj = MyObject()
obj.changeNum(10)
obj.showNum()
>>> self.num =  10

能看到成功返回结果,

由于在changeNum()方法中,有self.objectNum = anotherNum的赋值,而__init__中,没有创建类普通成员变量self.objectNum, 而是创建了一个临时变量objectNum,所以在这里

虽然changeNum()没有被自动调用(因为不是__init__()函数),但是其实充当了创建类成员变量和初始化的作用, 但是python并不会在创建新的实例化对象的时候自动调用它。

所以通过实验得到3个结论:

  • 1.python中的"构造函数"非常的自由,如果不考虑自动调用,任何类方法都可以去创建类成员变量:
class ExampleClass:
def createObjectProperty(self, value):
self.newObjectProperty = value

如上面的代码,这里声明一个类方法,传入参数self 和 value,调用这个方法,就可以生成一个普通成员变量newObjectProperty,并对其赋初值value

  • 2.如果想要找到真正意义上的成员变量,那么只需要在__init__(self)中声明self.objectProperty即可
  • 3.python中的self不能隐式调用,如果你不想生成一个临时变量而是创建一个类成员变量,那么就应该使用self.variableName
'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
class MyObject(object):
    x = 1
    def __init__(self):
        self.objectNum = 99
    def changeNum(self, anotherNum):
        self.objectNum = anotherNum
    def showNum(self):
        print("self.num = ", self.objectNum)
obj = MyObject()
# obj.changeNum(10)
obj.showNum()
>>>self.num =  99

知道了成员变量的问题之后,再来讨论一下类变量

class MyObject(object):
    x = 1
    def __init__(self):
        self.objectNum = 99
    def changeNum(self, anotherNum):
        self.objectNum = anotherNum
    def showNum(self):
        print("self.num = ", self.objectNum)
    
obj = MyObject()
  
print(MyObject.x)
>>> 1

在声明类T的时候,我们在所有的方法之外(但是仍在类的作用域中声明了一个变量classNum),从命名的角度来看,我们希望这是一个类变量,但我们不希望这次又是一个成员变量,测试发现它确实可以由类名直接访问再试一下能否修改:

MyObject.x = 100
print(MyObject.x)
>>> 100

发现可以修改
下面我们验证一下其是否能被所有实例化对象访问和修改,并且是否具有全局性。

'''
遇到问题没人解答?小编创建了一个Python学习交流QQ群:531509025
寻找有志同道合的小伙伴,互帮互助,群里还有不错的视频学习教程和PDF电子书!
'''
t1 = MyObject()
print(t1.x)
>>> 1
t2 = MyObject()
print(t2.x)
>>> 1
MyObject.x = 1000
print(t1.x)
>>> 1000
print(t2.x)
>>> 1000
t1.x = 2000
print(t2.x)
>>>1000
print(t1.x)
>>>2000
print(MyObject.x)
>>>1000

从以上结果看出类名.类变量名修改其值会导致实例化对象的值全部被改变,但是用实例化对象名.类变量名修改其值,就仅仅改变自己,不会真的改变类变量的数值。
我们来检查一下内存,看一段代码:

t2 = MyObject()
t1 = MyObject()
 
 
print(MyObject.x is t1.x)
>>>True
print(MyObject.x is t2.x)
>>>True
print(t2.x is t1.x)
>>>True
---------------------------------------
t2 = MyObject()
t1 = MyObject()
 
t2.x = 10
print(MyObject.x is t1.x)
>>>True
print(MyObject.x is t2.x)
>>>False
print(t2.x is t1.x)
>>>False
--------------------------------------
t2 = MyObject()
t1 = MyObject()
 
MyObject.x = 100
t2.x = 10
print(MyObject.x is t1.x)
>>>True
print(MyObject.x is t2.x)
>>>False
print(t2.x is t1.x)
>>>False

看得出来在最开始的时候MyObject.x和实例化对象t1.x与t2.x内存是同一处的,但当直接修改了实例化对象t2.x的数值后t2.x内存的数值便与其他两个不同,所以直接修改实例化对象的数值会指向新的内存空间,并且不受类变量改变而改变。
总结:
一个类=类变量(可以没有)+构造函数(必须有,没有的话默认调用)+成员函数(自己定义,可以没有)

构造函数中定义了类的成员变量,类的成员变量一定是在构造函数中以self.开头的变量!

成员函数中可以调用成员变量和类变量!成员函数的形参在类的实例调用该函数时传递,成员函数的局部变量在该成员函数内部定义。调用成员函数和调用普通函数一样,只是成员函数由该函数对应的类调用,即需要写成xxxx.func()而不是直接使用func()!

相关文章

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,...

爬虫基本原理

爬虫基本原理 一、爬虫是什么? 百度百科和维基百科对网络爬虫的定义:简单来说爬虫就是抓取目标网站内容的工具,一般是根据定义的行...

Django 函数和方法的区别

函数和方法的区别 1、函数要手动传self,方法不用传 2、如果是一个函数,用类名去调用,如果是一个方法...

Django 知识补漏单例模式

单例模式:(说白了就是)创建一个类的实例。在 Python 中,我们可以用多种方法来实现单例模式&#x...

Django基础知识MTV

Django简介 Django是使用Python编写的一个开源Web框架。可以用它来快速搭建一个高性能的网站。 Django也是一个MVC框架。但是在Dj...

Python mysql 索引原理与慢查询优化

一 介绍 为何要有索引? 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,...

发表评论

访客

看不清,换一张

◎欢迎参与讨论,请在这里发表您的看法和观点。