8.6 静态属性和静态函数

一.静态属性
对象的属性是每个对象都有自己的一份,例如学生类的学号、姓名,每一个学生对象,都有不同的学号姓名,这是很自然的。我们把这些称为对象的属性,前面已经讲过。 但是有一种属性,是所有对象共享的,这种叫做静态属性,或者类属性,它们无需任何对象就能存在。num这个属性是所有对象共享的,而使用的话,是这样的:
class Mobile:
    num= 100
    def __init__(self, name, mon):
        self.name = name
        self.mon = mon
mobile1 = Mobile("Samsung""Galaxy")
Mobile.num-= 1
mobile2 = Mobile("Apple""iPhone")
Mobile.num -= 1
Mobile.num -= 1
print(Mobile.num) #打印97,100已经自减了3次
mobile1.num+=1 #通过对象,num变成了非静态属性,它已经变成了98
print(Mobile.num) #这个num仍然是静态属性,此时它的值还是97
print(mobile1.num)#这个num属于对象mobile1,它的值是98
print(mobile2.num)#这个num属于对象mobile2,它的值还是97
Mobile.num -= 1
print(mobile1.num)  # 这个num属于对象mobile1,它的值是98
print(mobile2.num)  # 这个num属于静态熟悉,因为没有通过mobile2修改过num值,它的值是96

mobile3 = Mobile("Huawei","Mate")
print(Mobile.num)
注意这条语句Mobile.num -=1,表明了num这个属性完全不需要任何对象,就能存在,事实上,"类名.属性"访问的就是静态属性;如果使用“对象.属性”的方式修改了这个属性值,那么这个属性就不是静态属性。而且用对象访问的属性会永久转化成非静态属性。
例如学生类,有一个属性是学校名称,这是所有学生对象都相同的,如果学校改名了,所有学生对象的学校名都改了。 修改这类属性,不需要通过对象:
Student.school="清华大学"
二.静态方法
和静态属性类似的,是静态方法。 静态方法,一种不需要对象就能调用的方法。这是一个math类方法的调用,计算x的sin值:
import math as math
x=0.5
m=math.sin(x)
print(m)
最终打印0.479425538604,也即是0.5的sin值。函数sin的调用,不需要math对象,它直接用类。
事实上,math类全部都是静态方法,它就是一个提供了数学函数的一个集合体。并不需要创建一个对象。 
1.在同一个类内部,任何方法(静态或者非静态)都可以调用静态方法,都可以使用静态属性。
2.在同一个类内部,静态方法不可以调用非静态方法,不可以使用非静态属性。
关于第二点,可以这样理解:静态方法调用不需要对象,所以不能使用对象才有的属性和方法(也就是非静态的属性和方法)。这也可以解释静态方法里面不能出现self关键字。
对象是类的一个实例,每个对象都有独立的属性值来描述自身,除了静态属性外,其余的属性在每个对象之间是相互独立的。类和对象的关系,就是抽象和具体的关系。马是一个类,这匹马就是一个对象,那匹马也是。

staticmethod修饰的方法,都是不依赖对象而存在的。并且是对象都共用的。例如下面的例子welcome,它没有self参数(也不能有self):
class Mobile:
    NUM = 100
    def __init__(self, name, mon):
        self.name = name
        self.mon = mon
        self.n = 100
    @staticmethod
    def welcome(name):
        print("欢迎你,{},数量是{}".format(name,Mobile.NUM))
Mobile.welcome("good")