组合
组合指的是一个对象中,包含另一个或多个对象。(一个对象拥有另一个对象中的属性/方法)
减少代码的冗余
# 组合实现
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
# 老师类
class Teacher(People):
def __init__(self, name, age, sex):
super().__init__(name, age, sex)
# 学生类
class Student(People):
def __init__(self, name, age, sex):
super().__init__(name, age, sex)
# 日期类
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def tell_birth(self):
print(f'''
===== 出生年月日 =====
年: {self.year}
月: {self.month}
日: {self.day}
''')
stu1 = Student('qwe', 109, 'female')
date_obj = Date(1910, 11, 11)
# 学生对象中包含一个自定义日期对象
stu1.date_obj = date_obj #stu1.date_obj = Date(1910, 11, 11)
stu1.date_obj.tell_birth()
#===== 出生年月日 =====
# 年: 1910
# 月: 11
# 日: 11
继承: 继承是类与类的关系,子类继承父类的属性/方法,子类与父类是一种 “从属” 关系。
组合: 组合是对象与对象的关系,一个对象拥有另一个对象中的属性/方法,是一种什么有什么的关系。
封装
封装(Encapsulation)是面向对象的三大特征之一
什么是封装?
封装指的就是把数据与功能都整合到一起
代码封装,其实就是隐藏实现功能的具体代码,仅留给用户使用的接口,就好像使用计算机,用户只需要使用键盘、鼠标就可以实现一些功能,而根本不需要知道其内部是如何工作的。
是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。
封装数据:目的是保护隐私,保证了类内部数据结构的完整性,高扩展性
功能封装:目的是隔离复杂度
总的来说,对一个类或对象实现良好的封装,可以达到以下目的:
- 隐藏类的实现细节。
- 让使用者只能通过事先预定的方法来访问数据,从而可以在该方法里加入控制逻辑,限制对属性的不合理访问。
- 可进行数据检查,从而有利于保证对象信息的完整性。
- 便于修改,提高代码的可维护性。
为了实现良好的封装,需要从以下两个方面来考虑:
- 将对象的属性和实现细节隐藏起来,不允许外部直接访问。
- 把方法暴露出来,让方法来控制对这些属性进行安全的访问和操作。
因此,实际上封装有两个方面的含义:把该隐藏的隐藏起来,把该暴露的暴露出来
如果用了私有的,在类的外部,无法直接使用变形的属性,但是在类的内部可以直接使用
封装:
体现在两点:
1、数据的封装(将数据封装到对象中)
obj = Foo('宝宝',22)
2、封装方法和属性,将一类操作封装到一个类中
class Foo:
def __init__(self,name,age):
self.name = name
self.age = age
def show (self):
print(self.name,self.age)
访问限制机制,私有方法 (就是类属性前面加__)
class Goods:
# 按照打八折计算 (定义了一个私有类属性)
__discount = 0.8 #变形后:_Goods__discount
def __init__(self,name,price):
self.name = name
self.price = price
def goods_price(self):
return self.price * Goods.__discount
apple = Goods('apple',10)
print(apple.goods_price())
# print(Goods.__dict__) #类名.__dict__
print(Goods._Goods__discount)
# 封装:把你不想让人看的隐藏起来
# 数据封装:目的保护隐私
class Teacher:
__School = 'oldboy' #类属性
def __init__(self,name,salary):
self.name = name
self .__salary = salary #_Teacher__salary
# 老师的属性 值
#怎么把薪水隐藏起来?
self.__salary=salary
def foo(self):
print('------')
t=Teacher('egon',2000)
print(t.__dict__)
# print(t.name)
print(t._Teacher__salary)#让显示出来
print(Teacher._Teacher__School) #类属性使用_类名__属性名
t.foo()
#在本类内是可以正常调用的
#在本类外就必须以_类名__属性名调用(但是不建议你调)
property
调用的时候不用加括号
为什么要用property:将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则
from math import pi
class Circle:
def __init__(self,radius):
self.radius = radius
@property #装饰器:把一个方法当成一个属性用了
def area(self):
return self.radius * self.radius* pi
@property
def peimeter(self):
return 2*pi*self.radius
c = Circle(10)
print(c.area) #当成一个属性来调了,就不用加括号了
print(c.peimeter)