面向对象编程(简称OOP)
面向对象编程是一种解决软件复用的设计和编程方法。这种方法所软件系统中相似的操作逻辑、数据、状态等以类的形式描述出来,通过对象实例在软件系统中复用,从而提高软件开发效率。
类:一个事物的抽象,定义了一类事物的属性和行为
对象:通过类创建的一个具体事物,它具有状态和行为,可以做具体的事情
类与对象的关系:类相当于创建对象的模板,根据类可以创建多个对象
类的构成:
- 类的名称
- 类的属性
- 类的方法
类的定义
class 类名:
def 方法名(self[,参数列表 ])
类里面定义的叫方法,类外面定义的叫函数。
类名的命名规则按照“大驼峰”(单词首字母大写)
定义的方法默认要传入一个self参数,表示自忆,self参数必须是第一个参数
#定义类
class Dog:
def eat(self):
print("小狗正在啃骨头...")
def drink(self):
print("小狗正在喝水...")
类的创建
- 对象:通过类创建的一个具体事物,它具有状态和行为,可以做具体的事情
- 类与对象的关系:类相当于创建对象的模板,根据类可以创建多个对象
- 创建对象:对象变量名 = 类名()
# 创建对象
wang_cai = Dog()
print(id(wang_cai))
wang_cai.eat()
wang_cai.drink()
# 一个类可以创建多个对象
a_fu = Dog()
print(id(a_fu))
a_fu.eat()
a_fu.drink()
类的构造方法
_init_构造方法
- 调用时间:在对象被实例化是被程序自动调用
- 作用:用于对象创建时初始化
- 书写格式:init前后分别是两个下划线
- 程序不显示定义init方法,则程序默认调用一个无参init方法
class Dog:
def __init__(self):
print("我是构造方法,在创建对象时自动调用")
def eat(self):
print("正在吃骨头...")
def drink(self):
print("正在喝水....")
wangcai = Dog()
print("------------")
wangcai.eat()
wangcai.drink()
- 对象创建过程
- 在__init__()构造方法中初始化对象属性
class Dog:
def __init__(self, gender, variety, name):
self.gender = gender
self.variety = variety
self.name = name
# 获取对象属性,并打印出来
def get_pro(self):
print("gender:{},variety:{},name:{}".format(self.gender, self.variety, self.name))
wangcai = Dog("male","golden","wangcai")
yuanbao = Dog("female","husky","yuanbao")
wangcai.get_pro()
yuanbao.get_pro()
分别调用,互不干扰
注:self参数必须是第一个参数
类的访问权限
修改对象属性的方法
- 方法1:对象变量名.属性 = 新值
- 方法1的问题:
1)可能修改的属性值不合法
2)在类的外部可以随意修改类的内部属性 - 方法2:对象变量名.内部修改属性方法
class Dog:
def __init__(self,gender,variety,name,age):
#print("我是构造方法,在创建对象时自动调用")
self.gender = gender
self.variety = variety
self.name = name
self.age = age
wangcai = Dog('man','golden','wangcai','20')
#修改对象属性,方法1直接修改
wangcai.age = 100
print(wangcai.age)
class Dog:
def __init__(self,gender,variety,name,age):
#print("我是构造方法,在创建对象时自动调用")
self.gender = gender
self.variety = variety
self.name = name
self.age = age
def get_pro(self):
print("gender:{},variety:{},name:{},age:{}".format(self.gender,self.variety,self.name,self.age))
#设置对象内部属性
def set_pro(self,**kwargs):
if "gender" in kwargs:
self.gender = kwargs["gender"]
elif "age" in kwargs:
if kwargs["age"] < 0 or kwargs["age"]>20:
print("非法年龄")
else:
self.age = kwargs["age"]
wangcai = Dog("male","golden","wangcai",1)
#方法2:通过内部方法修改属性
wangcai.set_pro(age=10)
wangcai.get_pro()
##这种方法还是可以直接从外部直接修改属性,不够安全,所以引入私有属性概念
私有属性
- 定义:__私有变量名(前面两个下划线)
- 只能在类内部使用,类外部不能访问,否则报错
##将age变为私有属性
class Dog:
def __init__(self,gender,variety,name,age):
#print("我是构造方法,在创建对象时自动调用")
self.gender = gender
self.variety = variety
self.name = name
self.__age = age
def get_pro(self):
print("gender:{},variety:{},name:{},age:{}".format(self.gender,self.variety,self.name,self.__age))
#设置对象内部属性
def set_pro(self,**kwargs):
if "gender" in kwargs:
self.gender = kwargs["gender"]
elif "age" in kwargs:
if kwargs["age"] < 0 or kwargs["age"]>20:
print("非法年龄")
else:
self.__age = kwargs["age"]
wangcai = Dog('man','golden','wangcai',20)
wangcai.get_pro()
###如果def_pro和def set_pro中的age不加双下划线,则会报错出不存在age这个属性
私有方法
- 只能在类内部调用,在类的外部无法调用
- 定义私有方法在方法名前添加两个下划线
- 类内部调用私有方法要使用self.私有方法的方式调用
#私有方法的使用
class Comrade:
#私有方法
def __send_message(self):
print("消息已经向上级汇报")
def answer_secret(self,secret):
if secret == "芝麻开门":
print("接头成功!")
self.__send_message()#调用私有方法
else:
print("接头失败!")
comrade = Comrade()
comrade.answer_secret("芝麻开门")
继承
在程序中,继承描述的是类中类型与子类型之间的所属关系,例如猫和狗都属于动物
单继承:
- 子类继承一个父类,在定义子类时,小括号()中写父类的类名
- 父类的非私有属性、方法,会被子类继承
- 子类中方法的查找方式:先查找子类中对应的方法,如果找不到,再到父类中查找
- 子类可以继承父类的属性和方法,也可以继承父类的父类非私有属性和方法,依次类推
- 在子类中调用父类的方法:ClasssName.methodname(self)
class Animal:
def __init__ (self):
print("---animal构造方法----")
def __private_method(self):
print('私有方法')
def eat(self):
print('-----吃-----')
def drink(self):
print('-----喝-----')
def run(self):
print('-----跑-----')
class Dog(Animal):
def __init__(self):
print('dog构造方法')
def hand(self):
##子类在类里面调用父类的方法
Animal.run(self)
print('----握手-----')
wangcai =Dog()
#调用从父类继承的方法
wangcai.eat()
wangcai.drink()
wangcai.run()
#调用自身的方法
wangcai.hand()
#调用父类的私有方法,会被报错,不能继承父类的私有方法
# wangcai.__private_method
#如果在子类中没有定义init构造方法,则自动调用父类的init构造方法,如果在子类中定义了init构造方法,则不会调用父类的构造方法
duoduo = Dog()
duoduo.run()
重写父类方法
- 子类对父类允许访问的方法的实现过程进行重新编写
- 在子类中定义与父类同名的方法
- 优点:子类可以根据需要,定义合适的方法实现逻辑
class Animal:
def __init__ (self):
print("---animal构造方法----")
def __private_method(self):
print('私有方法')
def eat(self):
print('-----吃-----')
def drink(self):
print('-----喝-----')
def run(self):
print('-----跑-----')
class Dog(Animal):
#父类方法重写 #只要够名称覆盖掉父类的方法就可以实现重写
def run(self):
print('摇着尾巴跑')
def hand(self):
print('----握手-----')
wangcai =Dog()
wangcai.run()
多继承:
- object类是所有类的基类,在定义类的时候不需要显示的在括号中表明继承自object类
- 多继承:一人子类可以继承多个父类
- 多继承定义方式:在类名后的括号中添加需要继承的多个类名
- 多继承中,如果多个类中有同名的方法,子类调用查找方法的顺序是按照小括号内继承父类从左到右的顺序查找,第一个匹配方法名的父类方法将会被调用
#多继承中方法的名称尽量不一样,要不然会出现不必要的错误和困扰,比如下面的data_handle
class AI:
#人脸识别
def face_recongnition(self):
print("人脸识别")
def data_handle(self):
print("AI数据处理")
class BigData:
def data_analysis(self):
print("数据分析")
def data_handle(self):
print("BigData数据处理")
class Python(BigData,AI):
def operation(self):
print("自动化运维")
py = Python()
py.face_recongnition()
py.data_analysis()
py.operation()
py.data_handle()
print(Python.__mro__) #查看调用方法的搜索顺序
建议:尽量不要在父类中定义相同的方法名称,语法上是可以,但这个纯粹就是给自已挖坑。
多态
一个抽象类有多个子类,不同的类表现出多种形态;多态在Python中表现的并不强烈。
#子类的的方法是会覆盖掉父类的方法,只有存在继承,才能存在多态
class Animal:
def eat(self):
print("Animal正在吃饭")
class Dog(Animal):
def eat(self):
print("Dog正在吃饭")
class Cat(Animal):
def eat(self):
print("Cat正在吃饭")
def show_eat(obj):
obj.eat()
wangcai = Dog()
show_eat(wangcai)
tom = Cat()
show_eat(tom)