学习目标:
- 知道私有权限和公有权限的区别
- 知道继承的作用
- 掌握继承的使用,例如:语法格式,单继承、多层继承、多继承
- 知道使用super()能够调用父类的同名方法
- 知道类属性和实例属性的区别
- 知道类方法、实例方法、静态方法的区别
01_私有权限
学习目标:
- 知道私有权限和公有权限的区别
1.1 面向对象的特性
-
面向对象的的三大特性:封装、继承、多态
-
面向对象的封装特性:
- 将属性和方法放到一起封装成一个整体,然后通过实例化对象来处理
- 对类的属性和方法增加访问权限控制
1.2 私有属性
-
如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性
-
私有属性只能在类的内部访问
"""
私有属性:
1. __(2个下划线)开头的属性,就是私有属性
2. 只能在本类的内部访问,在类的外面无法直接访问
"""
class Dog(object):
# 添加属性
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1 # 公有属性
def print_info(self):
print(self.__baby_count)
# 类的外部
# 创建对象
dog1 = Dog()
# print(dog1.__baby_count) # err, 私有属性,在类的外面无法直接访问
print(dog1.age)
dog1.print_info()
1.3 私有方法
-
私有方法和私有属性类似,在方法名前面加了2个下划线'__',则表明该方法是私有方法
-
私有方法只能在类内部使用
"""
私有方法:
1. __(2个下划线)开头的方法,就是私有方法
2. 只能在本类的内部访问,在类的外面无法直接访问
3. 在类的内部调用实例方法的语法格式:self.方法名()
"""
class Dog(object):
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1
def print_info(self):
print(self.__baby_count)
self.__leave()
# 定义一个私有方法
def __leave(self):
print('休产假了')
dog1 = Dog()
dog1.print_info()
# AttributeError: 'Dog' object has no attribute '__leave'
# dog1.__leave() # err, 外部不能访问私有方法
面向对象的的三大特性:封装、继承、多态
面向对象的封装特性:
- 将属性和方法放到一起封装成一个整体,然后通过实例化对象来处理
- 对类的属性和方法增加访问权限控制
-
如果在属性名前面加了2个下划线'__',则表明该属性是私有属性,否则为公有属性
-
私有属性只能在类的内部访问
"""
私有属性:
1. __(2个下划线)开头的属性,就是私有属性
2. 只能在本类的内部访问,在类的外面无法直接访问
"""
class Dog(object):
# 添加属性
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1 # 公有属性
def print_info(self):
print(self.__baby_count)
# 类的外部
# 创建对象
dog1 = Dog()
# print(dog1.__baby_count) # err, 私有属性,在类的外面无法直接访问
print(dog1.age)
dog1.print_info()
1.3 私有方法
-
私有方法和私有属性类似,在方法名前面加了2个下划线'__',则表明该方法是私有方法
-
私有方法只能在类内部使用
"""
私有方法:
1. __(2个下划线)开头的方法,就是私有方法
2. 只能在本类的内部访问,在类的外面无法直接访问
3. 在类的内部调用实例方法的语法格式:self.方法名()
"""
class Dog(object):
def __init__(self):
self.__baby_count = 0 # 私有属性,以__(2个下划线)开头的属性
self.age = 1
def print_info(self):
print(self.__baby_count)
self.__leave()
# 定义一个私有方法
def __leave(self):
print('休产假了')
dog1 = Dog()
dog1.print_info()
# AttributeError: 'Dog' object has no attribute '__leave'
# dog1.__leave() # err, 外部不能访问私有方法
私有方法和私有属性类似,在方法名前面加了2个下划线'__',则表明该方法是私有方法
私有方法只能在类内部使用
【附】类定义时私有属性/私有方法的本质[了解]
(1) Python解释器将私有属性名/私有方法名进行的转换,转换的格式为:`_类名__属性名`或`_类名__方法名`
(2) 在类的外部直接通过原私有属性/私有方法是访问不到的,但是通过转换后的名称可以进行访问[不推荐使用]
02_继承介绍
学习目标:
- 知道继承的作用
- 知道继承的语法格式
2.1 继承的概念
2.1.1 生活中的继承
在现实生活中,继承一般指的是子女继承父辈的财产
2.1.2 程序中的继承
在程序中,继承描述的是指的是类与类之间的关系,如下如所示:
- 站在父类的角度来看,父类派生出子类
- 站在子类的角度来看,子类继承于父类
- 父类也叫基类,子类也叫派生类
2.2 继承的作用
- 继承:子类直接具备父类的能力(属性和方法)
- 作用:解决代码重用问题,提高开发效率
2.3 继承的语法格式
继承的语法格式:
class 子类名(父类名):
pass
示例代码:
# 定义一个父类
class Father(object):
# 添加一个属性, money
def __init__(self):
self.money = 9999999
def print_info(self):
print(self.money)
# 定义一个子类,继承与Father
class Son(Father):
pass
# 子类创建对象
s = Son()
print(s.money) # 子类私用继承过来的属性
s.print_info() # 子类使用继承过来的方法
注意:
- 子类对象调用方法有一个就近原则
- 如果本类能找到方法,直接调用本类的方法
- 如果本类找不到,则调用父类继承过来的方法
03_单继承和多层继承
学习目标:
- 知道单继承和多层继承的特点
3.1 单继承
- 单继承:子类只继承一个父类
# 定义一个父类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个子类,只有一个父类
class Dog(Animal):
pass
# 创建一个子类对象
dog1 = Dog()
dog1.eat()
3.2 多层继承
- 多层继承:继承关系为多层传递,如生活中的爷爷、父亲、儿子
# 定义一个爷爷类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个父亲类
class Dog(Animal):
def drink(self):
print('喝东西')
# 定义一个儿子类
class SuperDog(Dog):
pass
# 创建对象
sd = SuperDog()
sd.eat()
sd.drink()
- 多层继承:继承关系为多层传递,如生活中的爷爷、父亲、儿子
# 定义一个爷爷类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个父亲类
class Dog(Animal):
def drink(self):
print('喝东西')
# 定义一个儿子类
class SuperDog(Dog):
pass
# 创建对象
sd = SuperDog()
sd.eat()
sd.drink()
04_重写父类方法
学习目标:
- 知道使用super()能够调用父类的同名方法
4.1 子类重写父类同名方法
- 父类的方法不能满足子类的需要,可以对父类的方法重写,重写父类方法的目的是为了给他扩展功能,可以对父类(包括爷爷)以上的进行重写
- 在子类中定义了一个和父类同名的方法(参数也一样),即为对父类的方法重写
- 子类调用同名方法,默认只会调用子类的
示例代码1:(狗类)
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
print('Animal类中的__init__')
self.type = '动物'
# 设计一个方法,打印属性
def print_type(self):
print('Animal类中的print_type = ', self.type)
# 定义一个子类,继承与Animal
class Dog(Animal):
# __init__和父类的同名,重写父类同名方法
def __init__(self):
print('Dog类中的__init__')
self.type = '可爱的小狗'
# print_type和父类的同名,重写父类同名方法
def print_type(self):
print('Dog类中的print_type = ', self.type)
# 定义一个子类对象
dog1 = Dog() # 调用子类的__init__
dog1.print_type() # 调用子类的print_type()
运行结果:
Dog类中的__init__ Dog类中的print_type = 可爱的小狗
示例代码2: (支付类)
class PayClass(object):
"""支付类"""
def pay(self):
"""付款方法"""
pass
def refund(self):
"""退款方法"""
pass
class Alipay(PayClass):
"""支付宝支付"""
def pay(self):
"""重写父类中的 pay 方法"""
print('支付宝支付')
def refund(self):
"""重写父类中的 refund 方法"""
print('支付宝退款')
class WeChat(PayClass):
"""微信支付"""
def pay(self):
"""重写父类中的 pay 方法"""
print('微信支付')
def refund(self):
"""重写父类中的 refund 方法"""
print('微信支付退款')
4.2 子类调用父类同名方法
- 子类调用父类同名方法:
- 父类名.同名方法(self, 形参1, ……)
- super(子类名, self).同名方法(形参1, ……)
- super().同名方法(形参1, ……):是方法 2 的简写,推荐的写法
- 父类名.同名方法(self, 形参1, ……)
- super(子类名, self).同名方法(形参1, ……)
- super().同名方法(形参1, ……):是方法 2 的简写,推荐的写法
示例代码:
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
print('Animal类中的__init__')
self.type = '动物'
# 设计一个方法,打印属性
def print_type(self):
print('Animal类中的print_type = ', self.type)
# 定义一个子类,继承与Animal
class Dog(Animal):
# __init__和父类的同名,重写父类同名方法
def __init__(self):
print('Dog类中的__init__')
self.type = '可爱的小狗'
# print_type和父类的同名,重写父类同名方法
def print_type(self):
print('Dog类中的print_type = ', self.type)
print('='*20)
# 调用父类同名函数
# 方法1: 父类名.同名方法(self, 形参1, ……)
Animal.__init__(self)
Animal.print_type(self)
print('=' * 20)
# 方法2:super(子类名, self).同名方法(形参1, ……)
super(Dog, self).__init__()
super(Dog, self).print_type()
print('=' * 20)
# 方法3:super().同名方法(形参1, ……) # 是 4.2 方法的简写
# 推荐使用的方法
super().__init__()
super().print_type()
# 定义一个子类对象
dog1 = Dog() # 调用子类的__init__
dog1.print_type() # 调用子类的print_type()
运行结果:
Dog类中的__init__ Dog类中的print_type = 可爱的小狗 ==================== Animal类中的__init__ Animal类中的print_type = 动物 ==================== Animal类中的__init__ Animal类中的print_type = 动物 ==================== Animal类中的__init__ Animal类中的print_type = 动物
05_多继承
学习目标:
- 知道多继承的特点
5.1 多继承
- 所谓多继承,即子类有多个父类,并且具有它们的特征。
-
多继承的语法格式:
class 子类名(父类1, 父类2, ……):
pass
多继承的语法格式:
class 子类名(父类1, 父类2, ……):
pass
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def drink(self):
print('大口喝水')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat()
sd.drink()
运行结果:
吃小东西 大口喝水
5.2 类的继承顺序
- 查看类的继承顺序:类名.__mro__
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def drink(self):
print('大口喝水')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 查看类的继承顺序
print(SuperDog.__mro__)
运行结果:
(, , , )
5.3 调用父类同名方法
5.3.1 默认调用情况
- 如果继承过来的2个父类的方法同名,默认调用先继承父类的同名方法
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def eat(self):
print('啃大骨头')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat() # 默认先调用先继承的父类,即 SmallDog
- 如果继承过来的2个父类的方法同名,默认调用先继承父类的同名方法
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def eat(self):
print('啃大骨头')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
pass
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat() # 默认先调用先继承的父类,即 SmallDog
运行结果:
吃小东西
5.3.2 子类调用父类同名方法
- 子类调用父类同名方法(3种):
- 父类名.同名方法(self, 形参1, ……):调用指定的父类
- super(类名, self).同名方法(形参1, ……):调用继承顺序中类名的下一个类的同名方法
- super().同名方法(形参1, ……):调用先继承父类的同名方法
- 父类名.同名方法(self, 形参1, ……):调用指定的父类
- super(类名, self).同名方法(形参1, ……):调用继承顺序中类名的下一个类的同名方法
- super().同名方法(形参1, ……):调用先继承父类的同名方法
示例代码:
# 定义2个类,它们没有继承关系,是平级的
class SmallDog(object):
def eat(self):
print('吃小东西')
# 再定义一个类
class BigDog(object):
def eat(self):
print('啃大骨头')
# 定义一个子类,多继承于上面2个父类
class SuperDog(SmallDog, BigDog):
def eat(self):
print('吃蟠桃')
print('='*20)
# 子类调用父类同名方法:
# 1. 父类名.同名方法(self, 形参1, ……)
SmallDog.eat(self) # 调用SmallDog的eat()
print('=' * 20)
# 2. super(类名, self).同名方法(形参1, ……):调用继承顺序中类名的下一个类的同名方法
# 继承顺序中,SmallDog的下一个类是BigDog,所以,调用BigDog的eat()
super(SmallDog, self).eat()
print('=' * 20)
# 3. super().同名方法(形参1, ……) :调用先继承父类的同名方法
super().eat()
# 定义子类对象,调用方法
sd = SuperDog()
sd.eat()
运行结果:
吃蟠桃 ==================== 吃小东西 ==================== 啃大骨头 ==================== 吃小东西
06_私有和继承
学习目标:
- 知道私有方法、属性不能直接继承使用
6.1 私有和继承
- 父类中的私有方法、属性不能直接继承使用
- 可以通过调用继承的父类的共有方法,间接的访问父类的私有方法、属性
# 定义一个父类, Animal
class Animal(object):
# 添加一个type属性
def __init__(self):
self.__type = '动物' # 私有
def __leave(self): # 私有
print('休产假3个月')
# 通过公有方法,间接访问私有元素
def use_private(self):
print(self.__type)
self.__leave()
# 定义一个子类
class Dog(Animal):
def test(self):
# print(self.__type) # err,私有不能直接继承使用
# self.__leave() # err,私有不能直接继承使用
pass
# 创建子类对象
dog1 = Dog()
dog1.use_private()
07_多态
学习目标:
- 知道实现多态的步骤
- 多态:多种形态,调用同一个函数,不同表现
-
因为Python是动态语言,站在用户的角度,本身就是多态,不存在非多态的情况
-
实现多态的步骤:
-
实现继承关系
-
子类重写父类方法
- 通过对象调用该方法
-
示例代码:
"""
1. 多态:多种形态,调用同一个函数,不同表现
2. 实现多态的步骤:
1. 实现继承关系
2. 子类重写父类方法
3. 通过对象调用该方法
"""
# 定义一个父类, Animal
class Animal(object):
def eat(self):
print('吃东西')
# 定义一个子类Dog,继承于Animal
class Dog(Animal):
def eat(self):
"""重写父类方法"""
print('啃骨头')
# 定义一个子类Cat,继承于Animal
class Cat(Animal):
def eat(self):
"""重写父类方法"""
print('吃小鱼')
# 定义一个函数,用于测试多态
def func(temp):
temp.eat()
# 创建子类对象
d = Dog()
c = Cat()
# 调用同一个函数,不同表现
# 传递d参数,调用Dog的eat()
# 传递c参数,调用Cat的eat()
func(d) # 啃骨头
func(c) # 吃小鱼
08_实例属性、类属性
学习目标:
- 知道类属性的定义方式
- 知道类属性和实例属性的区别
8.1 实例属性和类属性
8.1.1 专业名词说明
-
在Python中 "万物皆对象"
-
通过类创建的对象 又称为 实例对象,对象属性 又称为 实例属性
- 类本身也是一个对象,执行class语句时会被创建,称为 类对象,为了和实例对象区分开来,我们习惯叫类
8.1.2 实例属性
-
通过在__init__方法里面给实例对象添加的属性
-
在类的外面,直接通过实例对象添加的属性
-
实例属性必须通过实例对象才能访问
# 定义类
class 类名(object):
def __init__(self):
self.实例属性变量1 = 数值1
self.实例属性变量2 = 数值3
# 创建实例对象
实例对象名 = 类名()
# 添加属性
实例对象名.实例属性变量3 = 数值3
8.1.3 类属性
-
类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
-
定义在类里面,类方法外面的变量就是类属性
-
类属性可以使用 类名 或 实例对象 访问,推荐使用类名访问
# 定义类
class 类名(object):
类属性变量 = 数值1
def __init__(self):
pass
8.1.4 示例代码
class Dog(object):
# 类属性
count = 0
def __init__(self):
# 实例属性
self.name = '大黄狗'
# 类属性同构类名访问,格式:类名.类属性名字
print(Dog.count)
# 创建实例对象
dog1 = Dog()
print(dog1.count) # 实例对象访问类属性
print(dog1.name) # 实例属性
-
在Python中 "万物皆对象"
-
通过类创建的对象 又称为 实例对象,对象属性 又称为 实例属性
- 类本身也是一个对象,执行class语句时会被创建,称为 类对象,为了和实例对象区分开来,我们习惯叫类
8.1.2 实例属性
-
通过在__init__方法里面给实例对象添加的属性
-
在类的外面,直接通过实例对象添加的属性
-
实例属性必须通过实例对象才能访问
# 定义类
class 类名(object):
def __init__(self):
self.实例属性变量1 = 数值1
self.实例属性变量2 = 数值3
# 创建实例对象
实例对象名 = 类名()
# 添加属性
实例对象名.实例属性变量3 = 数值3
8.1.3 类属性
-
类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
-
定义在类里面,类方法外面的变量就是类属性
-
类属性可以使用 类名 或 实例对象 访问,推荐使用类名访问
# 定义类
class 类名(object):
类属性变量 = 数值1
def __init__(self):
pass
8.1.4 示例代码
class Dog(object):
# 类属性
count = 0
def __init__(self):
# 实例属性
self.name = '大黄狗'
# 类属性同构类名访问,格式:类名.类属性名字
print(Dog.count)
# 创建实例对象
dog1 = Dog()
print(dog1.count) # 实例对象访问类属性
print(dog1.name) # 实例属性
通过在__init__方法里面给实例对象添加的属性
在类的外面,直接通过实例对象添加的属性
实例属性必须通过实例对象才能访问
# 定义类
class 类名(object):
def __init__(self):
self.实例属性变量1 = 数值1
self.实例属性变量2 = 数值3
# 创建实例对象
实例对象名 = 类名()
# 添加属性
实例对象名.实例属性变量3 = 数值3
-
类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
-
定义在类里面,类方法外面的变量就是类属性
-
类属性可以使用 类名 或 实例对象 访问,推荐使用类名访问
# 定义类 class 类名(object): 类属性变量 = 数值1 def __init__(self): pass
8.1.4 示例代码
class Dog(object):
# 类属性
count = 0
def __init__(self):
# 实例属性
self.name = '大黄狗'
# 类属性同构类名访问,格式:类名.类属性名字
print(Dog.count)
# 创建实例对象
dog1 = Dog()
print(dog1.count) # 实例对象访问类属性
print(dog1.name) # 实例属性
运行结果:
0 0 大黄狗
8.2 类属性和实例属性的区别
- 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
- 实例属性 要求 每个对象 为其 单独开辟一份内存空间 ,只属于某个实例对象的
示例代码:
"""
1. 定义一个类属性count,用于记录实例对象初始化的次数
2. __init__添加实例属性name,每初始化1次,类属性count加1
"""
class Dog(object):
# 类属性
count = 0
def __init__(self, _name):
# 实例属性
self.name = _name
# 每初始化一次,类属性数量加1
Dog.count += 1
# 打印类属性的值
print(Dog.count)
# 创建1个对象
d1 = Dog('旺财')
# 打印:实例属性,类属性
print(d1.name, Dog.count)
d2 = Dog('旺钱')
print(d2.name, Dog.count)
d3 = Dog('旺仔')
print(d3.name, Dog.count)
# 通过实例对象,访问类属性
print(d1.count, d2.count, d3.count)
运行结果:
0 旺财 1 旺钱 2 旺仔 3 3 3 3
8.3 注意点
8.3.1 修改类属性
- 类属性只能通过类对象修改,不能通过实例对象修改
# 类属性修改,只能通过类名修改,不能通过对象名修改
class Dog(object):
# 类属性
count = 0
# 通过类名修改
Dog.count = 1
print(Dog.count)
print('='*30)
# 对象名.变量 = 数据 默认操作给实例对象添加实例属性,已经不能操作类属性
# 如果类属性名字和实例属性名字相同,实例对象名只能操作实例属性
d1 = Dog()
d1.count = 250
print(Dog.count, d1.count)
- 类属性只能通过类对象修改,不能通过实例对象修改
# 类属性修改,只能通过类名修改,不能通过对象名修改
class Dog(object):
# 类属性
count = 0
# 通过类名修改
Dog.count = 1
print(Dog.count)
print('='*30)
# 对象名.变量 = 数据 默认操作给实例对象添加实例属性,已经不能操作类属性
# 如果类属性名字和实例属性名字相同,实例对象名只能操作实例属性
d1 = Dog()
d1.count = 250
print(Dog.count, d1.count)
运行结果:
1 ============================== 1 250
8.3.2 类属性和实例属性同名
- 如果类属性和实例属性同名,实例对象名只能操作实例属性
- 结论:操作类属性建议使用类名,避免不必要的麻烦
class Dog(object):
# 类属性
count = 666
def __init__(self):
self.count = 250 # 实例属性
# 创建对象
# 如果类属性和实例属性同名,实例对象名只能操作实例属性
d1 = Dog()
print(Dog.count, d1.count)
运行结果:
666 250
8.3.3 私有类属性
-
类属性也可以设置为 私有,前边添加两个下划线__
class Dog(object):
# 类属性
__count = 0
print(Dog.__count) # 类的外面,不能直接访问私有类属性,err
类属性也可以设置为 私有,前边添加两个下划线__
class Dog(object):
# 类属性
__count = 0
print(Dog.__count) # 类的外面,不能直接访问私有类属性,err 09_类方法、静态方法
学习目标:
- 知道类方法、实例方法、静态方法的区别
9.1 类方法
- 类对象所拥有的方法,主要为了在没有创建实例对象前提下,处理类属性
- 需要用装饰器@classmethod来标识其为类方法
- 对于类方法,第一个参数必须是类对象(代表类),一般以cls作为第一个参数,这个参数不用人为传参,解释器会自动处理
"""
类方法:为了方便处理类属性
1. 用装饰器 @classmethod 来标识其为类方法
2. 一般以 cls 作为第一个参数,代表当前这个类,这个参数不用人为传参,解释器会自动处理
3. 类方法调用:
3.1 类名.类方法() 推荐用法
3.2 实例对象名.类方法()
"""
class Dog(object):
# 类属性
count = 0
# 定义类方法
@classmethod
def print_num(cls): # 参数cls代表当前的类
# print('count = ', Dog.count)
print('count = ', cls.count)
# 调用类方法
Dog.print_num()
9.2 静态方法
- 需要通过装饰器@staticmethod来进行修饰,静态方法默认情况下, 既不传递类对象也不传递实例对象(形参没有self/cls)。
- 当方法中 既不需要使用实例对象,也不需要使用类对象时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
- 静态方法 也能够通过 实例对象 和 类对象(类名) 去访问。
"""
静态方法:
1. 需要通过装饰器@staticmethod来进行修饰默认情况下
2. 既不传递类对象也不传递实例对象(形参没有self/cls)
3. 静态方法调用:
3.1 类名.静态方法() 推荐用法
3.2 实例对象名.静态方法()
"""
class Dog(object):
# 定义静态方法
@staticmethod
def normal_func():
print('一个和实例属性、类属性没有关系的普通方法')
# 调用静态方法
Dog.normal_func()
面向对象(下)——练习题
- 需要通过装饰器@staticmethod来进行修饰,静态方法默认情况下, 既不传递类对象也不传递实例对象(形参没有self/cls)。
- 当方法中 既不需要使用实例对象,也不需要使用类对象时,定义静态方法
- 取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
- 静态方法 也能够通过 实例对象 和 类对象(类名) 去访问。
"""
静态方法:
1. 需要通过装饰器@staticmethod来进行修饰默认情况下
2. 既不传递类对象也不传递实例对象(形参没有self/cls)
3. 静态方法调用:
3.1 类名.静态方法() 推荐用法
3.2 实例对象名.静态方法()
"""
class Dog(object):
# 定义静态方法
@staticmethod
def normal_func():
print('一个和实例属性、类属性没有关系的普通方法')
# 调用静态方法
Dog.normal_func()
能力目标:
- 知道公有权限和私有权限的区别
- 知道继承的作用
- 知道子类重写父类方法的原因
- 知道使用super()能够调用父类的同名方法
- 知道多继承和多层继承的区别
- 知道多态的好处
- 知道类属性的定义方式
- 知道类属性和实例属性的区别
- 使用@classmethod定义类方法
- 使用@staticmethod定义静态方法
按步骤实现如下需求:
1.1 定义一个人的基类,类中要有初始化方法,方法中初始化人的姓名,年龄.
答案
class People(object): def __init__(self,_name,_age): self.name = _name self.age = _age
1.2 提供__str__方法,返回姓名和年龄信息
答案
def __str__(self):
return f'我的姓名是{self.name},我今年{self.age}岁了'
1.3 将类中的姓名和年龄属性私有化.
答案
def __init__(self,_name,_age): self.__name = _name self.__age = _age
1.4 提供获取私有属性的方法.
答案
def get_name(self):
return self.__name
def get_age(self):
return self.__age
1.5 提供可以设置私有属性的方法.、
答案
def set_name(self,new_name): self.__name = new_name def set_age(self,new_age): self.__age = new_age
1.6 设置年龄时限制范围(0-100).
答案
def set_age(self,new_age):
if 0 < new_age < 100:
self.__age = new_age
else:
print('年龄不符合要求,必须要在0-100之内')
2. 继承
2.1 继承有什么好处? 答案
继承可以让子类直接使用父类的属性和方法,解决代码重用的问题,提高开发效率
2.2 请写出继承的语法格式。 答案
class 子类名(父类名): pass
2.3 请写出一个Car作为基类,BMW类继承于Car类,基类中有init方法(包含name,color).
创建Car和BMW的实例对象, 并分别打印对象的2个属性值 答案
class Car(object):
def __init__(self,_name,_color):
self.name = _name
self.color = _color
def __str__(self):
return f'我的名字是{self.name},我的颜色是{self.color}'
class BMW(Car):
pass
c1 = Car('雷克萨斯','银色')
print(c1)
b2 = BMW('宝马','紫色')
print(b2)
2.4 利用继承编写下面一段代码
要求:
运行结果:
喵喵 花猫drink 旺旺
答案
class Animal(object):
def eat(self):
print(f'{self.name}eat')
def drink(self):
print(f'{self.name}drink')
def run(self):
print(f'{self.name}run')
def cry(self):
print(f'{self.name}say')
class Cat(Animal):
def __init__(self,_name):
self.name = _name
def cry(self):
print('喵喵')
class Dog(Animal):
def __init__(self,_name):
self.name = _name
def cry(self):
print('旺旺')
c1 = Cat('猫')
c1.cry()
c2 = Cat('花猫')
c2.drink()
d1 = Dog('狗')
d1.cry()
-
动物:吃,喝,跑,叫
-
猫的叫声是"喵喵"
-
狗的叫声是"旺旺"
-
猫狗继承于动物,并且有猫、狗有自己的属性.
3.1 如果子类中没有定义init方法,但是要实例化一个对象,那此时会调用父类的init方法吗? 答案
会,子类没有的功能会跟父类要,如果父类也没有则会导致报错
3.2 如果子类重写了init方法,那么在实例化对象的时候,你觉得会调用哪个init方法,是父类的还是子类的? 答案
会调用子类的,当子类重写了父类方法,则默认调用子类的方法
3.3 当子类重写init方法,在实例化对象的时候,如果想要调用父类的init方法该怎么办? 答案
方法1: 父类名.方法名(self,参数列表) 方法2: super(子类名,self).方法名(参数列表) 方法3: super().方法名(参数列表)
3.4 创建一个动物类,其中有一个run方法
创建一个Cat类继承于动物类,Cat类中重写run方法,增加打印"迈着猫步跑起来",同时实现eat方法
运行结果:
跑起来 迈着猫步跑起来 吃东西
训练提示
-
继承父类
-
重写父类方法
-
使用super方法调用父类方法
答案
方法一:
class Animal(object):
def run(self):
print('跑起来')
def eat(self):
print('吃东西')
class Cat(Animal):
def run(self):
super(Cat,self).run()
print('迈着猫步跑起来')
Animal.eat(self)
c = Cat()
c.run()
方法二:
class Animal(object):
def run(self):
print("跑起来")
class Cat(Animal):
def run(self):
super(Cat, self).run()
# 简写形式
# super().run()
print("迈着猫步跑起来")
def eat(self):
print("吃东西")
c = Cat()
c.run()
c.eat()
4. 私有与继承
4.1 父类中的私有属性能被子类继承吗,子类能直接使用父类的私有属性吗? 答案
父类中的私有方法、属性,不会被子类继承; 不能,可以通过调用继承的父类的共有方法,间接的访问父类的私有方法、属性
4.2 定义一个类,提供可以重新设置私有属性name的方法,限制条件为字符串长度小于10,才可以修改.
训练提示
-
定义私有属性
-
私有属性修改需要在本类中定义对应的方法修改属性
答案
class Father(object): def __init__(self,_name): self.__name = _name def get_name(self,new_name): if len(self.__name) < 10: self.__name = new_name
4.3 编写一段代码以完成下面的要求
要求:
-
定义一个人的基类,类中要有初始化方法,方法中要有人的姓名,年龄.
-
将类中的姓名和年龄私有化.
-
提供获取用户信息的函数.
-
提供获取私有属性的方法.
-
提供可以设置私有属性的函数.
-
设置年龄的范围(0-100).若设置的范围有误,则打印“输入的年龄错误!”
运行结果:
张三:20 张三:30 李四:30
答案
class People(object):
def __init__(self,_name,_age):
self.__name = _name
self.__age = _age
def __str__(self):
return f'{self.__name}:{self.__age}'
def get_name(self):
return self.__name
def get_age(self):
return self.__age
def set_name(self,new_name):
self.__name = new_name
def set_age(self,new_age):
if 0 < new_age < 100:
self.__age = new_age
print(self.__age)
else:
print('输入的年龄错误')
p1 = People('张三',20)
print(p1)
p2 = People('张三',30)
print(p2)
p3 = People('李四',30)
print(p3)
5. 多继承
写出一个简单的多继承案例,并使用子类对象调用所有的父类方法。比如 LuoZi 类同时继承 Ma类、Lv类。 答案
class Ma(object):
def run(self):
print('马跑得快')
class Lv(object):
def walk(self):
print('驴走得远')
class LuoZi(Ma,Lv):
pass
b1 = LuoZi()
b1.run()
b1.walk()
6. 多态
6.1 面向对象开发的三个基本特征是什么?
答案
面向对象三大特性:封装继承多态 封装:将事物抽象成一个类,区分出属性和方法,并提供权限控制 继承:继承一个父类,获得父类的公有的方法和属性.作用是:可以提高代码的复用性 多态:传入不同的对象,调用同名方法,执行不同的效果(核心是方法同名).作用是:方便程序的功能扩展 Python的多态和其他语言不一样: 其他语言, 必须有继承必须有重写, 才能实现多态. 因为其他语言对数据类型有严格的要求, 定义参数时, 会指明参数的类型. 如果不是同一个类或者子类, 那么无法传入. Python只要不同的类方法同名即可实现
6.2 按如下要求实现代码:
-
创建一个动物的基类,其中有一个run方法
-
创建一个Cat类继承于动物类,具有私有属性__name = "波斯猫"
-
创建一个Dog类继承于动物类,具有私有属性__name = "京巴狗"
-
Cat类中不仅有run方法还有eat方法
-
Dog类中方法同上
-
创建一个letRun函数,可以接收动物及其子类对象,并调用run方法 class Cat(Animal):
-
编写测试代码以验证功能正常
-
运行结果:
跑起来 波斯猫在跑 波斯猫在吃 京巴狗在跑 京巴狗在吃
答案
class Animal(object):
def run(self):
print('跑起来')
class Cat(Animal):
def __init__(self):
self.__name = '波斯猫'
def run(self):
print(f'{self.__name}在跑')
def eat(self):
print(f'{self.__name}在吃')
class Dog(Animal):
def __init__(self):
self.__name = '京巴狗'
def run(self):
print(f'{self.__name}在跑')
def eat(self):
print(f'{self.__name}在吃')
def letRun(animal):
animal.run()
animal = Animal()
letRun(animal)
cat = Cat()
letRun(cat)
cat.eat()
dog = Dog()
letRun(dog)
dog.eat()
7. 类属性 实例属性
什么是类属性?什么是实例属性?两者的 区别是?
答案
8. 类方法、静态方法类属性就是类对象所拥有的属性,它被该类的所有实例对象所拥有的 实例属性就是实例对象的属性 实例属性要求每个对象为其单独开辟一份内存空间来记录数据,而类属性为全类所共有,仅占用一份内存,更加节省内存空间
8.1 定义类方法的格式是什么?对于类方法的参数有什么要求? 调用类方法的格式是什么?
答案
class Test(object):
@classmethod
def func(cls):
print('类方法上必须要写@classmethod,第一个形参必须是类对象')
# 类方法的第一个形参必须是类对象
# 调用格式: 类对象.类方法()
8.2 定义静态方法的格式是什么? 对于静态方法的参数有什么要求?调用静态方法的格式是什么?
答案
class Test(object):
@staticmethod
def func(cls):
print('静态方法上必须要写@staticmethod,没有强制性的形参')
# 静态方法没有强制性的形参
# 调用格式: 类对象.静态方法()
8.3 按如下要求实现代码
定义一个Animal类(动物类),拥有 • 公有类属性name"动物大家族" • 私有类属性leg"四条腿" 定义类Cat(),继承自Animal。 初始化名字为波斯猫 • 定义方法play,打印“xxx在玩耍” xxx表示名字 • 增加静态方法run,打印“动物们跑起来了” • 增加类方法eat,打印“xxx在吃饭” 打印cat对象的name
答案
class Animal():
name = '动物大家族'
__leg = '四条腿'
class Cat(Animal):
def __init__(self,_name):
self.name = _name
def play(self):
print(f'{self.name}在玩耍')
@staticmethod
def run():
print('动物们跑起来了')
@classmethod
def eat(cls):
print(f'{cls.name}在吃饭')
c = Cat('波斯猫')
c.play()
c.run()
c.eat()
print(c.name)



