假设我们要处理学生的成绩表,为了表示一个学生的成绩:
面向过程的方法:用一个dict表示,在进行函数调用
std1 = { 'name': 'Michael', 'score': 98 } std2 = { 'name': 'Bob', 'score': 81 } #而处理学生成绩可以通过函数实现,比如打印学生的成绩: def print_score(std): print('%s: %s' % (std['name'], std['score'])) print_score(std2) print_score(std1)
Bob: 81 Michael: 98
面向对象的方法:创建出这个学生对应的对象,给对象发一个print_score消息,让对象自己把自己的数据打印出来。
class Student(object): # 定义初始化方法,创建实例对象自动调用,对属性赋值 def __init__(self, name, score): self.name = name self.score = score def print_score(self): print('%s: %s' % (self.name, self.score)) hongenjie = Student('洪恩节',100) lisa = Student('Lisa Simpson', 87) hongenjie.print_score() lisa.print_score()
洪恩节: 100 Lisa Simpson: 87
面向对象和面向程序的区别:
如果采用面向对象的程序设计思想,我们首选思考的不是程序的执行流程,
而是Student这种数据类型应该被视为一个对象,这个对象拥有name和score这两个属性。
如果要打印一个学生的成绩,首先必须创建出这个学生对应的对象,
给对象发一个print_score消息,让对象自己把自己的数据打印出来,给对象发消息实际上就是调用对象对应的关联函数,我们称之为对象的方法
面向对象的设计思想是抽象出Class,根据类创建实例,面向对象的抽象程度又比函数要高,因为一个Class既包含数据,又包含操作数据的方法
创建对象和定义类:
经典类:class Cat:
# 定义一个猫类 class Cat: # 定义猫的属性(color,legs) color = '黄色' legs = 4 # 定义猫的方法(eat,sleep) def eat(self): print('猫吃鱼') def sleep(self): print('猫睡觉') my_cat=Cat()#创建实例my_cat my_cat.eat()#访问方法 my_cat.sleep()#访问方法 print(Cat.color)#访问属性 print(Cat.legs)#访问属性
猫吃鱼 猫睡觉 黄色 4
新式类:class Car(object):
# 定义一个车类 class Car(object): # 属性:颜色,四个轮子 color = '白色' wheel = 4 # 行为:跑,鸣笛 def move(self): print('车子在移动') def whistle(self): print('车子在鸣笛') my_car=Car() my_car.move() my_car.whistle() print(Car.color) print(Car.wheel)
车子在移动 车子在鸣笛 白色 4
实例的作用:
当创建实例对象的时候,对象自动拥有方法,对象就可以直接调用方法(属性也一样)。
对象属性的添加和获取:
属性的添加语法格式:对象名.属性名 = 新的值
属性的获取语法格式:print(对象名.属性名)
对象调用的方法语法格式:对象名.方法名()
#定义一个关于person的类 class Person(object):#属性:身高,体重,年龄#行为:吃饭 睡觉 喝水 #定义普通的方法 def eat(self): print('人都要吃饭') def sleep(self): print('人都要休息') def drink(self): print('水是生命之源') #通过Person创建一个实例对象p p = Person() #直接添加属性 p.name = '张三' p.age = 20 p.height=180 p.weight=60 #获取属性 print(p.name) print(p.age) print(p.height) print(p.weight) #对象调用方法 p.eat() p.sleep() p.drink()
张三 20 180 60 人都要吃饭 人都要休息 水是生命之源
不仅如此,我们还可以创建新的对象p2,它可以和p有不同的属性,但他们含有相同的方法。
#通过Person创建一个对象p2 p2 = Person() #直接添加属性 p2.name = '李四' p2.age = 30 p2.sex = '男' #获取属性 print(p2.name,p2.age,p2.sex) #对象调用方法 p2.eat() p2.sleep() p2.drink()
李四 30 男 人都要吃饭 人都要休息 水是生命之源
类中的函数称为方法,我们在python前面的基础学习中,学到的任何函数都适用于方法,唯一的区别在于调用方法的方式不同。
init()方法的使用:
init(self,属性1,属性2)是一个特殊的方法,每当我们所创建的类产生新的示例的时候,python都会自动运行它,在这个运行方法的名称中,开头和末尾均有两个下划线,这是避免与普通方法名称产生矛盾,因此必须确保__init__(self,属性1,属性2)的两边都有两个下划线,否则当你使用类来创建示例时,将不会自动调用这个方法,进而引发难以发现的错误。
举例:
#定义一个汽车类 class Car(object): def __init__(self,color,wheelNum): self.color = color self.wheelNum = wheelNum # 定义一个普通方法 def move(self): print('车子在移动') # 定义一个普通方法 def whistle(self): print('车子在鸣笛') #创建一个对象bmw bmw = Car('红色',4) #调用类里面普通方法 bmw.move() bmw.whistle() print(bmw.color) print(bmw.wheelNum)
细心的小伙伴可能都发现了为什么__init_()属性里面包含了self.
为何必须在方法定义中包含形参self呢?
因为python调用这个方法创建示例时,将自动传入实参self,每个与示例相关联的方法调用都自动传递实参self,它是一个指向示例本身的引用,让示例能够访问类中的属性和方法。
属性我们可以在编写__init__()的时候将属性的值指定,也可以是通过实参来传递属性的值。
指定属性的值:
def __init__(self,color,wheelNum): self.color = '黑色' self.wheelNum = 4
不指定属性的值:
def __init__(self,color,wheelNum): self.color = color self.wheelNum = wheelNum
那么这两种有什么区别?
区别在于如果指定了属性的值,那么在调用属性的时候,即使实参传递了和指定值不相同的,输出结果依然为指定值。
举例:
def __init__(self,color,wheelNum): self.color = '黑色' self.wheelNum = 4 bmw = Car('红色',4) print(bmw.color) print(bmw.wheelNum)
黑色 4
难道属性的值就不能被改变吗?当然不是
下面我们对上面例子中的属性进行修改:
bmw.color="yellow" bmw.wheelNum=10
直接修改 对象名.属性名 = 新值
完整代码:
class Car(object): def __init__(self,color,wheelNum): self.color = '黑色' self.wheelNum = 4 def move(self): print('车子在移动') def whistle(self): print('车子在鸣笛') bmw = Car('红色',4) bmw.move() bmw.whistle() bmw.color="yellow" bmw.wheelNum=10 print(bmw.color) print(bmw.wheelNum)
这次的颜色和车轮数很好的被修改了
车子在移动 车子在鸣笛 yellow 10
当实例化类得到具体对象的时候,会自动调用__init__()方法,对类的属性进行初始化赋值,创建对象的时候,自动拥有类里面属性
__del__析构方法:
import time #定义一个动物类 class Animal(object): #定义初始化方法 创建对象时候自动调用 def __init__(self,name): print('__init__方法被调用') self.name = name #定义普通方法 def walk(self): print('动物会跑') #定义一个析构方法 删除对象的时候自动调用 def __del__(self): print('__del__方法被调用') print('%s对象被干掉'%(self.name)) #创建一个dog对象 dog = Animal('哈皮狗') dog.walk()
__init__方法被调用 动物会跑 __del__方法被调用 哈皮狗对象被干掉
通过输出结果我们发现,为什么__del__()也被调用了呢?
原因是:析构函数__del__(),使用del删除实例时才触发,否则等到文件执行完毕进行回收时才触发。
修改之后:
import time # 定义一个动物类 class Animal(object): #定义初始化方法 创建对象时候自动调用 def __init__(self,name): print('__init__方法被调用') self.name = name #定义普通方法 def walk(self): print('动物会跑') #定义一个析构方法 删除对象的时候自动调用 def __del__(self): print('__del__方法被调用') print('%s对象被干掉'%(self.name)) #创建一个dog对象 dog = Animal('哈皮狗') dog.walk() # 手动销毁对象,再测试对象调用类中方法报错 del dog dog.walk()
此时编译器告诉我们dog没有被定义,事实上是因为使用del将其删除了
上面代码中,dog只被引用了一次,因此使用一次del,该对象就被真正的删除了,那么如果是下面这种情况呢?
cat被引用了3次,如果我们去用和面一样的方法,会成功实现对象的删除吗?
cat=Animal("波斯猫") cat2=cat cat3=cat
删除cat,去调用cat2和cat3
class Animal(object): def __init__(self,name): print('__init__方法被调用') self.name = name def walk(self): print('动物会跑') def __del__(self): print('__del__方法被调用') print('%s对象被干掉'%(self.name)) cat=Animal("波斯猫") cat2=cat cat3=cat del cat cat3.walk() cat2.walk()
__init__方法被调用 动物会跑 动物会跑 __del__方法被调用 波斯猫对象被干掉
cat2和cat3成功被调用了,难道是对象没被删除?下面我们调用一下cat.
class Animal(object): def __init__(self,name): print('__init__方法被调用') self.name = name def walk(self): print('动物会跑') def __del__(self): print('__del__方法被调用') print('%s对象被干掉'%(self.name)) cat=Animal("波斯猫") cat2=cat cat3=cat del cat cat.walk()
Traceback (most recent call last): File "C:/Users/Lenovo/PycharmProjects/pythonProject4/main.py", line 295, in <module> cat.walk() NameError: name 'cat' is not defined __init__方法被调用 __del__方法被调用 波斯猫对象被干掉
通过结果我们可得出如下结论:
在本例中,cat被删除,但不影响cat2/cat3的调用,其他情况亦是如此。
变量保存了对象的引用,对象的引用计数加1,使用__del__()删除对象的时候,对象的引用计数-1,对象被删除,如果对象的引用计数不是1,每删除一次对象的引用计数减1,直到引用计数为0时候,该对象才被真正的删除