面向过程与面向对象
我们大概已经知道,编程范式一共有三种,分别为面向过程编程,面向对象编程和函数式编程(这里重点说前两种)。
面向过程编程(Procedural Programming)
定义:使用一系列的指令来告诉计算机一步一步的该干什么。
面向过程编程依赖过程,一个过程包含了一组要被执行的步骤。面向过程就是程序从上到下一步步的执行,从头到尾的解决问题。基本的设计思路就是程序一开始要着手处理一个大问题,然后把一个大问题分解成多个小问题或者子过程,这些子过程再执行的过程再继续分解直到足够的简单可以在一个小步骤范围内解决。
这样做的弊端也就显现出来了,假如说要对以前的程序进行修改,那么对修改部分有依赖的那部分都要跟着修改。For example:假如程序开始设置了一个变量为1,但如果其他的一些子过程要依赖这个变量1才能正常的运行,那么改变了这个变量,那些子过程也要跟着修改,这样出现一连串的问题,随着程序的越来越大,维护难度也会随着增加。
所以一般情况下建议,写一些简单脚本或者做一些一次性的任务,面向过程是不错的选择。
面向对象编程(Object Oriented Programming)简称 OOP
面向对象???先看一张图片加深理解
纳尼,我读书少,千万别骗我!!!玩笑了,其实不然!(哈哈哈)
定义:利用“类”和“对象”创建各种模型来实现对真实世界的描述。
使用面向对象编程可以使程序的维护和扩展比较简单,并且可以大大提高程序的开发效率,另外,也可以使他人更容易理解,从而使团队开发变得从容。
类(Class)
一个类就是一类拥有相同属性的对象的抽象。
对象(Object)
一个对象就是一个类实例化后的实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象也可有不同的属性。
面向对象的核心特性:
封装
在类中对数据进行赋值,内部调用对外部用户是透明的(不可见的)。
继承
一个类可以派生出一个或多个子类,在这个父类里定义的属性,方法自动被子类继承。
多态
一个基类中派生出不同的子类,且每个子类在继承了同样的方法名的同时又被父类的方法做了不同的实现,这就是同一事物表现出的多种形态。
先看一个simple例子:
class Animal:
def __init__(self, name, eat, sleep, life=20, leg=4):
# 构造函数,在实例化时做一些类的初始化工作
self.NAME = name # 实例变量(静态属性),作用域就是实例本身
self.EAT = eat
self.SLEEP = sleep
self.LIFE = life
self.LEG = leg
def cat(self): # 类方法,功能(动态属性)
print("The cat name is \033[31;1m%s\033[0m!" % self.NAME)
def dog(self):
print("The dog favourite food is \033[34;1m%s\033[0m!!" % self.EAT)
def pig(self, colour):
print("The \033[35;1m%s\033[0m pig sleep \033[30;1m%s\033[0m hours everyday!!!" % (colour, self.SLEEP))
r1 = Animal("huahua", "meat", 15) # 把一个类变成一个具体对象的过程叫实例化(实例化一个类,相当于构造了一个对象)
r1.cat()
r1.dog()
r1.pig("white")
r2 = Animal("honghong", "vegetables", 10) # 实例化
r2.cat()
r2.dog()
r2.pig("black")
运行结果为:
再品:
class Animal:
n = 555 # 类变量(存在类的内存里)
n_list = []
NAME = "peiqi"
def __init__(self, name, eat, sleep, life=20, leg=4):
self.NAME = name
self.EAT = eat
self.SLEEP = sleep
self.LIFE = life
self.LEG = leg
def cat(self):
print("The cat name is \033[31;1m%s\033[0m!" % self.NAME)
def dog(self):
print("The dog favorite food is \033[34;1m%s\033[0m!!" % self.EAT)
def pig(self, colour):
print("The \033[35;1m%s\033[0m pig sleep \033[30;1m%s\033[0m hours everyday!!!" % (colour, self.SLEEP))
r1 = Animal("huahua", "meat", 15)
r1.NAME = "luoluo" # 改名字
r1.WEIGHT = "56kg" # 加属性(体重)
r1.n_list.append("from r1")
# print(r1.EAT)
# del r1.EAT # 删除吃,但是删除前还可以打印
r1.n = 666 # 改类变量(相当于在r1的内存里加了一个n=666,所以不影响r2.n的值)
print(r1.n, r1.NAME, r1.WEIGHT, r1.EAT, r1.n_list)
r2 = Animal("honghong", "vegetables", 10)
r2.EAT = "potato" # 改吃的
r2.n_list.append("from r2")
print(r2.n, r2.EAT, r2.n_list)
Animal.n = "abc"
print(Animal.n, r2.n, r1.n, Animal.n_list) # Animal.n不用实例化就可以打印
G:\Python38\python.exe G:/Project1/self_taught/week_6/cs_play.py
666 luoluo 56kg meat ['from r1']
555 potato ['from r1', 'from r2']
abc abc 666 ['from r1', 'from r2']
Process finished with exit code 0
通过上面的例子我们知道了,类变量的用途就是,都共有的属性!
析构函数
在实例释放,销毁的时候执行的。
class Animal:
def __init__(self, name, eat, sleep, life=20, leg=4):
self.NAME = name
self.EAT = eat
self.SLEEP = sleep
self.LIFE = life
self.LEG = leg
def __del__(self): # 析构函数
print("%s is hungry!!!" % self.NAME)
def cat(self):
print("The cat name is \033[31;1m%s\033[0m!" % self.NAME)
def dog(self):
print("The dog favorite food is \033[34;1m%s\033[0m!!" % self.EAT)
def pig(self, colour):
print("The \033[35;1m%s\033[0m pig sleep \033[30;1m%s\033[0m hours everyday!!!" % (colour, self.SLEEP))
r1 = Animal("huahua", "meat", 15)
r1.cat()
r1.dog()
r2 = Animal("honghong", "vegetables", 10)
r2.pig("black")
运行结果为:
G:\Python38\python.exe G:/Project1/self_taught/week_6/cs_play.py
The cat name is huahua!
The dog favorite food is meat!!
The black pig sleep 10 hours everyday!!!
huahua is hungry!!!
honghong is hungry!!!
Process finished with exit code 0
因程序执行完退出就会被销毁,所以析构函数会在最后被执行。
再稍微改动下:
r1 = Animal("huahua", "meat", 15)
r1.cat()
r1.dog()
del r1 # 删除r1
r2 = Animal("honghong", "vegetables", 10)
r2.pig("black")
再看运行结果:
G:\Python38\python.exe G:/Project1/self_taught/week_6/cs_play.py
The cat name is huahua!
The dog favorite food is meat!!
huahua is hungry!!!
The black pig sleep 10 hours everyday!!!
honghong is hungry!!!
Process finished with exit code 0
当r1被删除后,析构函数就会立即执行。
私有属性
self.__LIFE = life # 私有属性(对外面是透明的)
那要是想访问它,该怎么办呢?
class Animal:
def __init__(self, name, eat, sleep, life=20, leg=4):
self.NAME = name
self.EAT = eat
self.SLEEP = sleep
self.__LIFE = life # 私有属性
self.LEG = leg
def show_LIFE(self): # 在内部访问
self.__LIFE -= 5 # 在内部也可以改
print("The life is \033[31;1m%s\033[0m!" % self.__LIFE)
def cat(self):
print("The cat name is \033[31;1m%s\033[0m!" % self.NAME)
def dog(self):
print("The dog favorite food is \033[34;1m%s\033[0m!!" % self.EAT)
def pig(self, colour):
print("The \033[35;1m%s\033[0m pig sleep \033[30;1m%s\033[0m hours everyday!!!" % (colour, self.SLEEP))
r1 = Animal("huahua", "meat", 15)
r1.show_LIFE()
结果为:
G:\Python38\python.exe G:/Project1/self_taught/week_6/cs_play.py
The life is 15!
Process finished with exit code 0
可以看出,不但在内部访问还可以修改。
其实上面的例子已经包含了封装,那么下面咱们来看继承和多态!
先看例子:
class People:
def __init__(self, name, age):
self.NAME = name
self.AGE = age
def eat(self):
print("%s is eating..." % self.NAME)
def sleep(self):
print("%s is sleeping..." % self.NAME)
def talk(self):
print("%s is talking..." % self.NAME)
class Man(People):
def work(self):
print("%s is working..." % self.NAME)
def sleep(self):
People.sleep(self)
print("man is sleeping...")
class Woman(People):
def get_birth(self):
print("%s is born a baby..." % self.NAME)
m1 = Man("liming", 18)
m1.eat()
m1.work()
m1.sleep()
w1 = Woman("xiaohong", 22)
w1.get_birth()
运行结果为:
G:\Python38\python.exe G:/Project1/self_taught/week_6/inherit.py
liming is eating...
liming is working...
liming is sleeping...
man is sleeping...
xiaohong is born a baby...
Process finished with exit code 0
再看:
# class People: # 经典类
class People(object): # 新式类
def __init__(self, name, age):
self.NAME = name
self.AGE = age
def eat(self):
print("%s is eating..." % self.NAME)
def sleep(self):
print("%s is sleeping..." % self.NAME)
def talk(self):
print("%s is talking..." % self.NAME)
class Relation(object):
def make_friends(self, obj): # obj相当于w1
print("%s is making friends with %s" % (self.NAME, obj.NAME))
class Man(People, Relation):
def __init__(self, name, age, money):
# People.__init__(self, name, age)
super(Man, self).__init__(name, age) # 新式类写法(和上面的基本一样)
self.MONEY = money
print("%s born with %s money" % (self.NAME, self.MONEY))
def work(self):
print("%s is working..." % self.NAME)
def sleep(self):
People.sleep(self)
print("man is sleeping...")
class Woman(People, Relation):
def get_birth(self):
print("%s is born a baby..." % self.NAME)
m1 = Man("liming", 18, 9)
m1.eat()
m1.work()
m1.sleep()
w1 = Woman("xiaohong", 22)
w1.get_birth()
m1.make_friends(w1)
那么新式类和经典类有啥主要区别呢?
主要在多继承上的一个顺序问题
咱看个简单的例子
接着看:
class School(object):
def __init__(self, name, addr):
self.NAME = name
self.ADDR = addr
self.students = [] # 初始化学生的空列表
self.staffs = [] # 初始化老师的空列表
def enroll(self, stu_obj):
print("Register \033[31;1m%s\033[0m of new students" % stu_obj.NAME)
self.students.append(stu_obj)
def hire(self, staff_obj):
self.staffs.append(staff_obj)
print("Hire new teachers \033[33;1m%s\033[0m" % staff_obj.NAME)
class SchoolMember(object):
def __init__(self, name, age, sex):
self.NAME = name
self.AGE = age
self.SEX = sex
def tell(self):
pass
class Teacher(SchoolMember):
def __init__(self, name, age, sex, salary, course):
super(Teacher, self).__init__(name, age, sex)
self.SALARY = salary
self.COURSE = course
def tell(self):
print("""
----info of Teacher:%s----
Name:%s
Age:%s
Sex:%s
Salary:%s
Course:%s
""" % (self.NAME, self.NAME, self.AGE, self.SEX, self.SALARY, self.COURSE))
def teacher(self):
print("\033[35;1m%s\033[0m is teacher course \033[36;1m%s\033[0m" % (self.NAME, self.COURSE))
class Student(SchoolMember):
def __init__(self, name, age, sex, stu_id, grade):
super(Student, self).__init__(name, age, sex)
self.STU_ID = stu_id
self.GRADE = grade
def tell(self):
print("""
----info of Student:%s----
Name:%s
Age:%s
Sex:%s
Stu_id:%s
Grade:%s
""" % (self.NAME, self.NAME, self.AGE, self.SEX, self.STU_ID, self.GRADE))
def pay_tuition(self, amount):
print("\033[32;1m%s\033[0m has paid tuition for $\033[34;1m%s\033[0m" % (self.NAME, amount))
school = School("hpl", "雁塔区")
t1 = Teacher("liangzai", 34, "F", 20000, "Linux")
t2 = Teacher("diaomao", 28, "M", 15000, "Unix")
s1 = Student("zhangsan", 18, "F", 1001, "python")
s2 = Student("lisi", 19, "M", 1002, "java")
t1.tell()
s1.tell()
school.hire(t1) # 雇佣一个新老师t1
school.hire(t2) # 雇佣一个新老师t2
school.enroll(s1) # 注册一个学生s1
school.enroll(s2) # 注册一个学生s2
print(school.students)
print(school.staffs)
school.staffs[0].teacher() # 让新雇佣的老师开始教课
school.staffs[1].teacher()
for stu in school.students: # 让所有注册的学生都交学费
stu.pay_tuition(5000)
运行结果为:
G:\Python38\python.exe G:/Project1/self_taught/week_6/inherit_school.py
----info of Teacher:liangzai----
Name:liangzai
Age:34
Sex:F
Salary:20000
Course:Linux
----info of Student:zhangsan----
Name:zhangsan
Age:18
Sex:F
Stu_id:1001
Grade:python
Hire new teachers liangzai
Hire new teachers diaomao
Register zhangsan of new students
Register lisi of new students
[<__main__.Student object at 0x000002499EFD8490>, <__main__.Student object at 0x000002499EFD8550>]
[<__main__.Teacher object at 0x000002499EFD8370>, <__main__.Teacher object at 0x000002499EFD8400>]
liangzai is teacher course Linux
diaomao is teacher course Unix
zhangsan has paid tuition for $5000
lisi has paid tuition for $5000
Process finished with exit code 0
最后看个多态:
# 多态:一种接口,多种实现
class Animal(object):
def __init__(self, name):
self.NAME = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print("%s is miaomiao...." % self.NAME)
class Dog(Animal):
def talk(self):
print("%s is wangwang..." % self.NAME)
d = Dog("liangzai")
d.talk()
c = Cat("diaomao")
c.talk()
另一种写法:
class Animal(object):
def __init__(self, name):
self.NAME = name
def talk(self):
pass
class Cat(Animal):
def talk(self):
print("%s is miaomiao...." % self.NAME)
class Dog(Animal):
def talk(self):
print("%s is wangwang..." % self.NAME)
def animal_talk(obj):
obj.talk()
d = Dog("liangzai")
# d.talk()
c = Cat("diaomao")
# c.talk()
animal_talk(c)
animal_talk(d)
两种的结果都是一样的:
G:\Python38\python.exe G:/Project1/self_taught/week_6/polymorphic.py
liangzai is wangwang...
diaomao is miaomiao....
Process finished with exit code 0
但你是否觉得第二种会更好一些呢?
本周的学习内容就到此为止,望各位看客大佬发现有不足或错误能留言相告,臣不胜感激!!!