p10_面向对象编程

学生 老师

人物出场介绍(姓名、年龄、地址) 人物出场介绍(姓名、年龄、地址)

起床(起床) 起床(起床啦)

洗漱(刷牙、洗脸) 洗漱(刷牙、洗脸)

吃饭(吃菜、扒饭) 吃饭(吃菜、扒饭)

登录账号(账号登录成功) 打卡(今日打卡成功)

学习(看视频、写代码) 工作(授课、答疑、写代码)

吃饭(吃菜、扒饭) 吃饭(吃菜、扒饭)

学习(看视频、写代码) 工作(授课、答疑、写代码)

吃饭(吃菜、扒饭) 吃饭(吃菜、扒饭)

洗漱(刷牙、洗脸) 洗漱(刷牙、洗脸)

睡觉(睡觉) 睡觉(睡觉)

人数统计(统计、公布) 人数统计(统计、公布)

学生 老师

人物出场介绍(姓名、年龄、地址) 人物出场介绍(姓名、年龄、地址)

起床(起床啦) 起床(起床啦)

定义洗漱函数、吃饭函数、学习函数 定义洗漱函数、吃饭函数、工作函数

调用洗漱函数 调用洗漱函数

调用吃饭函数 调用吃饭函数

模拟学生和老师的一天

面向过程(结构化编程)

学生 老师

登录账号(账号登录成功) 打卡(今日打卡成功)

调用学习函数 调用工作函数

调用吃饭函数 调用吃饭函数

调用学习函数 调用工作函数

调用吃饭函数 调用吃饭函数

调用洗漱函数 调用洗漱函数

睡觉(睡觉) 睡觉(睡觉)

人数统计(统计、公布) 人数统计(统计、公布)

count_s = 0
stu1 = "张三"
age_s = 18
adres_s = "黄土高坡"
print(f"大家好! 我是{stu1}, 今年{age_s}岁, 家住在{adres_s},
欢迎大家有空来玩哦!")
count_s += 1
def wash(name):
print(f"{name}刷牙")
print(f"{name}洗脸")
def eat(name):
print(f"{name}吃菜")
print(f"{name}扒饭")
def study(name):
print(f"{stu1}看视频")
print(f"{stu1}写代码")

print(f"{stu1}起床")

wash(stu1)

eat(stu1)

print(f"{stu1}账号登录成功")

study(stu1)

eat(stu1)

study(stu1)

eat(stu1)

wash(stu1)

print(f"{stu1}睡觉")

print(f"当前统计的学生人数是: {count_s} 人")

count_t = 0
teacher1 = “老王”
age_t = 40
adres_t = “人民广场”

print(f"大家好! 我是{teacher1}, 今年{age_t}岁, 家住在
{adres_t}, 欢迎大家有空来玩哦!")

count_t += 1

def wash(name):
print(f"{name}刷牙")
print(f"{name}洗脸")

def eat(name):
print(f"{name}吃菜")
print(f"{name}扒饭")

def work(name):
print(f"{name}授课")
print(f"{name}答疑")
print(f"{name}写代码")

print(f"{teacher1}起床")

wash(teacher1)

eat(teacher1)

print(f"{teacher1}今日打卡成功")

work(teacher1)

eat(teacher1)

work(teacher1)

eat(teacher1)

wash(teacher1)

print(f"{teacher1}睡觉")

学生 老师 人

创建一个学生 类 创建一个老师 类 创建一个人 类

针对某个学生的属性作

为:

实例变量

针对某个老师的属性作

为:

实例变量

让学生类和老师类 继承 人

不针对某个学生而针对

整个类的属性作为:类

变量

不针对某个老师而针对

整个类的属性作为:类

变量

把 子类 共有的变量和方法

写到 父类 中,而子类可不

用写

针对某个学生的功能作

为:

对象方法

针对某个老师的功能作

为:

对象方法

把 子类 独有的变量和方法

留在 子类 中

不针对某个学生而针对

整个类的功能作为:类

方法

不针对某个老师而针对

整个类的功能作为:类

方法

面向对象(高内聚低耦合)

程序 = 数据 + 算法。

面向过程编程,更侧重于算法;而面向对象编程更侧重于数据。

print(f"当前统计的老师人数是: {count_t} 人")
class Student:
count = 0
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
self.show_time()

Student.count += 1

def show_time(self):
print(f"大家好! 我是{self.name}, 今年{self.age}岁,
家住在{self.address}, 欢迎大家有空来玩哦!")

def get_up(self):
print(f"{self.name}起床")

def wash(self):
print(f"{self.name}刷牙")
print(f"{self.name}洗脸")

def eat(self):
print(f"{self.name}吃菜")
print(f"{self.name}扒饭")

def login_ID(self):
print(f"{self.name}账号登录成功")

def study(self):
print(f"{self.name}看视频")
print(f"{self.name}写代码")

def sleep(self):
print(f"{self.name}睡觉")

@classmethod
def counter(cls):
print(f"当前统计的学生人数是: {cls.count} 人")

stu1 = Student(“张三”, 18 , “黄土高坡”)
stu1.get_up()
stu1.wash()

stu1.eat()
stu1.login_ID()
stu1.study()
stu1.eat()
stu1.study()
stu1.eat()
stu1.wash()
stu1.sleep()
stu1.counter()

class Teacher:
count = 0

def init(self, name, age, address):
self.name = name
self.age = age
self.address = address
self.show_time()
Teacher.count += 1

def show_time(self):
print(f"大家好! 我是{self.name}, 今年{self.age}岁,
家住在{self.address}, 欢迎大家有空来玩哦!")

def get_up(self):
print(f"{self.name}起床")

def wash(self):
print(f"{self.name}刷牙")
print(f"{self.name}洗脸")

def eat(self):
print(f"{self.name}吃菜")
print(f"{self.name}扒饭")

def clock_in(self):
print(f"{self.name}今日打卡成功")

def work(self):
print(f"{self.name}授课")
print(f"{self.name}答疑")
print(f"{self.name}写代码")

def sleep(self):
print(f"{self.name}睡觉")

@classmethod
def counter(cls):
print(f"当前统计的老师人数是: {cls.count} 人")

teacher1 = Teacher(“老王”, 40 , “人民广场”)
teacher1.get_up()
teacher1.wash()
teacher1.eat()
teacher1.clock_in()
teacher1.work()
teacher1.eat()
teacher1.work()
teacher1.eat()
teacher1.wash()
teacher1.sleep()
teacher1.counter()

class Person:

def init(self, name, age, address):
self.name = name

self.age = age
self.address = address
self.show_time()

def show_time(self):
print(f"大家好! 我是{self.name}, 今年{self.age}岁,
家住在{self.address}, 欢迎大家有空来玩哦!")

def get_up(self):
print(f"{self.name}起床")

def wash(self):
print(f"{self.name}刷牙")
print(f"{self.name}洗脸")

def eat(self):
print(f"{self.name}吃菜")
print(f"{self.name}扒饭")

def sleep(self):
print(f"{self.name}睡觉")

class Student(Person):

count = 0

def init(self, name, age, address, classes):
super().init(name, age, address)
self.classes = classes
Student.count += 1

def login_ID(self):
print(f"{self.name}账号登录成功")

def study(self):
print(f"{self.name}看视频")
print(f"{self.name}写代码")

@classmethod
def counter(cls):
print(f"当前统计的学生人数是: {cls.count} 人")

class Teacher(Person):
count = 0

def init(self, name, age, address, department):
super().init(name, age, address)
self.department = department
Teacher.count += 1

def clock_in(self):
print(f"{self.name}今日打卡成功")

def work(self):
print(f"{self.name}授课")
print(f"{self.name}答疑")
print(f"{self.name}写代码")

@classmethod
def counter(cls):
print(f"当前统计的老师人数是: {cls.count} 人")

stu1 = Student(“张三”, 18 , “黄土高坡”, “高三 1 班”)
Student.counter()

teacher1 = Teacher(“老王”, 38 , “人民广场”, “教育部”)
teacher2 = Teacher(“老翁”, 39 , “黄浦江”, “教育部”)

面向对象基本概念

类对象、实例对象、类属性、实例属性

teacher3 = Teacher("老李", 40 , "黄浦江", "教导处")
Teacher.counter()
“”"
类, 类对象(通常用大驼峰法命名)
object是所有类的父类, 通常省略不写 """
class Student(object):
school = '深兰教育' # 类属性(类变量)
def __init__(self, name, age):
self.name = name # 实例属性(实例变量)
self.age = age
“”"
魔术方法(特殊方法): 官方定义好的, 以两个下划线开头并且以两个下划
线结尾的方法
魔术方法特点: 一般不需要主动调用, 在满足特定条件时, 会被自动调用
__new__称为构造方法, 用来创建实例对象, 并返回实例对象
__init__称为初始化方法, 可以对实例对象进行属性定制, 没有返回值

每当实例化时, 先自动调用魔术方法__new__(cls, args,
**kwargs), 把类对象(Student)作为实参传递给cls, 并把实例化时传
入的其他实参(‘张三’, age=28)分别传给
args, **kwargs, 然后
__new__根据cls创建一个实例对象(obj), 并返回该实例对象
(stu1=obj).

再自动调用魔术方法__init__(self, name, age), 把实例对象(obj)
作为实参传递给self, 实例化时传入的其他实参(‘张三’, age=28)分别
传给name, age, 然后__init__再对实例对象(obj)进行属性定制(返回
None, 相当于是对实例对象做inplace操作) “”"
stu1 = Student(‘张三’, age= 28 )
stu2 = Student(‘李四’, 32 )

“”" 调用实例属性: 只能用实例对象调用, 不能用类对象调用 “”"
print(stu1.name)
print(stu2.name)

print(getattr(stu1, ‘age’))
print(getattr(stu1, ‘adres’, ‘该实例属性不存在’))

“”"
调用类属性: 既可以用类对象调用(推荐), 也可以用实例对象调用
注意: 当实例属性和类属性同名时, 实例对象优先调用实例属性
“”"
print(Student.school)
print(stu1.school)  # 本质: type(stu1).school
print(stu2.school)  # 本质: type(stu2).school

print(getattr(Student, ‘school’))
print(getattr(Student, ‘adres’, ‘该类属性不存在’))

“”" 修改实例属性: 只能用实例对象修改 “”"
stu1.age = 29
print(stu1.age)

setattr(stu1, ‘age’, 27 )
print(stu1.age)

“”" 修改类属性: 只能用类对象修改 “”"
Student.school = ‘深兰大学’
print(Student.school)

setattr(Student, ‘school’, ‘深兰教育’)
print(Student.school)

“”"
动态定义实例属性: 当实例对象修改的属性不存在时, 则新增该实例属性
“”"
stu1.school = ‘ShenLanEdu’
print(stu1.school)  # 给stu1新增一个实例属性
print(Student.school)  # 类属性不变

setattr(stu2, ‘adres’, ‘威宁路’)
print(stu2.adres)  # 给stu2新增一个实例属性

“”" 动态定义类属性: 当类对象修改的属性不存在时, 则新增该类属性
“”"
Student.subject = ‘AI’
print(Student.subject)  # 新增一个类属性
print(stu1.subject)
print(stu2.subject)

setattr(Student, ‘course’, ‘人工智能’)
print(Student.course)  # 新增一个类属性
print(stu1.course)
print(stu2.course)

“”" 删除属性: 可以用del语句 “”"
del stu1.age
delattr(stu1, ‘name’)

与属性操作相关的内置函数

delattr(object, name)

删除 object 的 name 属性(name 参数为字符串)

del Student.school
delattr(Student, 'subject')
""" 判定属性是否存在 """
print(hasattr(Student, 'school'))
print(hasattr(stu1, 'name'))
print(hasattr(stu2, 'age'))
class Person:
eat = "rice"
def __init__(self, age):
self.age = age
p = Person( 18 )
print(Person.eat)
""" 等价于 del Person.eat """
delattr(Person, "eat")  # 删除类属性eat
print(Person.eat)
print(p.age)
""" 等价于 del p.eat """
delattr(p, "age")  # 删除实例属性age
print(p.age)

getattr(object, name[, default])

返回 object 对象的 name 属性值(name 参数为字符串)

如果 name 属性不存在,且提供了 default 值,则返回它,否则触发

AttributeError

hasattr(object, name)

判断 object 对象是否包含 name 属性(name 参数为字符串),返回

True 或 False

此功能是通过调用 getattr(object, name) 看是否有 AttributeError 异常

来实现的

class Person:
eat = "rice"
def __init__(self, age):
self.age = age
p = Person( 18 )
""" 等价于 Person.eat """
print(getattr(Person, "eat"))
""" 等价于 p.age """
print(getattr(p, "age"))
print(getattr(p, "height", 178 ))
# print(getattr(p, "height"))

setattr(object, name, value)

将 object 的 name 属性设置为 value,属性不存在则新增属性(name

参数为字符串)

class Person:
eat = "rice"
def __init__(self, age):
self.age = age
p = Person( 18 )
print(hasattr(Person, "eat"))  # True
print(hasattr(p, "eat"))  # True
print(hasattr(p, "age"))  # True
print(hasattr(p, "height"))  # False
class Person:
eat = "rice"
def __init__(self, age):
self.age = age
p = Person( 18 )
setattr(Person, "eat", "noodles")
print(Person.eat)
setattr(Person, "drink", "water")
print(Person.drink)
setattr(p, "age", 29 )
print(p.age)

类方法、对象方法、静态方法

通常把定义在类中的函数叫方法(method)

对象方法隐式的接收了 self 参数,类方法隐式的接收了 cls 参数

setattr(p, "height", 178 )
print(p.height)
class Student:
school = '深兰教育'
def __init__(self, name):
self.name = name
def study(self, course):
print(f'{self.name}在学习{course}课!')
@classmethod # 类方法装饰器
def study(cls, course):
print(f'{cls.school}的学生在学习{course}课!')
print(f'{Student.school}的学生在学习{course}课!')
@staticmethod # 静态方法装饰器
def study(course):
print(f'{Student.school}的学生在学习{course}课!')
stu1 = Student('张三')
stu2 = Student('李四')
"""

思考:静态方法、类方法有什么区别?

调用对象方法: 通常用实例对象去调用, 用类对象调用时需要主动给self
传实参 “”"
stu1.study(‘Python’)
stu2.study(‘机器学习’)
Student.study(stu1, ‘Python’)  # 不推荐
Student.study(stu2, ‘机器学习’)  # 不推荐

“”" 调用类方法: 既可以用类对象调用(推荐), 也可以用实例对象调用
“”"
Student.study(‘Python’)
stu1.study(‘Python’)  # 本质: type(stu1).study(‘公开’)
stu2.study(‘Python’)  # 本质: type(stu1).study(‘公开’)

“”" 调用静态方法: 既可以用类对象调用(推荐), 也可以用实例对象调用
“”"
Student.study(‘Python’)
stu1.study(‘Python’)
stu2.study(‘Python’)

class A:

var1 = 123

@classmethod
def func1(cls):
print(cls.var1)

@staticmethod
def func2():
print(A.var1)

面向对象三大特性

封装

在属性名或方法名前面加两个下划线开头, 声明为私有属性或私有方法

私有属性或私有方法只能在该类的内部调用, 不能在类的外部直接调用

可以提供一个非私有方法在类的外部间接访问私有属性或私有方法

就算是继承关系,子类也无法直接访问父类的私有属性和私有方法

class B(A):
var1 = 321
A.func1()
A.func2()
B.func1()
B.func2()
class Person:
def __init__(self, name, age):
self.__name = name # 私有属性
if age <= 0 :
self.__age = "年龄必须大于0" # 私有属性
else:
self.__age = age # 私有属性
# 利用非私有方法访问私有属性

def show_info(self):
print(f"姓名:{self.__name}\n年龄:{self.__age}")

# 私有方法

def __sleep(self):
print(“我要睡觉了, 晚安!”)

利用非私有方法调用私有方法

def sleep(self):
self.__sleep()

# 私有属性或私有方法只能在该类的内部调用

ps = Person(“赵六”, 26 )
ps.show_info()
ps.sleep()

不能在类的外部直接调用

print(ps.__name)
print(ps.__age)
ps.__sleep()

class Person:

__school = “调用__school成功” # 私有属性
school = “调用school成功” # 非私有属性

def __sleep(self):  # 私有方法
print(“调用__sleep成功”)

def sleep(self):  # 非私有方法
print(“调用sleep成功”)

class Student(Person):
pass

stu = Student()
print(Student.school)
stu.sleep()  # 非私有方法在类的外部间接调用私有方法

就算是继承关系,子类也无法直接访问父类的私有属性和私有方法

print(Student.__school)
stu.__sleep()

class A:

def __func(self):
print(‘执行func’)

def call_func(self):
self.__func()

class B(A):
pass

b = B()

子类调用父类的非私有方法, 间接调用父类的私有方法

b.call_func()

继承

所有的类都默认继承 object,只是一般不用写出来

子类继承父类后,会拥有父类中所有的非私有属性和方法

继承的作用:从子类来看,继承可以简化代码;从父类来看,子类是

对父类功能的扩充

单继承

# class A(object) 每一个类默认继承 class object
class A:
pass
# class B(A, object) 每一个类默认继承 class object
class B(A):
pass
class Person:
state = "China"
def eat(self):
print('吃饭')
def speak(self):
print('说话')
class Student(Person):
def study(self):
print('读书')

class Worker(Person):

def work(self):
print(‘搬砖’)

stu = Student()
print(Student.state)  # 子类调用父类的属性
stu.study()  # 子类调用自己的方法
stu.eat()  # 子类调用父类的方法
stu.speak()  # 子类调用父类的方法

wk = Worker()
print(Worker.state)
wk.work()  # 子类调用自己的方法
wk.eat()  # 子类调用父类的方法
wk.speak()  # 子类调用父类的方法

class Animal:
def eat(self):
print(‘吃东西’)

class Cat(Animal):
def catch_mouse(self):
print(‘抓老鼠’)

class Ragdoll(Cat):
def cute(self):
print(‘卖萌’)

c1 = Ragdoll()
c1.cute()  # 子类调用自己的方法

多重继承

继承顺序

单继承查找顺序:先找自己的,再去找父类,再去找父类的父类,依

此类推

多重继承查找顺序:先找自己的,再按照从左往右的顺序依次找父类

当继承比较复杂时,可以使用__mro__属性查看搜索顺序

c1.catch_mouse()  # 子类调用父类的方法
c1.eat()  # 子类调用父类的父类的方法
class Animal:
def eat(self):
print('吃东西')
class Cat:
def catch_mouse(self):
print('抓老鼠')
class Ragdoll(Cat, Animal):  # 继承多个父类
def cute(self):
print('卖萌')
c1 = Ragdoll()
c1.cute()  # 子类调用自己的方法
c1.catch_mouse()  # 子类调用Cat父类的方法
c1.eat()  # 子类调用Animal父类的方法

class A:
a = 1
def pr(self):
print(‘A’)

class B(A):
def pr(self):
print(‘B’)

class C(B):
a = 3
def pr(self):
print(‘C’)

class D(B):
pass

c = C()
c.pr()
print(c.a)

d = D()
d.pr()
print(d.a)

class Biology:

def eat(self):
print(“Biology吃东西”)

class Animal:

方法重写

在继承中,当父类方法的功能不能满足需求时,可以在子类重写父类

的方法

def sleep(self):
print("Animal睡觉")
def cute(self):
print("Animal卖萌")
class Cat:
def sleep(self):
print("Cat睡觉")
class Ragdoll(Cat, Animal, Biology):
pass
rd = Ragdoll()
rd.eat()
rd.sleep()
rd.cute()
class Animal:
def __init__(self, food):
self.food = food
def eat(self):

super()

super是内置的类, 可以调用指定类的父类(超类)

适用场景:在子类重写父类方法后,想再使用父类的该方法

print(f"动物吃{self.food}")
class Cat(Animal):
# 为了实现'猫吃鱼'的功能, 而不是父类的'动物吃鱼', 子类对eat
方法重写
def eat(self):
print(f"猫吃{self.food}")
c = Cat("鱼")  # 实例化, 调用父类的初始化方法
c.eat()
class Animal:
def eat(self):
print("吃东西")
class Cat(Animal):
def eat(self):
print("吃鱼")
class Ragdoll(Cat):

继承中的 init 方法

def eat(self):
print("喝咖啡")
rd = Ragdoll()
rd.eat()  # rd调用Ragdoll类中的对象方法
super(Ragdoll, rd).eat()  # rd调用Ragdoll父类的对象方法
super(Cat, rd).eat()  # rd调用Cat父类的对象方法
c = Cat()
c.eat()  # c调用Cat类中的对象方法
super(Cat, c).eat()  # c调用Cat父类的对象方法
class A:
def __init__(self, name):
self.name = name
self.Q()
def E(self):
print('E方法被调用')
def Q(self):
print(self.name, 'Q方法被调用')
class B(A):
pass

b = B(‘张三’)  # 实例化,调用初始化方法,B没有则调用父类中的初始
化方法,初始化方法中调用了Q方法
b.E()  # 调用父类的E方法
b.Q()  # 调用父类的Q方法

class C(A):

def init(self, name):
self.names = name

c = C(‘赵六’)  # 实例化, 优先调用C中初始化方法

‘’’ 虽然可以调用父类的Q方法, 但是因为Q方法中的self.name没有定
义, 因为A的初始化方法没有被调用, 所以报错
解决方案: 先通过c调用一次A的初始化方法 或者 把C类中的self.names
改为self.name ‘’’

c.Q() # 报错

class D(A):

def init(self, name):
super(D, self).init(‘李四’)
self.name = name

d = D(‘王五’)  # 实例化, 先调用D的初始化方法, super方法调用父
类的初始化方法, 父类的初始化方法中调用Q方法
d.Q()  # 调用父类的Q方法

与继承相关的两个内置函数

isinstance(object, classinfo)

object:实例对象

classinfo:类名、基本类型或者由它们组成的元组

如果 object 是 classinfo 的实例或者是其子类的实例,则返回 True

如果 object 不是给定类型的对象,则返回 False

如果 classinfo 是类型对象元组,那么如果 object 是其中任何一个类型

的实例或其子类的实例,就返回 True

如果 classinfo 既不是类型,也不是类型元组或类型元组的元组,则将

引发 TypeError 异常

issubclass(class, classinfo)

class A:
pass
class B(A):
pass
class C(A):
pass
a = A()
b = B()
c = C()
print(isinstance(a, A))  # True
print(type(a) == A)  # True
print(isinstance(b, A))  # True,考虑继承
print(type(b) == A)  # False,type不考虑继承
print(isinstance(c, A))  # True,考虑继承
print(type(c) == A)  # False,type不考虑继承
print(isinstance(c, (B, A)))  # True,c是A子类的实例

如果 class 是 classinfo 的子类则返回 True

类会被视作其自身的子类

classinfo 也可以是类对象的元组,只要 class 是其中任何一个类型的

子类,就返回 True

多态性

多态性是指具有不同内容的方法可以使用相同的方法名,则可以用一

个方法名调用不同内容的方法

class A:
pass
class B(A):
pass
class C(A):
pass
print(issubclass(B, A))  # True
print(issubclass(C, A))  # True
print(issubclass(A, A))  # True,类会被视作其自身的子类
print(issubclass(C, (B, A)))  # True
class Apple:
def change(self):
return '啊~ 我变成了苹果汁!'
class Banana:
def change(self):

return ‘啊~ 我变成了香蕉汁!’

class Mango:
def change(self):
return ‘啊~ 我变成了芒果汁!’

class Juicer:
def work(self, fruit):
print(fruit.change())

“”"
三个内容不同的change方法使用相同的名字命名,
只要改变change的调用对象, 就可以调用不同内容的方法
“”"
a = Apple()
b = Banana()
m = Mango()
j = Juicer()
j.work(a)
j.work(b)
j.work(m)

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值