Python学习笔记——类属性和实例属性

时间:2021-08-29 10:41:47

Python学习笔记——类属性和实例属性的区别


访问特性

首先我们以Test类为例:

class Test(object):
#类属性
a = 100
def __init__(self, b):
#实例属性
self.b = b
t = Test(100)

#通过实例化对象访问 类属性

print("t.a = %d"%t.a)

#通过类名访问 类属性

print("Test.a = %d"%Test.a)

#通过实例化对象访问 实例属性

print("t.b = %d"%t.b)

#通过类名访问 实例属性

print("Test.b = %d"Test.b) #error 无法通过(类名.属性名)的方式访问实例属性

从上面这里例子我们可以知道:
对于类属性我们可以通过类名及实例对象去访问,即:
类名.类属性,
实例.类属性
两种方式访问。


属性

  
1:实例属性:

在__init__(self,…)中初始化

内部调用时都需要加上self.

外部调用时用实例化对象.属性名

2:类属性:

在__init__()外初始化

在内部用类名.类属性名调用

外部既可以用类名.类属性名又可以用实例化对象.类属性名来调用

3:私有属性:

1):单下划线_开头:只是告诉别人这是私有属性,外部依然可以访问更改

2):双下划线__开头:外部不可通过实例化对象.属性名来访问或者更改
   
实际将其转化为了_类名_属性名,只是在内部将变量名修改了,我们仍让可以通过._类名_属性名访问

如图:
Python学习笔记——类属性和实例属性


类属性的修改

类属性是所有实例共有的属性即静态属性,类似JAVA/C++中static,但是仅仅只是类似。

我们知道在JAVA中所有类对象共享static内数据的内存,也就是说通过修改static中的值会导致其他对象中static值

同样被修改,但在Python中并不是这样。我们看下面这个例子:

class Test(object):
a = 100
def __init__(self):
pass
t1 = Test()
t2 = Test()
#1.通过实例对象t1修改类属性的值
print("修改前:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))
t1.a += 100
print("修改后:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))

output:
>>>修改前:t1.a = 100, t2.a = 100, Test.a = 100
>>>修改后:t1.a = 200, t2.a = 100, Test.a = 100

很明显,我们通过实例对象修改类属性的值,并没有在全局范围奏效,只是对于t1中的类属性有所不同。

那接下来通过类名修改类属性看看会有什么结果,

class Test(object):
a = 100
def __init__(self):
pass
t1 = Test()
t2 = Test()
#1.通过类名修改类属性的值
print("修改前:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))
Test.a += 100
print("修改后:t1.a = %d, t2.a = %d, Test.a = %d"%(t1.a, t2.a, Test.a))

output:
>>>修改前:t1.a = 100, t2.a = 100, Test.a = 100
>>>修改后:t1.a = 200, t2.a = 200, Test.a = 200

通过类名修改的类属性,在全局范围奏效,也就是说确实修改了类属性的值,在实例对象中我们看到a的值全部被

修改。实际上这就是类属性的持久性从这个例子看,实例对象确实和类对象共有相同的类属性,那么为什么通过实例对象无法在全局范围修改

呢?

实际上,这就是关于作用域的问题,看下面这张图
Python学习笔记——类属性和实例属性

也就是说,实例对象仅能访问类属性,即只能get不能set。我们怎么证明这一点呢?

我们知道dir()是Python中的内建函数

通过调用dir()函数显示出对象或者类的所有属性

我们通过输出__dict__属性观察变化,类输出的是全局的函数,变量等信息。

对象输出的只是对象拥有的普通变量。这样可以其他信息的干扰。

class Test():
a = 100
def __init__(self):
pass
t1 = Test()
#打印修改前的类和实例对象中的变量,函数
print(Test.__dict__)
print("\n\n\n")
print(t1.__dict__)
t1.a += 100
#通过修改实例对象修改a的值吗,并打印类和实例对象中的变量,函数
print(Test.__dict__)
print("\n\n\n")
print(t1.__dict__)
print("\n\n\n")

output如图:
Python学习笔记——类属性和实例属性

确实,我们无法通过实例对象对类属性进行修改,真的是这样吗?
接下来看下面这段代码,

  class Test(object):
dict_a = {1:"leo"}
def __init__(self):
pass
t1 = Test()
print("--------Before--------")
print(t1.__dict__)
print(Test.__dict__)
t1.dict_a[2] = "mike"
print("--------After-------")
print(t1.__dict__)
print(Test.__dict__)

Output如图:
Python学习笔记——类属性和实例属性

我们发现,通过实例对象添加的键值对 2:”mike”并没有创建实例属性,这是因为字典为可变类型,而数

字是不可变类型,因此无法通过这种方式修改。所以在实际开发中应该避免通过实例对象去修改类属

性。