python中类变量与成员变量的使用注意点

本文探讨了Python中类变量与实例变量的区别和使用注意事项,通过示例代码解释了它们如何影响对象状态。类变量是所有实例共享的,而实例变量是对象独有的。当类变量为可变类型如列表时,直接修改会影响所有实例,而通过实例修改则会产生新的副本。为了避免混淆,建议在初始化时明确实例化变量。关键词包括Python、类变量、实例变量、数据共享、对象状态。
摘要由CSDN通过智能技术生成

python 的类中主要会使用的两种变量:类变量与成员变量。类变量是类所有实例化对象共有的,而成员变量是每个实例化对象自身特有的。下面这篇文章主要给大家介绍了在python中类变量与成员变量的一些使用注意点,需要的朋友可以参考借鉴,下面来一起看看吧。

前言

最近在用python,发现一个bug(实际上是理解不到位),就是同由一个类生成的两个实例之间的数据竟然会相互影响,这让我非常不解。后来联想到java的类有类变量也有实例变量,因此翻阅了相关资料,发现python也有类似的类变量和实例变量,下面来看看详细的介绍。

看下面的示例代码:

1

2

3

4

class A:

 x = 0

 def __init__(self):

 self.y = 0

x就是类变量,y就是实例变量。

原则上是没有错的,但是实际用的时候就发现一些恶心的问题(也就是我找了三天的bug)。。。比如下面的代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

class A:

 x = []

 y = 0

 def __init__(self):

 pass

 def add(self):

 self.x.append('1')

 self.y+=1

a=A()

print a.x,a.y

print A.x,A.y

a.add()

print a.x,a.y

print A.x,A.y

b=A()

print b.x,b.y

print A.x,A.y

这里很明显x和y都是类变量,add的作用是分别对x和y做出修改。然后构造一个实例a,对实例a的值进行修改,最后构造实例b。

本以为这个结果是显而易见的,然而他输出的结果却是:

1

2

3

4

5

6

[] 0

[] 0

['1'] 1

['1'] 0

['1'] 0

['1'] 0

问题在哪?明明x和y都是类变量,在第二组print中为什么a.x和b.x一样,但是a.y和b.y就是不一样呢?

想了半天悟了一个道理。。。就是对于python来说,类变量的确是所有类共有的东西。但是那是在我们用的同一个引用的情况下,比如对于[]对象的append方法就是公用一个类变量了;但是对于赋值语句来说,如果在类中对类变量使用了赋值语句,那么python就会生成一个该对象的副本,以后的操作都是基于这个副本而不会对原来的类对象造成影响。这样就解释的通上面的现象了。

那么为了杜绝自己忘记类变量和实例变量的区别导致本不想公用变量的时候公用了变量,最好的办法就是在每个类中使用变量的时候重新初始化一下,这样就不会导致意外了。

 

相比于C++语言,每个类可以有类成员变量,也可以有对象的成员变量,类成员变量需要用static修饰;在python中,也有两种变量

python中类成员变量是不用self修饰的,也就是说对象成员变量需要用self.来修饰,具体可以看代码。

class person:
    population = 0
 
    def __init__(self,name):
        self.name=name
        self.population+=1
        print self.population
        print person.population
 
 
peter = person('peter')
print peter.population
print person.population
line2: population = 0,这个是类的变量。无论在哪里调用,都需要用person.population来引用
line6: self.population +=1,这个地方调用的就是对象的变量。对象的变量会在类的变量的基础上执行加一,这是在对象变量没有被赋值的前提下。

这段代码的执行结果是

1

0

1

0

还会有一个全局的变量来干扰
class person:
    population = 0
 
    def __init__(self,name):
        self.name=name
        self.population+=1
        print self.population
        print person.population
        print population
 
population = 2
peter = person('peter')
print peter.population
print person.population
print population

代码的运行结果是
1

0

2

1

0

2

===================================================================================

Python3 之 类属性与实例属性

1、类属性与实例属性

  类属性就相当与全局变量,实例对象共有的属性实例对象的属性为实例对象自己私有

  类属性就是类对象(Tool)所拥有的属性,它被所有类对象的实例对象(实例方法)所共有,在内存中只存在一个副本,这个和C++中类的静态成员变量有点类似。对于公有的类属性,在类外可以通过类对象和实例对象访问。

2、实例:类属性

 

 1 class People(object):
 2     name = 'Jack'  #类属性(公有)
 3     __age = 12     #类属性(私有)
 4 
 5 p = People()    #创建实例对象
 6 
 7 print(p.name)           #通过实例对象,打印类属性:name
 8 print(People.name)      #通过类对象,打印类属性:name
 9 print(p.__age)            #错误,不能在类外通过实例对象访问私有的类属性
10 print(People.__age)        #错误,不能在类外通过类对象访问私有的类属性
11 
12 #结果如下:
13 # Jack
14 # Jack
15 # AttributeError: 'People' object has no attribute '__age'
16 # AttributeError: type object 'People' has no attribute '__age'

 

3、实例:实例属性(对象属性)

 

 1 class People(object):
 2     address = '山东'  # 类属性
 3     def __init__(self):
 4         self.name = 'xiaowang'  # 实例属性
 5         self.age = 20  # 实例属性
 6 
 7 p = People()    #创建实例对象
 8 p.age = 12  # 通过实例对象调用实例属性,更改实例属性值
 9 print(p.address)  # 通过实例对象调用类属性,并打印
10 print(p.name)  # 通过实例对象调用实例属性,并打印
11 print(p.age)  # 通过实例对象调用实例属性,并打印
12 
13 #结果:
14 # 山东
15 # xiaowang
16 # 12
17 
18 print(People.address)  # 通过类对象调用类属性,并打印
19 print(People.name)  # 错误(程序会报错),通过类对象调用实例属性,并打印
20 print(People.age)  # 错误(程序会报错),通过类对象调用实例属性,并打印
21 
22 #结果:
23 # 山东
24 # AttributeError: type object 'People' has no attribute 'name'
25 # AttributeError: type object 'People' has no attribute 'age'

 

4、通过实例(对象)去修改类属性

 

 1 class People(object):
 2     country = 'china'  # 类属性
 3 
 4 print(People.country)   #china
 5 p = People()
 6 print(p.country)    #china
 7 p.country = 'japan' 
 8 print(p.country)  # 实例属性会屏蔽掉同名的类属性:japan
 9 print(People.country)   #china
10 del p.country  # 删除实例属性
11 print(p.country)    #实例属性被删除后,再调用同名称的属性,会调用类属性:china

 

小结:

  如果需要在类外修改类属性必须通过类对象去引用然后进行修改。如果通过实例对象去引用,会产生一个同名的实例属性,这种方式修改的是实例属性,不会影响到类属性,并且之后如果通过实例对象去引用该名称的属性,实例属性会强制屏蔽掉类属性,即引用的是实例属性,除非删除了该实例属性

//========================================

从根本上解决问题就是类属性和对象属性不要重名,重名以后会增加理解负担,特别是刚学习的时候。

真正理解,不管是类属性还是对象属性,都是在赋值操作(=)后才会参数作用,没有赋值就不存在;

在通过对象使用属性时,其搜索路径是:先对象后类。这就意味着重名以后可能屏蔽的问题,还有可能对象属性和类属性使用混乱的问题。

混乱的根源是python的变量不用预先定义,赋值才真正完成定义;虽然灵活,带也带来了混乱。

在类中,最好指定好规则,不能随便增减属性。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值