学习总结
封装:外部不能直接使用,内部开接口 property:将方法伪装成数据,可以不加括号直接用 绑定:绑定(对象,类),非绑定 封装(方法,数据): 1 数据封装 提供接口,附加逻辑 2 方法封装 隔离复杂度 property(方法):注意方法名一样 property 查看 name.setter 修改 name.deleter 删除 方法(绑定 非绑定): 绑定:1 对象 默认 2 类 classmethod(配置文件读配置) 非绑定: staticmethod (uuid.uuid1())
复习
上节课复习: 1、组合 什么是组合? 一个类的对象具备某一个属性 该属性的值是指向另外一个类的对象的 class Foo: pass class Bar: pass obj_of_foo=Foo() obj_of_bar=Bar() obj_of_foo.attrib=obj_of_bar obj_of_foo.attrib.xxx 为何用组合? 是为了减少类与类直接的代码冗余 2、菱形继承问题之新式类与经典的区别 A(B,C,D) 在属性查找方面 新式类:广度优先查找 经典类:深度优先查找 3、继承的实现原理 c3算法 mro列表 4、在子类派生的新方法中重用父类功能的两种方式 指名道姓(与继承无关):类名.函数名(该传几个传几个) super(自己的类名,self).父类的属性:严格依赖继承,super()会得到一个特殊的对象 该对象专门从当前的父类开始往后查找 5、多态 多态指的是同一种事物的多种形态,比如水有冰、水蒸气、雪 多态性: 指的是继承同一个父类的子类,具有相同的方法名 在使用的时候,子类的对象可以在不用考虑其具体数据类型的前提下 而直接调用的方法 import abc class Foo(metaclass=abc.ABCMeta): @abc.abstractmethod def func1(self): pass class Bar(Foo): def func1(self): pass 强调:父类不能实例化,子类要想实例化则必须实现与父类同名的方法 python中崇尚“鸭子类型” 今日内容: 1、封装 1.1 如何隐藏属性 1.2 封装的真实意图与用法 1.3 property 2、绑定方法与非绑定方法
封装
''' 1、什么是封装 封:属性对外是隐藏的,但对内是开放的 装:申请一个名称空间,往里装入一系列名字/属性 2、为什么要封装 封装数据属性的目的 首先定义属性的目的就是为了给类外部的使用使用的, 隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口 然后让类外部的使用通过接口来间接地操作隐藏的属性。 精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作 封装函数属性 首先定义属性的目的就是为了给类外部的使用使用的, 隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口 然后在接口内去调用隐藏的功能 精髓在于:隔离了复杂度 3、如何封装 ''' # 如何隐藏:在属性前加上__开头 #1、 这种隐藏仅仅只是一种语法上的变形操作 #2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次 #3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是 # 在类定义阶段,类体内代码统一发生了一次变形 #4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头 # class People: # __country='China' #_People__country='China' # __n=100 #_People__n=100 # def __init__(self,name,age,sex): # self.__name=name #self._People__name=name # self.age=age # self.sex=sex # # def eat(self): # print('eat.....') # print(People.__country) #People._People__country # print(self.__name) #self._People__name # People.eat(123) # print(People.__country) # peo1=People('egon',18,'male') # peo1.eat() # print(peo1.__name) # print(People.__dict__) # print(People.__country) # print(People._People__country) # People.__x=11 # print(People.__dict__) # peo1=People('egon',18,'male') # print(peo1.__dict__) # peo1.__x=111 # print(peo1.__dict__) # class Foo: # def __f1(self): #_Foo__f1 # print('Foo.f1') # # def f2(self): # print('Foo.f2') # self.__f1() #self._Foo__f1 # # class Bar(Foo): # def __f1(self): #_Bar__f1 # print('Bar.f1') # # obj=Bar() # obj.f2() # class People: # def __init__(self,name,age): # self.__name=name # self.__age=age # # def tell_info(self): # print('%s:%s' %(self.__name,self.__age)) # # def set_info(self,name,age): # if type(name) is not str: # # print('用户名必须为str类型') # # return # raise TypeError('用户名必须为str类型') # # if type(age) is not int: # # print('年龄必须为int类型') # # return # raise TypeError('年龄必须为int类型') # self.__name=name # self.__age=age # # peo1=People('egon',18) # peo1.name=123 # peo1.age # peo1.tell_info() # # peo1.set_info('egon',19) # peo1.tell_info()
特性
#property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不用加括号而直接引用 # class People: # def __init__(self,name,weight,height): # self.name=name # self.weight=weight # self.height=height # # @property # def bmi(self): # return self.weight / (self.height ** 2) # # peo1=People('egon',75,1.8) # # peo1.height=1.85 # print(peo1.bmi) ''' class People: def __init__(self,name): self.__name=name @property # 查看obj.name def name(self): return '<名字是:%s>' %self.__name @name.setter #修改obj.name=值 def name(self,name): if type(name) is not str: raise TypeError('名字必须是str类型傻叉') self.__name=name @name.deleter #删除del obj.name def name(self): # raise PermissionError('不让删') print('不让删除傻叉') # del self.__name peo1=People('egon') # print(peo1.name) # print(peo1.name) # peo1.name='EGON' # print(peo1.name) del peo1.name ''' class People: def __init__(self,name): self.__name=name def tell_name(self): return '<名字是:%s>' %self.__name def set_name(self,name): if type(name) is not str: raise TypeError('名字必须是str类型傻叉') self.__name=name def del_name(self): print('不让删除傻叉') name=property(tell_name,set_name,del_name) peo1=People('egon') print(peo1.name) peo1.name='EGON' print(peo1.name) del peo1.name
绑定方法与非绑定方法
''' 1、绑定方法 特性:绑定给谁就应该由谁来调用,谁来调用就会将谁当作第一个参数自动传入 《《《精髓在于自动传值》》》 绑定方法分为两类: 1.1 绑定给对象方法 在类内部定义的函数(没有被任何装饰器修饰的),默认就是绑定给对象用的 1.2 绑定给类的方法: 在类内部定义的函数如果被装饰器@classmethod装饰, 那么则是绑定给类的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入 2、非绑定方法 类中定义的函数如果被装饰器@staticmethod装饰,那么该函数就变成非绑定方法 既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用 但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数 3 应用 如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法 如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法 如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数 ''' # class Foo: # @classmethod # def f1(cls): # print(cls) # # def f2(self): # print(self) # obj=Foo() # print(obj.f2) #obj # print(Foo.f1) #Foo # # Foo.f1() # print(Foo) #1、f1绑定给类的 # 了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的仍然是类 # print(Foo.f1) # print(obj.f1) # Foo.f1() # obj.f1() #2、f2是绑定给对象的 # obj.f2() # Foo.f2(obj) import settings import uuid class Mysql: def __init__(self,ip,port): self.uid=self.create_uid() self.ip=ip self.port=port def tell_info(self): print('%s:%s' %(self.ip,self.port)) @classmethod def from_conf(cls): return cls(settings.IP, settings.PORT) @staticmethod def func(x,y): print('不与任何人绑定') @staticmethod def create_uid(): return uuid.uuid1() # 默认的实例化方式:类名(..) obj=Mysql('10.10.0.9',3307) # 一种新的实例化方式:从配置文件中读取配置完成实例化 obj1=Mysql.from_conf() obj1.tell_info() obj.func(1,2) Mysql.func(3,4) print(obj.func) print(Mysql.func) print(obj.uid)
1、定义MySQL类(参考答案:http://www.cnblogs.com/linhaifeng/articles/7341177.html#_label5) 1.1.对象有id、host、port三个属性 1.2.定义工具create_id,在实例化时为每个对象随机生成id,保证id唯一 1.3.提供两种实例化方式,方式一:用户传入host和port 方式二:从配置文件中读取host和port进行实例化 1.4.为对象定制方法,save和get_obj_by_id,save能自动将对象序列化到文件中,文件路径为配置文件中DB_PATH,文件名为id号,保存之前验证对象是否已经存在,若存在则抛出异常,;get_obj_by_id方法用来从文件中反序列化出对象 2、定义一个类:圆形,该类有半径,周长,面积等属性,将半径隐藏起来,将周长与面积开放 参考答案(http://www.cnblogs.com/linhaifeng/articles/7340801.html#_label4) 3、明日默写 1、简述面向对象三大特性:继承、封装、多态 2、定义一个人的类,人有名字,身高,体重,用property讲体质参数封装成人的数据属性 3、简述什么是绑定方法与非绑定方法,他们各自的特点是什么?
###1 author--oneself import settings import uuid import json import os class Mysql: def __init__(self,host,port): self.uid=self.create_uid() self.host=host self.port=port @staticmethod #为每个对象随机生成id def create_uid(): return uuid.uuid1() @classmethod def from_conf(cls): #从配置文件中读取host和port进行实例化 return cls(settings.HOST, settings.PORT) def save(self): user_dic = {'host':self.host,'port':self.port} user_path = os.path.join(settings.DB_PATH,'%s.json' %self.uid) if os.path.exists(user_path): raise FileExistsError('文件已存在') with open(user_path,'w',encoding='utf-8') as f: json.dump(user_dic,f) f.flush() print('save successful') # def get_obj_by_id(self): # user_path = os.path.join(settings.DB_PATH, '%s.json' % self.uid) # with open(user_path,encoding='utf-8') as f: # return json.load(f) @staticmethod def get_obj_by_id(id): user_path = os.path.join(settings.DB_PATH,id) with open(user_path,encoding='utf-8') as f: return json.load(f) # mysql1 = Mysql.from_conf() # mysql2 = Mysql('3.3.3.3','88') # # mysql1.save() # mysql2.save() # print(mysql1.get_obj_by_id()) # print(mysql2.get_obj_by_id()) obj1 = Mysql.get_obj_by_id('2d197874-7ac6-11e8-915c-68f728b8340c.json') print(obj1) ###2 # import math # # # class circle: # radius #perimeter #area # def __init__(self, radius): # self.__radius = radius # # @property # def perimeter(self): # return 2 * math.pi * self.__radius # @property # def area(self): # return math.pi * self.__radius ** 2 # # c1 = circle(3) # print(c1.perimeter) # print(c1.area) ##1 # 继承:新建类,遗传属性,减少代码冗余,新式类,经典类 # 封装:对内开放,对外隐藏,外部不能直接使用,调用接口,附加逻辑,隔离复杂度 # 多态:同一事物,不通形态,同一父类的子类,相同的方法名, 使用时子类的对象可以在不用考虑其具体数据类型的前提下,直接调用方法 ##2 # class People: # def __init__(self,name,height,weight): # self.name=name # self.height=height # self.weight=weight # # @property # def bmi(self): # return self.weight / (self.height ** 2) # # p1 = People('xjj',1.78,68) # print(p1.bmi) ##3 # 绑定方法:自动传值 1 对象绑定(默认) 2 类绑定(@classmethod) # 非绑定方法: 没有自动传值 @staticmethod 普通函数,都可以调用