类属性指的是类对象所绑定的属性
绑定类属性(给类对象绑定属性)的方式有两种:
- 在类对象的内部(方法外),语法格式:属性名 = 属性值
- 在类对象的外部,Python是动态语言,所以,在类对象创建之后,可以对齐动态的绑定属性。语法格式:类对象.属性名 = 属性值 如果指定名称的类属性已经存在,则是对类属性进行修改
访问类属性的方式有两种:
- 在类对象的内部(方法中),语法格式:类对象.属性名
- 在类对象的外部,语法格式:类对象.属性名 或 实例对象.属性名 类对象的所有实例对象都有一个指向类对象的指针,所以,类对象的所有实例对象都可以访问类属性
之所以添加前缀“类对象”,是为了表明类属性被哪个类对象所绑定
class MyClass(object):
# 在类对象的内部(方法外)绑定类属性
ca1 = 18
def do_sth(self):
# 在类对象的内部(方法中)访问类属性
print(MyClass.ca1)
def do_another(self):
# 在类对象的内部(方法中)访问类属性
print(MyClass.ca2)
mc = MyClass()
# 在类对象的外部调用方法,使得在类对象的内部(方法中)访问类属性
mc.do_sth() # 18
# 在类对象的外部通过类对象访问类属性,在类对象的外部通过实例对象访问类属性
print(MyClass.ca1, mc.ca1) # 18 18
# 在类对象的外部绑定类属性
MyClass.ca2 = 56
# 在类对象的外部通过类对象访问类属性
print(MyClass.ca2) # 56
# 在类对象的外部通过实例对象访问类属性
print(mc.ca2) # 56
# 在类对象的外部修改绑定的类属性值
MyClass.ca2 = 73
print(MyClass.ca2) # 73
print(mc.ca2) # 73
# 在类对象的外部调用方法,使得在类对象的内部访问类属性
mc.do_another() # 73
访问实例属性和类属性,都可以通过 “实例对象.属性名” 的方式。当通过这种方式来访问属性时,会先查找指定的实例对象中有没有指定名称的实例属性,如果没有再查找对应的类对象中有没有指定名称的类属性。所以当通过这种方式访问属性时,如果实例属性和类属性同名时,返回结果时实例属性。
当通过 “实例对象.属性名 = 属性值” 的方式绑定属性时,这里属性只表示实例属性(因为类属性没有这样的绑定方式),所以只会查找指定的实例对象有没有绑定指定名称的实例属性,如果没有则进行绑定,如果已经绑定了,则对属性值进行修改
class Person(object):
age = 18
p = Person()
# 在实例对象 p 中没有找到名为 age 的实例属性,然后在类对象 Person 中找到了该属性
print(p.age) # 18
# 直接打印名为 age 的类属性
print(Person.age) # 18
# 在查找实例对象时不存在名为 age 的属性,给实例对象 p 绑定实例属性
p.age = 19
# 如果实例属性和类属性同名时,返回结果时实例属性
print(p.age) # 19
# 直接打印名为 age 的类属性
print(Person.age) # 18
# 删除实例对象 p 绑定的实例属性
del p.age
# 在实例对象 p 中没有找到名为 age 的实例属性,然后在类对象 Person 中找到了该属性
print(p.age) # 18
p1 = Person()
p2 = Person()
# p1.age += 2 等价于 p1.age = p1.age + 2
# 等号右边是属性访问,整个赋值语句是实例属性的绑定
p1.age += 2
# 直接打印名为 age 的类属性
print(Person.age) # 18
# 如果实例属性和类属性同名时,返回结果时实例属性
print(p1.age) # 20
# 在实例对象 p2 中没有找到名为 age 的实例属性,然后在类对象 Person 中找到了该属性
print(p2.age) # 18
# Person.age += 3 等价于 Person.age = Person.age + 3
# 等号右边是属性访问,整个赋值语句是类属性的绑定
Person.age += 3
# 直接打印名为 age 的类属性
print(Person.age) # 21
# 如果实例属性和类属性同名时,返回结果时实例属性
print(p1.age) # 20
# 在实例对象 p2 中没有找到名为 age 的实例属性,然后在类对象 Person 中找到了该属性
print(p2.age) # 21