面向对象
一、面向对象是什么?
问题: 洗衣机里面放有脏衣服,怎么洗干净?
--------------------------------------- 面向过程的解决方法 ----------------------------------
1、把衣服放进洗衣机
2、放洗衣液
3、放水
4、洗衣服
5、倒掉脏水
6、再放水
7、再清洗
8、甩干衣服
9、晾晒
以上就是将解决这个问题的过程拆成一个个方法,通过一个个函数的执行来解决问题。
--------------------------------------- 面向对象的解决方法 ----------------------------------
1、我先弄出两个对象:"洗衣机"对象和"人"对象
2、针对对象“人”加入属性和方法:“把衣服放进洗衣机”、“放洗衣液”
3、针对对象"洗衣机"加入一些属性和方法:"放水"方法,"洗衣服"方法,"倒掉脏水"方法,"再放水"方法,"再清洗"方法,"甩干衣服"方法
4、然后执行
人.把衣服放进洗衣机
人.放洗衣液
洗衣机.放水
洗衣机.洗衣服
洗衣机.倒掉脏水
洗衣机.再放水
洗衣机.再清洗
人.甩干衣服
解决同一个问题 ,面向对象编程就是先抽象出所有相关对象,然后用对象执行方法的方式解决问题。
面向对象: 将问题里面涉及到的角色或者对象抽离出来
面向对象 (Object Oriented,OOP) 的思想对软件开发相当重要,它的概念和应用甚至已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD 技术、人工智能等领域。面向对象是一种 对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向过程 (Procedure Oriented) 是一种 以过程为中心 的编程思想。
无论是在软件开发还是在实际工作中,深入地理解软件开发的思想都非常有必要。
二、类和实例
对象同时具有属性与方法两项特性
对象的属性与方法通常被封装到一起,用属性与方法来共同体现事物的特性,二者相辅相成
说一说教师里面的对象,描述他们的属性与方法
2.1 对象在代码中的体现
在分析现实生活中的事物时发现,这些事物都有其具体的特点和功能,这些特点和功能就组成了这个特殊的事物
我们来描述一辆小汽车:
分析:
事物的特点(属性):
颜色
品牌
事物的功能:
高速运行
发现:事物其实就是由特点(属性)和行为(功能)组成的。
可以简单的理解:属性就是数据,其实就是变量;行为就是功能,就是方法。
小汽车类
颜色
品牌
def 高速运行():
pass
在python语言中定义的类语法:
class 类名: # 声明一个类 注意,如果由单词构成类名,建议大驼峰命名。
'''
解释文档
'''
类变量
def 实例方法(self,*args,**kwargs):
pass
2.2 实例变量(实例属性)
面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板,比如Person类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
案例演示:
class Person(object):
pass
p1=Person()
p2=Person()
print(id(p1))
print(id(p2))
每一个人的实例对象都应该有自己的属性,比如姓名和年龄,实例变量的赋值如下:
# 实例变量的增删改查
p1.name="alex"
p1.age=18
p2.name="yuan"
p2.age=22
print(p1.gender)
del p2.age
这种方式需要先实例化再赋值实例变量,如何能在初始化对象的时候就将实例变量赋值好呢?这就要利用到类的魔法方法中最重要的构造方法( init)了:
# 定义Person类
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
print(id(self))
# 实例化Person类的实例对象: 类实例对象=类名(实例化参数)
alex=Person("alex",18)
yuan=Person("yuan",22)
print(id(alex))
注意到__init__
方法的第一个参数永远是self
,表示创建的实例本身,因此,在__init__
方法内部,就可以把各种属性绑定到self
,因为self
就指向创建的实例本身。
2.2 实例方法
实例方法或者叫对象方法,指的是我们在类中定义的普通方法。只有实例化对象之后才可以使用的方法,该方法的第一个形参接收的一定是对象本身。
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def print_info(self):
print("姓名:%s,年龄:%s"%(self.name,self.age))
yuan = Person("yuan",18)
yuan.print_info()
2.3 一切皆对象
在python语言中,一切皆对象!
我们之前学习过的字符串,列表,字典等等数据都是一个个的类,我们用的所有数据都是一个个具体的实例对象。
区别就是,那些类是在解释器级别注册好的,而现在我们学习的是自定义类,但语法使用都是相同的。所以,我们自定义的类实例对象也可以和其他数据对象一样可以进行传参、赋值等操作。
class Weapon:
def __init__(self,name,av,color):
self.name=name
self.av=av
self.color=color
jiguangqiang=Weapon("激光枪",100,"red")
class Hero:
def __init__(self,name,sex,hp,ce,weapon,level=2,exp=2000,money=10000): # 类必不可少的方法,用于实例化
self.name=name # 英雄的名字
self.sex=sex # 英雄的性别
self.hp=hp # 英雄生命值
self.level=level # 英雄的等级
self.exp=exp # 英雄的经验值
self.money=money # 英雄的金币
self.weapon=weapon # 英雄的武器
alex=Hero("yuan","male",100,80,jiguangqiang)
print(alex.weapon.color)
def show_hero_weapon(obj):
print(alex.weapon.color)
show_hero_weapon(alex)
2.4 类对象和类属性
class Student:
# 类属性
number = 68
def __init__(self,name):
self.name=name
yuan = Student("yuan")
# 实例对象和类对象可以获取类属性,但是只有类对象才能修改类属性
print(yuan.number)
print(Student.number)
yuan.number = 88
print(yuan.number)
print(Student.number)
2.5 静态方法和类方法
静态方法
定义:使用装饰器@staticmethod。参数随意,没有“self”和“cls”参数,但是方法体中不能使用类或实例的任何属性和方法;
调用:类对象或实例对象都可以调用。
class Cal():
类方法
定义:使用装饰器@classmethod。第一个参数必须是当前类对象,该参数名一般约定为“cls”,通过它来传递类的属性和方法(不能传实例的属性和方法);
调用:类对象或实例对象都可以调用。
class Student:
# 类属性
number = 68
问题:
-
类对象.实例方法会怎么样?
-
类方法的意义是什么,在实例方法中使用类对象变量不可以吗?
三、面向对象三大特性
3.1面向对象特性之继承(重点掌握)
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。
class 派生类名(基类名)
...
3.1.1 继承的基本使用
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。
实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性。例如猫有抓老鼠、爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,例如我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”。
诚然,继承定义了类如何相互关联,共享特性。对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。
同时在使用继承时需要记住三句话:
1、子类拥有父类非私有化的属性和方法。
2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
3、子类可以用自己的方式实现父类的方法。(以后介绍)。
# 无继承方式
class Dog:
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
def swimming(self):
print("swimming...")
class Cat:
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
def climb_tree(self):
print("climb_tree...")
# 继承方式
class Animal:
def eat(self):
print("eating...")
def sleep(self):
print("sleep...")
class Dog(Animal):
def swimming(self):
print("toshetou...")
class Cat(Animal):
def climb_tree(self):
print("climb_tree...")
alex=Dog()
alex.run()
3.1.2 重写父类方法和调用父类方法
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
def sleep(self):
print("基类sleep...")
class Emp(Person):
# def __init__(self,name,age,dep):
# self.name = name
# self.age = age
# self.dep = dep
def __init__(self, name, age, dep):
# Person.__init__(self,name,age)
super().__init__(name,age)
self.dep = dep
def sleep(self):
if "不在公司":
# print("子类sleep...")
# 调用父类方法
# 方式1 :父类对象调用 父类对象.方法(self,其他参数)
# Person.sleep(self)
# 方式2: super关键字 super(子类对象,self).方法(参数)or super().方法(参数)
super().sleep()
yuan = Emp("yuan",18,"教学部")
yuan.sleep()
print(yuan.dep)
测试题:
class Base:
def __init__(self):
self.func()
def func(self):
print('in base')
class Son(Base):
def func(self):
print('in son')
s = Son()
案例:电商项目的结算功能
电商项目,设计收银功能:
目前平台有三种商品:海尔冰箱每台3000元;西门子洗衣机每台5000元;芝华士沙发每件6000元。根据用户购买商品单价和数量计算总价。
------------------------------------------- 面向过程:
unit=int(input("请输入商品序号>>>"))
number=int(input("请输入商品数量>>>"))
goods={1:("海尔冰箱",3000),2:("西门子洗衣机",5000),3:("芝华士沙发",3000)}
total_price=goods[unit][1]*number
print(total_price)
------------------------------------------- 函数完善版:
def get_unit():
unit=int(input("请输入商品序号>>>"))
return unit
def get_number():
number=int(input("请输入商品数量>>>"))
return number
goods={1:("海尔冰箱",3000),2:("西门子洗衣机",5000),3:("芝华士沙发",6000)}
def get_total_price(unit,number):
total_price=goods[unit][1]*number
return total_price
unit=get_unit()
number=get_number()
total_price=get_total_price(unit,number)
print(total_price)
------------------------------------------- 面向对象版本
import datetime
import random
print('''
1、海尔冰箱 单价3000元;
2、西门子洗衣机 单价5000元;
3、芝华士沙发 单价6000元
''')
goods={1:("海尔冰箱",3000),2:("西门子洗衣机",5000),3:("芝华士沙发",6000)}
# 结账类
class Bill(object):
def __init__(self,name):
self.name=name
def get_unit(self):
unit = int(input("请输入商品序号>>>"))
return unit
def get_number(self):
number = int(input("请输入商品数量>>>"))
return number
def get_total_price(self):
unit = self.get_unit()
number = self.get_number()
total_price = goods[unit][1] * number
ret = self.discount(total_price)
print("%s于%s总共花费%s元"%(self.name,datetime.datetime.today(),ret))
return ret
def discount(self,price):
return price
# bill=Bill("Yuan老师")
# bill.get_total_price()
class NationalDayBill(Bill):
def discount(self, price):
if price>399:
return price-200
return super().discount(price)
# ndb=NationalDayBill("Yuan")
# ndb.get_total_price()
class Double11Bill(Bill):
def discount(self,price):
if price > 200:
free=random.randint(0,1)
if free == 0:
return 0
return super().discount(price)
# mab=Double11Bill("Yuan")
# mab.get_total_price()
# 问题:如果再加一个中秋节满五百折扣0.8,但是今年中秋节和国庆节是一天,所以两个优惠同时享受的话该怎样设计?
class MiddleAutumeBill(NationalDayBill):
def discount(self,price):
if price >500:
temp_price=super().discount(price) # 国庆优惠后的价格
return temp_price*0.8
return super().discount(price)
mab=MiddleAutumeBill("Yuan")
mab.