面向对象编程
函数封装了重复代码
类包含属性和函数
Python中面向对象三大特性:封装,继承,多态
封装
class ClassName:
"类说明文档"
<statement1>
.
.
.
<statement2>
demo = ClassName()
面向对象编程—对象
一切皆是对象
Python中在尽可能不增加新语法的情况和语义的情况下加入类机制
对象:
- 拥有一个类型class
- 拥有属性attribute(data + functions)
面向对象编程—__init__
方法
def __init__(self):
self.data = []
#类有一个名为__init__()的特殊函数(构造方法)
#该方法在类实例化时会自动调用
def __init__(self, name, id):
self.data = []
print("myname:{},myid{}".format(name, id))
#__init__()方法可以有参数,参数通过__init__()传递到类的实例化操作上
面向对象编程—普通方法
在类的内部,使用 def
关键字来定义一个方法,类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称:如self
。
self
代表类的实例,而非类,self为类的方法调用时传送的参数。
class Myclass:
"This is a simple class example"
e = 3.1415
def func(self):
print(self)
print(self.__class__)
return "hello world"
#实例化类
x = Myclass()
#访问类的属性和方法
print("MyClass类的属性e为: ",Myclass.e)
# MyClass类的属性e为: 3.1415
print("MyClass类的方法func输出为: ",x.func())
# <__main__.Myclass object at 0x0000022371CE6160>
# <class '__main__.Myclass'>
# MyClass类的方法func输出为: hello world
print(x.__class__)
# <class '__main__.Myclass'>
注意:由于
func()
是一个实例方法,你需要首先创建MyClass
的一个实例,然后通过该实例调用func()
方法。如果直接MyClass.func()会报错:TypeError: func() missing 1 required positional argument: ‘self’
DEMO
class People:
"This is a people class example"
#类属性,实例属性
#类属性
People_name = "Python"
def __init__(self, name, id):#self也可以换成其他名字如this,语法不报错,默认推荐是self
#实例属性
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
实例化类
#python构造对象时有两个函数__init__和__new__。1.调用new方法2.调用init方法。一般不重写new方法,只做init方法初始化
p1 = People("hzh", 1)
print(p1.People_name)
#Python
print(p1.name)
# hzh
print(p1.speak())
# My name is : hzh
# None
print(type(People))
# <class 'type'>
p2 = People("Tom", 2)
print(p2.People_name)#People_name是类属性是所有对象共有的对象,自动传递给每个实例化对象
# Python
print(p2.name)#self.name是实例化属性,所以p1p2里属性构造是不同的
# Tom
类属性的特性
# 1:当People_name = "Python 类属性是不可变对象
# 修改p1中的类属性,p2不受影响.对象修改类属性实际上是创建了一个同名的新属性
p1.People_name = "Chinese"
print(p1.People_name)
# Chinese
print(p2.People_name)
# Python
# 2.当People_name = ["Python", "Java"] 类属性为可变对象
# 修改p1中的类属性,p2也跟着改变
print(p1.People_name)
# ['Python', 'Java']
p1.People_name[0] = "Chinese"
print(p1.People_name)
# ['Chinese', 'Java']
print(p2.People_name)
['Chinese', 'Java']
# 3.当People_name = "Python 类属性是不可变对象
# 通过类修改类属性,p1p2也都跟着变化
People.People_name = "Chinese"
print(p1.People_name)
# Chinese
print(p2.People_name)
# Chinese
Python动态语言特性:可以直接操作实例或类修改属性
# __dict__:属性字典,其中包含了实例的属性信息
p1 = People("hzh", 1)
print(p1.__dict__)#p1里拥有的实例
# {'name': 'hzh', 'id': 1}
p1.gender = "male"#可以直接给p1添加属性
print(p1.__dict__)
# {'name': 'hzh', 'id': 1, 'gender': 'male'}
del(p1.gender)#删除p1中属性
print(p1.__dict__)
# {'name': 'hzh', 'id': 1}
People.People_id = "1111"#同样也可以修改类的属性
print(People.__dict__)
# ...'People_id': '1111'}
继承
面向对象编程—继承
Python继承的语法格式:
申明类的时候,在括号里加上父类(基类)的名称
class ChildClassName(BaseClass):
<statement - 1>
.
.
.
<statement - N>
#注意:
# 1.当基类定义在不同作用域(模块)时:
class ChildClassName(modulename.BaseClass):
# 2.多继承:
class ChildClassName(Base1, Base2, Base3):
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id):
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
class Student(People):# Student类继承了父类People中的属性和方法
#默认继承父类构造方法
def eat(self, food):
print("I like eat: ", food)
p1 = People("hzh", 1)
s1 = Student("Tom", 2)
print(dir(s1))
print(s1.People_name)# Python
print(s1.name)# Tom
s1.speak()# My name is : Tom
s1.eat("rice")# I like eat: rice
print(type(s1))# <class '__main__.Student'>
面向对象编程—继承方法重写(覆盖)
super
父类方法的功能不能满足需求,可以在子类重写父类的方法
class Parent: # 定义父类
def my_method(self):
print("调用父类方法")
class Child(Parent): # 定义子类
def my_method(self):
print("调用子类方法")
c1 = Child() # 子类实例
c.my_method() # 子类调用重写方法
super(Child, c).my_method() # 用子类对象调用父类已被覆盖的方法
# 注意
# 1.如果需要子类对象调用父类方法:`super`关键字
super(Child, c1).my_method()# c1也可以换成self
# 等价于
Parent.my_method()
# 2.子类继承父类构造方法:如果在子类中需要父类的构造方法就需要显式地调用父类的构造方法或者不重写父类的构造方法,或者不重写父类的构造方法
# 子类调用父类的构造方法
super(Chlid, self).__init__(参数1, 参数2,...)
# 等价于
Parent.__init__(self, 参数1, 参数2,...)
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id):
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
class Student(People):# Student类继承了父类People中的属性和方法
#默认继承父类构造方法
def __init__(self, name, id, food):# 重写父类初始化方法,添加一个新属性
super(Student, self).__init__(name, id)# 调用父类构造方法
self.food = food
def eat(self, food):
print("I like eat: ", food)
def speak(self):# 子类中重写父类方法 覆盖
super(Student, self).speak()# 传入父类的speak方法/ super里参数可以不写
print("His name is :", self.name)
p1 = People("hzh", 1)# 父类
s1 = Student("Tom", 2, "noddles")# 子类
print(dir(s1))
print(s1.People_name)# Python
print(s1.name)# Tom
print(s1.food)# noddles
s1.speak()# My name is : Tom
s1.eat("rice")# I like eat: rice
print(type(s1))# <class '__main__.Student'>
s1.speak()
# My name is : Tom 父类方法
# His name is : Tom 子类重写的方法
多继承
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id):
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
class Runner:
People_speed = "100m/s"
def run(self, speed):
print("My speed is: ", speed)
def speak(self):
print("I like running")
class Student(People, Runner):# Student类继承了父类People和Runner类
#默认继承父类构造方法
def __init__(self, name, id, food):# 重写父类初始化方法,添加一个新属性
super(Student, self).__init__(name, id)# 调用父类构造方法
self.food = food
def eat(self, food):
print("I like eat: ", food)
# def speak(self):# 子类中重写父类方法 覆盖
# print("His name is :", self.name)
s1 = Student("hzh", 2, "noddles")# 子类
s1.speak()# 覆盖先去自己类里找,找不到再去找父类
# His name is : hzh
s1.speak()#如果子类中没有speak方法,Student(People, Runner),括号里谁再前先去找哪个父类
# My name is : hzh
print(Student.__mro__)# 返回方法解析数据的列表,方法的查找顺序
# (<class '__main__.Student'>, <class '__main__.People'>, <class '__main__.Runner'>, <class 'object'>)
print(Student.__bases__)# 返回基类列表
# (<class '__main__.People'>, <class '__main__.Runner'>)
# 注意
# <class 'object'>这是所有类的基类
如果不想用默认顺序调用父类方法:
def speak(self):# 子类中重写父类方法 覆盖
Runner.speak(self)# 自定义先调用Runner父类
People.speak(self)
print("His name is :", self.name)
s1 = Student("hzh", 2, "noddles")# 子类
s1.speak()
# I like running
# My name is : hzh
# His name is : hzh
由父类完成子类初始化的方法:
- 使用父类名显式调用
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id):
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
class Runner:
People_speed = "100m/s"
def __init__(self, speed):
self.speed = speed
def run(self, speed):
print("My speed is: ", speed)
def speak(self):
print("I like running")
class Student(People, Runner):# Student类继承了父类People和Runner类
#默认继承父类构造方法
def __init__(self, name, id, speed, food):# name id 来自People,speed来自Runner
# super(Student, self).__init__(name, id)
# 调用多个父类构造方法,用父类名来调用
People.__init__(self, name, id)
Runner.__init__(self, speed)
self.food = food
def eat(self, food):
print("I like eat: ", food)
def speak(self):# 子类中重写父类方法 覆盖
print("His name is :", self.name)
s1 = Student("hzh", 2, "150m/s", "noddles")# 子类
s1.speak()
# His name is : hzh
print(s1.__dict__)
# {'name': 'hzh', 'id': 2, 'speed': '150m/s', 'food': 'noddles'}
- 使用super() 广度优先遍历的检索
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id, *args, **kwargs):# 添加万能参数
print("People start")
super().__init__(*args, **kwargs)
self.name = name
self.id = id
print("People end")
def speak(self):
print("My name is :", self.name)
class Runner:
People_speed = "100m/s"
def __init__(self, speed, *args, **kwargs):# 添加万能参数
print("Runner start")
super().__init__(*args, **kwargs)
self.speed = speed
print("Runner end")
def run(self, speed):
print("My speed is: ", speed)
def speak(self):
print("I like running")
class Student(People, Runner):# Student类继承了父类People和Runner类
#使用万能可变参数
def __init__(self, food, *args, **kwargs):# name id 来自People,speed来自Runner
# 将万能参数写入,让父类自动处理
print("Student start")
super(Student, self).__init__(*args, **kwargs)
self.food = food
print("Student end")
def eat(self, food):
print("I like eat: ", food)
def speak(self):# 子类中重写父类方法 覆盖
print("His name is :", self.name)
s1 = Student("noddles", "hzh", 2, "150m/s")# 固定参数要写前面,万能参数写后面,打印初始化过程的运行顺序
# Student start
# People start
# Runner start
# Runner end
# People end
# Student end
s1.speak()
# His name is : hzh
print(s1.__dict__)
# {'speed': '150m/s', 'name': 'hzh', 'id': 2, 'food': 'noddles'}
总结:如果要用super关键字实现多继承的父实例属性的自动化构造方法,需要将给父类传入的参数变成万能参数的形式*args, **kwargs
,并且在父类中要在初始化后面加入万能参数来接受子类传入的参数传递。同时父类也需要去写一个super初始化方法来调用父类的初始化方法。
多态
什么是多态?
什么是多态
class People:
"This is a people class example"
People_name = "Python"
def __init__(self, name, id):
self.name = name
self.id = id
def speak(self):
print("My name is :", self.name)
class Student(People):
def speak(self): # 子类中重写父类方法 覆盖
print("His friend is :", self.name)
p1 = People("hzh", 1) # 父类
s1 = Student("Tom", 2) # 子类
def fun(People):# 参数是一个对象
People.speak()# 去对应的对象中找speak方法
print("This is fun!")
fun(p1)
# My name is : hzh
# This is fun!
fun(s1)
# His friend is : Tom
# This is fun!
判断对象是否属于某个类
# isinstance() 返回bool某个对象是否属于某个类
print(isinstance(s1, People))# 子类对象既属于父类
# True
print(isinstance(s1, Student))# 也属于子类
# True
# type()也能判断某个对象是否属于某个类
print(type(p1))
# <class '__main__.People'>