一、封装
什么是封装
在日常中封装指的是将我们的物品包裹起来,不让看到其内部,具有保护的功能。在程序设计中,封装(Encapsulation)是将类中的某些部分(某些属性或者方法)隐藏起来,对象不能直接使用隐藏起来的属性或者方法,具有保护功能。
私有属性封装
格式:_属性名
示例
# 封装:私有属性
# class Car():
#
# def __init__(self, name, color):
# self._name = name # 私有属性
# self.color = color
#
# def run(self):
# print('汽车开始跑起来了')
#
# def dididi(self):
# print('汽车鸣笛了')
#
#
# car = Car('法拉利', '红色')
# car._name = '中华田园犬'
# car.run()
# car.dididi()
# print(car._name)
运行结果
汽车开始跑起来了
汽车鸣笛了
中华田园犬
注意:
这种方法只是一种行业规定,表明这个属性不要被轻易更改,但是它还是能被更改
隐藏属性
格式:__属性名
示例
# 封装:隐藏属性
# class Car():
#
# def __init__(self, name, color):
# self.__name = name # 隐藏属性 不可读的属性
# self.color = color
#
# def run(self):
# print('汽车开始跑起来了')
#
# def dididi(self):
# print('汽车鸣笛了')
#
#
# car = Car('法拉利', '红色')
# car.__name = '中华田园犬'
# car.run()
# car.dididi()
运行结果
C:\Users\Lenovo\AppData\Local\Programs\Python\Python37\python.exe F:/桌面/day13/封装一.py
Traceback (most recent call last):
File "F:/桌面/day13/封装一.py", line 60, in <module>
print(car.__name)
AttributeError: 'Car' object has no attribute '__name'
进程已结束,退出代码为 1
可以看出程序报错无法访问
但是真的能完全无法访问吗?
其实隐藏属性只不过是Python自动为属性改了一个名字 --> _类名__属性名 例如
class Car():
def __init__(self, name, color):
self.__name = name # 隐藏属性 不可读的属性
self.color = color
def run(self):
print('汽车开始跑起来了')
def dididi(self):
print('汽车鸣笛了')
car = Car('法拉利', '红色')
print(car._Car__name)
运行结果
C:\Users\Lenovo\AppData\Local\Programs\Python\Python37\python.exe F:/桌面/day13/封装一.py
法拉利
进程已结束,退出代码为 0
我们也可以提供给一个getter()和setter()方法是外部可以访问到属性
• getter() 获取对象中指定的属性
• setter() 用来设置对象指定的属性
示例
class Car():
def __init__(self, name, color):
self._name = name # 隐藏属性 不可读的属性
self.color = color
# getter方法 提供给你访问这个属性的方法
def get_name(self):
return self._name
# setter方法 提供给你修改这个属性的方法
def set_name(self, name):
self._name = name
def run(self):
print('汽车开始跑起来了')
def dididi(self):
print('汽车鸣笛了')
car = Car('法拉利', '红色')
print(car.get_name())
car.set_name('玛莎拉蒂')
print(car.get_name())
运行结果
C:\Users\Lenovo\AppData\Local\Programs\Python\Python37\python.exe F:/桌面/day13/封装二.py
汽车开始跑起来了
汽车鸣笛了
法拉利
玛莎拉蒂
进程已结束,退出代码为 0
二、property装饰器
Python 还提供了 @property 装饰器。通过 @property 装饰器,可以直接通过方法名来访问方法,不需要在方法名后添加一对“()”小括号。
@property 的语法格式如下:
@property
def 方法名(self)
代码块
例如,定义一个矩形类,并定义用 @property 修饰的方法操作类中的 area 私有属性,代码如下:
class Rect:
def __init__(self,area):
self.__area = area
@property
def area(self):
return self.__area
rect = Rect(30)
#直接通过方法名来访问 area 方法
print("矩形的面积是:",rect.area)
上面程序中,使用 @property 修饰了 area() 方法,这样就使得该方法变成了 area 属性的 getter 方法。需要注意的是,如果类中只包含该方法,那么 area 属性将是一个只读属性。
也就是说,在使用 Rect 类时,无法对 area 属性重新赋值
而要想实现修改 area 属性的值,还需要为 area 属性添加 setter 方法,就需要用到 setter 装饰器,它的语法格式如下:
@方法名.setter
def 方法名(self, value):
代码块
例如,为 Rect 类中的 area 方法添加 setter 方法,代码如下:
@area.setter
def area(self, value):
self.__area = value
这样,area 属性就有了 getter 和 setter 方法,该属性就变成了具有读写功能的属性。
除此之外,还可以使用 deleter 装饰器来删除指定属性,其语法格式为:
@方法名.deleter
def 方法名(self):
代码块
例如,在 Rect 类中,给 area() 方法添加 deleter 方法,实现代码如下:
@area.deleter
def area(self):
self.__area = 0
然后运行如下代码:
del rect.area
print("删除后的area值为:",rect.area)
运行结果为:
删除后的area值为: 0
三、继承
什么是继承?
让子类直接拥有父类的属性和方法的过程就是继承
父类 - 被继承者(又叫超类)
子类 - 继承者
怎么继承
"""
class 类名(父类1,父类2,...):
类的说明文档
类的内容
注意: 默认情况下,定义的类继承自 object
"""
class Person:
num = 61
def __init__(self):
print('Person中init')
self.name = '小明'
self.age = 18
self.gender = '男'
self.__sex = '女'
def eat(self):
print(f'Person:{self.name}在吃饭')
@classmethod
def show_num(cls):
print(f'人类的数量:{cls.num}')
@staticmethod
def func1():
print('人类破坏环境!')
# 让 Student(子类) 继承 Person(父类)
class Student(Person):
pass
# 继承的时候子类可以直接拥有父类所有的属性和方法
print(Student.num)
stu = Student()
print(stu.name, stu.age, stu.gender)
stu.eat()
Student.show_num()
Student.func1()
print(stu.__dict__)
在子类中添加内容
1.在子类中添加类属性和方法
类属性和方法的添加不会因为继承而收到任何影响
2.添加对象属性
对象属性是怎么被继承:继承的时候因为init方法被继承,间接继承了对象属性
在子类的__init__方法中通过 super()去调用父类的__init__方法
类中的方法的调用过程(重要)
通过类或者对象在调用方法的时候,会先看当前类中有没有这个方法,如果有就直接调用自己类中的方法;没有就看父类中有没有定义这个方法,如果父类定义了就调用父类的;父类没有定义,就看父类的父类中有没有定义…以此类推,如果object 中没有定义才会报错!
class Teacher(Person):
title = '老师'
def __init__(self):
# 调用父类的init方法
super().__init__()
self.school = '千锋'
self.subject = 'Python'
self.tea_id = '001'
def attend_class(self):
print('老师上课')
def eat(self):
super().eat()
print(f'老师在吃饭')
print(Teacher.num, Teacher.title)
t1 = Teacher()
t1.attend_class()
print(t1.school, t1.subject, t1.tea_id)
print(t1.name)
t1.eat()
四、多继承
class Animal:
num = 10
def __init__(self, age, gender):
self.age = age
self.gender = gender
def eat(self):
print('动物需要吃东西')
class Fly:
name = '飞行器'
def __init__(self, height, time):
self.height = height
self.time = time
def stop(self):
self.height = 0
print('停止飞行')
class Bird(Animal, Fly):
pass
b1 = Bird(2, '雌')
# 两个父类的类属性都可以继承
print(Bird.num)
print(Fly.name)
# 对象属性只会继承第一个父类的
print(b1.age, b1.gender)
# print(b1.height, b1.time) # AttributeError: 'Bird' object has no attribute 'height'
# 两个父类的不同方法都可以继承
b1.eat()
b1.stop()
五、方法的重写
子类和父类中拥有方法名相同的方法,说明子类重写了父类的方法
重写的作用:父类中已经有了这个方法,但子类想修改里面的内容,直接修改父类是不好的,就需要用到重写
例如:
class Animal:
def eat(self):
print("---吃-----")
def drink(self):
print("----喝-----")
def sleep(self):
print("----睡觉-----")
class Dog(Animal):
def bark(self):
print("---汪汪叫----")
class Xiaotq(Dog):
def fly(self):
print("----飞-----")
def bark(self):
print("----狂叫-----")
xiaotq = Xiaotq()
xiaotq.fly()
xiaotq.bark()
xiaotq.eat()
super方法
super这个方法的使用时建立在两个基础之上的
- 必须要有父类的继承
- 必须要有方法的重写
例如:
class A(object):
def sleep(self):
print(11111)
class Animal(A): # 括号中没写,默认继承object
def sleep(self): # 房地产
print('动物会睡觉')
def run(self):
print('动物会跑')
class Dog(Animal):
def sleep(self): # 电竞
print('狗会睡觉')
# super的作用: 将被覆盖了的父类方法,重新调用
super().sleep()
dog = Dog()
dog.run()
dog.sleep()