类的理解
1.1 类的介绍
类的定义:
class CocaCola:
formula = ['caffeine','sugar','water','soda']
使用 class 来定义一个类,就如同创建函数时使用的 def 定义一个函数一样简单。如上你可以看到定义了名为 CocaCola 的类,接着在缩进的地方有一个装载着列表的变量的 formula,这个在类里面定义的变量就是类的变量,而类的变量有一个专有的术语,我们称之为类的属性。
类的属性:
- 类变量
- 方法
①类的实例化:
coke_for_me = CocaCola()
coke_for_you = CocaCola()
②类变量属性的引用:CocaCola.formula、coke_for_me.formula
类方法的使用:
class CocaCola:
formula = ['caffeine','sugar','water','soda']
def drink(self):
print('Energy!')
coke = CocaCola()
coke.drink()
结果:
Energy!
1.2 self
我想很多人会有关注到这个奇怪的地方——似乎没有派上任何用场的self参数。我们来说明下原理,其实很简单,我们修改下上面的代码:
class CocaCola:
formula = ['caffeine','sugar','water','soda']
def drink(coke): # 把self改为coke
print('Energy!')
coke = CocaCola()
coke.drink()
结果:
Energy!
这个参数其实就是被创建的实例本身。也就是将一个个对象作为参数放入函数括号内,再进一步说,一旦一个类被实例化,那么我们其实可以使用和与我们使用函数相似的方式:
coke = CocaCola
coke.drink() == CocaCola.drink(coke) #左右两边的写法完全一致
被实例化的对象会被编译器默默地传入后面方法的括号中,作为第一个参数。上面两个方法是一样的,但我们更多地会写成前面那种形式。其实self这个参数名称是可以随意修改的(编译器并不会因此而报错)。
和函数一样,类的方法也能有属于自己的参数,如下:
class CocaCola:
formula = ['caffeine','sugar','water','soda']
def drink(self,how_much):
if how_much == 'a sip':
print('Cool~')
elif how_much == 'whole bottle’:
print('Headache!')
ice_coke = CocaCola()
ice_coke.drink('a sip')
结果:
Cool~
1.3 魔术方法
Python 的类中存在一些方法,被称为「魔术方法」,init()就是其中之一。
class CocaCola():
formula = ['caffeine','sugar','water','soda']
def __init__(self):
self.local_logo = '可口可乐'
def drink(self):
print('Energy!')
coke = CocaCola()
print(coke.local_logo)
作用:在创建实例之前,它做了很多事情。说直白点,意味着即使你在创建实例的时候不去引用 init_() 方法,其中的语句也会先被自动的执行。这给类的使用提供了极大的灵活性。
class CocaCola:
formula = ['caffeine','sugar','water','soda']
def __init__(self,logo_name):
self.local_logo = logo_name
def drink(self):
print('Energy!')
coke = CocaCola('ݢݗݢԔ')
coke.local_logo
>>> 可口可乐
有过面向对象编程经验很好理解了,也就是很多面向对象语言中的「构造函数」。
1.4 类的继承
如下代码:
class CaffeineFree(CocaCola):
caffeine = 0
ingredients = [
'High Fructose Corn Syrup',
'Carbonated Water',
'Phosphoric Acid',
'Natural Flavors',
'Caramel Color',
]
coke_a = CaffeineFree('Cocacola-FREE')
coke_a.drink()
表示 CaffeineFree 继承了 CocaCola 类。
类中的变量和方法可以被子类继承,但如需有特殊的改动也可以进行覆盖。
Q1:类属性如果被重新赋值,是否会影响到类属性的引用?
class TestA():
attr = 1
obj_a = TestA()
TestA.attr = 24
print(obj_a.attr)
>>> 结果:24
A1:会影响。
Q2:实例属性如果被重新赋值,是否会影响到类属性的引用?
class TestA:
attr = 1
obj_a = TestA()
obj_b = TestA()
obj_a.attr = 42
print(obj_b.attr)
>>> 结果:1
A2:不会影响。
Q3:类属性实例属性具有相同的名称,那么.后面引用的将会是什么?
class TestA():
attr =1
def __init__(self):
self.attr = 24
obj_a = TestA()
print(obj_a.attr)
>>> 结果:24
A3:类属性赋值后的值。
总结:如图所示,Python 中属性的引用机制是自外而内的,当你创建了一个实例之后,准备开始引用属性,这时候编译器会先搜索该实例是否拥有该属性,如果有,则引用;如果没有,将搜索这个实例所属的类是否有这个属性,如果有,则引用,没有那就只能报错了。