面向对象之核心封装
今日学习总结:
一、组合:
1.什么是组合?
组合指的是一个对象中,包含另外一个或多个对象
2.为什么要用组合?
减少代码的冗余
3.如何使用组合?
耦合度:藕断丝连
耦合度越高,程序的可扩展性越低
耦合度越低,程序的可扩展性越高。
总结:
继承是类与类的关系,子类继承父类的属性/方法,子类与父类是一种‘从属’关系。
组合是对象与对象的关系,一个对象拥有另一个对象中的属性/方法,是一种 什么有什么的关系。
例子:组合的使用
#组合的实现 #父类 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} ''' ) tea1=Teacher('tank',17,'male') #调用老师类,产生老师类的对象 date_obj=Date(1999,7,7) #调用日期类,产生日期类的对象 print(tea1.name,tea1.age,tea1.sex) tea1.date_obj=date_obj #把日期类的对象赋给了tea1.date_obj(老师类的对象中包含一个日期类的对象) #也就是给老师类对象tea1 中加了一个属性叫 date_obj属性、属性的值是对象(date_obj) tea1.date_obj.tell_birth() #调用老师类对象(tea1)中的 对象属性(date_obj) 的 属性(tell_birth)
例子:继承使用
#继承实现 #父类 class People: def __init__(self, name, age, sex, year, month, day): self.name = name self.age = age self.sex = sex self.year = year self.month = month self.day = day def tell_birth(self): print(f''' ===== 出生年月日 ===== 年: {self.year} 月: {self.month} 日: {self.day} ''') # 老师类 class Teacher(People): def __init__(self, name, age, sex, year, month, day): super().__init__(name, age, sex, year, month, day) # 学生类 class Student(People): def __init__(self, name, age, sex, year, month, day): super().__init__(name, age, sex, year, month, day) tea1 = Teacher('tank', 17, 'male', 2002, 6, 6) stu1 = Student('HCY', 109, 'female', 1910, 11, 11) print(tea1.name, tea1.age, tea1.sex) tea1.tell_birth() #表示调用父类的 属性(tea1_birth)进而输出,, print(stu1.name, stu1.age, stu1.sex) stu1.tell_birth()
例子:组合的练习:
选课系统: 1.有学生、老师类,学生与老师有属性‘名字、年龄,性别,课程’
2.有方法 老师、学生可以添加课程,打印学习/教授课程
class People: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def add_course(self, course_obj): self.course_list.append(course_obj) #给父类 添加一个 课程列表属性(course_list),然后在在这个列表中 添加课程对象(course_obj) def tell_all_course_info(self): # 从当前对象中课程列表中取出所有的课程对象 for course_msg in self.course_list: # course_msg 变量其实就是 一个个 课程对象 。 # 通过课程对象.打印课程信息方法 course_msg.tell_course_info() # 因为 course_msg 是课程对象,所以可以调用 课程类中 tell_course_info 的属性,输出。。。 class Student(People): def __init__(self, name, age, sex): super().__init__(name, age, sex) self.course_list = [] class Teacher(People): def __init__(self, name, age, sex): super().__init__(name, age, sex) self.course_list = [] class Course: def __init__(self, course_name, course_price, course_time): self.course_name = course_name self.course_price = course_price self.course_time = course_time def tell_course_info(self): print(f''' ====== 课程信息如下 ====== 课程名称: {self.course_name} 课程价格: {self.course_price} 课程周期: {self.course_time} ''') # 创建学生对象 stu1 = Student('HCY', 2000, 'female & male') # 创建课程对象 python_obj = Course('python', 77777, 6) #调用课程类 产生 课程对象 go_obj = Course('go', 88888, 4) stu1.add_course(python_obj) # 调用父类的 添加课程(add_course)属性。把课程类 的对象当成参数传进去。进而实现了组合 stu1.add_course(go_obj) # 当前学生打印所有课程信息 stu1.tell_all_course_info() #调用 父类中 打印所有课程信息的 (tell_all_course_info) 属性
二、封装
1.什么是封装?
封:好比一个袋子 。 比如:对象
装:好比将一堆小猫、小狗等等装在袋子里。比如:属性和方法
封装:指的是可以将一堆属性和方法,封装到对象中。
ps:对象就好比一个‘袋子/容器’,可以存放一堆属性和方法。
ps:存不是目的,目的是为了取,可以通过‘对象’的方法获取属性和方法。
2.为什么要封装?
可以通过‘对象.属性或方法’的方式 ‘存取/获取’ 属性和方法
优点:对象拥有‘.’的机制,方便存取数据。
class User: x = 10 def func(): pass obj = User() #调用类 产生一个类的对象 ,这个对象像一个袋子,里面有属性 x , y ,func obj.y = 20 #对象拥有 . 的机制 print(obj.x) print(obj.y)
3.如何封装?
看例子:
class User: x = 10 def func(self): pass obj = User() # 调用类 产生一个类的对象 ,这个对象像一个袋子,里面有属性 x , y ,func obj.y = 20 # 对象拥有 . 的机制。 另外这是给 类的一个对象添加属性 不是给类 print(obj.x) #10 print(obj.y) #20 print(obj) #这是类的 对象,所以结果是 <__main__.User object at 0x000000000211DEB8> print(User) #这是类名,所以结果是 <class '__main__.User'> print(obj.__dict__) #查看类的对象中的 属性 。结果是:{'y': 20} print(User.__dict__)#查看类中的属性 。结果是 {'__module__': '__main__', 'x': 10, 'func': <function User.func at 0x0000000009EE27B8>, '__dict__': <attribute '__dict__' of 'User' objects>, # '__weakref__': <attribute '__weakref__' of 'User' objects>, '__doc__': None}
三、访问限制机制
1.什么是访问限制机制?
01.凡是在类 内部定义的属性或方法,以__开头的属性或方法名,都会被限制,外部不能‘直接访问’该属性原型
02.python特有的:凡是在类内部定义_ _开头的属性或方法,都会变形为_类名_ _属性/方法
2.为什么要有访问机制?
比如:将一些隐私的数据,隐藏起来不让外部轻易获取。
接口:可以将一些数据封装成一个接口,可以让用户访问接口,并且通过相应的逻辑,最后再将数据返回给用户。
class User: __name = 'tank' __age = 17 __sex = 'male' __ID = '46549846798468498498' __bal = 151651651651654654654 # 校验接口,获取用户信息 def parse_user(self, username, password): if username == 'tank_jam' and password == '123': print(f''' 通过验证,获取用户信息。 用户名: {self.__name} 用户年龄: {self.__age} 用户性别: {self.__sex} 身份ID: {self.__ID} 用户资产: {self.__bal} ''') else: print('校验失败, 无法查询用户信息!') # __开头的方法 def __run(self): print('tank is running...') obj = User() #调用类产生 类的对象 obj.parse_user('tank_jam', '123') #调用类的 parse_user函数
3.如何实现?
class User: __name='tank' #这里内部 会变形为 _User_ _name __age=78 #这里内部 会变成 _User_ _age def __run(self): #这里内部 会变成 _User_ _run(self) print('tank今年78岁了') # print(User.__age) # obj=User() # print(obj.__age) print(User._User__name)
User._User__run(123)        #这里需要传实参      
obj=User()
print(obj._User__name)
obj._User__run() #这里不需要参数
四、property
1.什么是property ?
01.是一个python内置的装饰器,可装饰在类内部的方法上。
02.可以将该方法调用方式:对象.方法()——》对象.方法
2.为什么用property?
 让名词的方法,调用时更为合理。
        目的是为了,迷惑调用者,调用的方法误以为是 属性.
PS: 在某些场景下,调用的方法只是用来获取计算后的某个值。
PS: 必须通过 对象.方法() 方式调用,让该方法看起来像动词
3.如何使用?
class User: def __init__(self, name, weight, height): self.__name = name self.weight = weight self.height = height # 获取bmi指数方法 @property def bmi(self): return self.weight / (self.height ** 2) user_obj = User('HCY', 100, 1.9) # print(user_obj.bmi()) print(user_obj.bmi) #省略了小括号()
例子:
class Foo: def __init__(self,val): self.__NAME=val #将属性隐藏起来 @property def name(self): return self.__NAME obj=Foo('lili') print(obj._Foo__NAME) #因为__NAME 所以调用时 要加上 _类名 print(obj.name) #因为有了property 所以调用函数name时,不需要小括号() 结果: lili
例子:修改,删除
class Foo: def __init__(self,val): self.__NAME=val #将属性隐藏起来 @property def name(self): return self.__NAME @name.setter def name(self,value): if not isinstance(value,str): #在设定值之前进行类型检查 isinstance() 函数来判断一个对象是否是一个已知的类型 raise TypeError('%s must be str' %value) self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter def name(self): #raise PermissionError('Can not delete') del self.__NAME obj=Foo('lili') print(obj._Foo__NAME) #lili obj.name='tank' #触发name.setter装饰器对应的函数name(obj,'tank') print(obj._Foo__NAME) #tank del obj.name #触发name.deleter对应的函数name(obj),抛出异常PermissionError
五、python中的__init__() 方法:
在Python中定义类经常会用到__init__函数(方法),首先需要理解的是,两个下划线开头的函数是声明该属性为私有,不能在类的外部被使用或访问。而__init__函数(方法)支持带参数类的初始化,也可为声明该类的属性(类中的变量)。
例子:__init__函数(方法)的第一个参数必须为self,后续参数为自己定义。
demo1:
class User: name='tank' age=78 def run(self,sal): #self 是指 :谁调用函数,谁就是self print('tank今年78岁了') self.sal=sal #这里 self就是等于obj 所以这是给obj添加了一个属性 obj=User() obj.run(12000) #这是类的对象去调用 类的函数方法,不需要传参。当函数的形参不是一个时候,要传实参 print(obj.sal) #结果:12000
demo2:
class User: name='tank' age=78 def __init__(self,sal): #self 是指 :谁调用函数,谁就是self print('tank今年78岁了') self.sal=sal #这里 self就是等于obj 所以这是给obj添加了一个属性 obj=User(9999) #只有调用类 时 才会触发__init__函数 print(obj.sal) #9999
六、__init__ 与__new__的区别:
__init__(self) 初始化,__new__实例化方法,两者执行的顺序,先有实例,才能初始化。
__new__ (构造函数)单独地创建一个对象,而 __init__ (初始化函数)负责初始化这个对象。
__new__ 负责对象的创建而 __init__ 负责对象的初始化

                
            
        
浙公网安备 33010602011771号