Python【day 18】面向对象-类和类的关系
一、昨日内容回顾 成员 1、变量 1、成员变量--最常见 1、写法: 变量前面加了self就是成员变量 这里的self表示当前对象 一般是在构造方法中定义 2、调用: 对象.成员变量 3、作用: 可以在类中的不同方法间使用 有点局部的意思(每个对象的成员变量可以不同) 2、类变量(静态变量) 1、写法 写在类中,方法外的变量 2、调用 类名.类变量 3、作用 全局的意思 注意点: 1、如果用对象.类变量,就相当于给对象新增了一个和类变量同名的成员变量 原来的类变量不会有任何变化 2、方法 1、成员方法--最常见 1、范围: 构造方法: 创建对象的时候,自动调用构造方法 普通方法 2、写法: 1、第一个参数是self,表示当前对象本身 3、调用 对象.成员方法 内部原理:类名.成员方法(对象名) 2、静态方法 1、写法 1、方法上面加上@staticmethod 2、参数没有self 2、调用 类名.静态方法 3、作用 把静态方法理解成类中的函数就可以 3、类方法 1、写法 1、类方法名字上面加上@classmethod 2、第一个参数是cls 2、调用 类名.类方法 3、作用 用于在类中创建对象,设计模式 3、属性 1、概念 通过方法的形式来表示一个属性信息(变量-名称) 2、引入原因-由来 1、成员变量或者数据库字段一般不保存人的年龄,而是保存人的生日 2、因为年龄的话,每年都会变化,生日是不会变化的,易于维护 3、根据出生日期计算年龄,做成一个成员方法的,但是年龄是一个名词属性 用方法-动作来计算,稍有点不妥 4、于是,就引入了属性 3、写法 1、成员方法的定义上面加上一行@property 4、调用 对象名.属性名--调属性 对象名.方法名()--调成员方法 4、私有 1、私有变量 1、写法 类中,变量名字前面加上双下划线__ 2、调用 1、不能用对象进行调用 2、可以在类中的成员方法中使用 3、对象如何间接调用私有变量 1、把私有变量写在类中的成员方法中 2、对象通过调成员方法,从而间接调用私有变量 2、私有方法 1、写法 类中,成员方法名字前面加上双下划线__ 2、调用 1、不能用对象进行调用 2、可以在类中的成员方法中使用 3、对象如何间接调私有方法 1、把私有方法的调用,写在类中的成员方法中 2、对象通过调成员方法,从而间接调用私有方法 3、注意点: 1、子类继承父类的时候,无法继承父类的私有变量和私有方法 二、今日主要内容 1、依赖关系 1、比较轻的关系 2、例子: 大象装冰箱 大象装高压锅--多态 你打车 3、写法 1、类2的对象作为参数传入到类1的成员方法中 2、在类1的成员方法中,通过类2的对象调类2的成员方法 2、关联关系(组合、聚合) 1、一对一 1、例子:男女朋友 2、写法 1、类2的对象作为参数传入到类1的成员方法中 2、在类1的成员方法体中,把类2的对象赋值给类1的成员变量 3、类1的成员变量就可以指代类2的对象了 4、可以通过类1的成员变量调类2的成员变量,或者类2的成员方法 2、一对多 1、例子:学校和老师 2、写法 类1-学校类的定义 1、类1-学校类中定义一个成员变量,赋值空列表 2、把类2的对象作为参数传入到类1的成员方法1中 3、在类1的成员方法体中,把类2的对象添加到空列表 4、在类1的成员方法2中,循环遍历这个列表,列表的每个元素就是类2的对象 通过类2的对象调类2的成员变量 类1的成员方法调用 1、类1的对象每调用一次成员方法1,就新增加一个老师对象到列表中 3、继承关系,实现关系 1、self:当前执行这个方法的对象 2、子类继承父类 1、新建的是子类对象,那么self就是子类对象 2、新建的是父类对象,那么self就是父类对象 4、特殊成员 1、重点是: __str__() #打印对象,默认是打印对象的内存地址; 重写__str__()后,打印对象的时候,可以打印对象的成员变量 例子: def __str__(self): # return self.name,self.age,self.hobby #报错 # TypeError: __str__ returned non-string (type tuple) # 返回值必须是字符串,而不能是元组 return '%s %s %s' % (self.name,self.age,self.hobby) __new__() #创建对象的过程 1、加载类 calss 类名 定义类 2、开辟内存空间 __new__(cls)方法,此时内存空间没有对象,需要下一步创建 3、创建对象 通过__new__(cls)的返回值 return object.__new__(cls) 来创建对象 注意点:这里参数是cls类,而不是self对象,因为此时只有类,对象还没有被创建出来 4、初始化对象 构造方法 __init__() 5、使用对象 对象调成员变量,或者对象调成员方法 2、常见特殊成员 1、__init__() 构造方法 2、__hash__() 类和对象默认是可哈希的,不可变,可以作为字典的key __hash__ = None #就变成不可哈希,可变的,不能作为字典的key 3、__getitem__(value) 对象[key]就是调用__getitem__(value)方法,参数是value 通过key获取value,类似字典 4、__setitem__() 对象[key] = value 就是调用__setitem__(key,value)方法,参数是key,value 添加键值对,类似字典 5、__delitem__(key) del 对象[key]就是调用__delitem__(key)方法,参数是key 通过key删除键值对,类似字典 6、__enter__() return 字符串 7、__exit__() with 对象 as 变量: pass print(变量) 过程如下: 1、先调__enter__()方法进入 2、其返回值,被with后面的变量接收 3、再调__exit__()方法退出 例子:打开文件
一、依赖关系 需求:要把大象装冰箱 伪代码思路: 1、新建2个类,大象类和冰箱类 2、关系:大象类要依赖冰箱类 3、大象类--成员方法: 1、开冰箱门--依赖冰箱类--传入冰箱对象 2、装自己 3、关冰箱门--依赖冰箱类 4、冰箱类--成员方法: 1、开门 2、关门 需求2:要把大象装高压锅 -这里的冰箱和高压锅 多态 伪代码思路: 1、新建2个类,大象类和高压锅类 2、关系:大象类要依赖高压锅类 3、大象类--成员方法: 1、开高压锅门--依赖高压锅类--传入高压锅对象 2、装自己 3、关高压锅门--依赖高压锅类 4、高压锅类--成员方法: 1、开门 2、关门 小结: 1、依赖是一种松耦合的关系 大象开冰箱门,冰箱坏了,大象还可以开高压锅门 2、多态思想 大象开冰箱门,开高压锅门 冰箱和高压锅对象就是多态 3、依赖的写法 1、类a依赖类b 大象类依赖冰箱类 2、类a的成员方法,形参是类b的对象 类a的成员方法的内容: 类b的对象.类b的成员方法() 4、依赖的概念 在方法中引入另一个类的对象 5、没有特指 大象开冰箱门,想要的对象是一个冰箱-泛指, 具体是哪个冰箱(是那台haier冰箱,还是这台美的冰箱)没有指定--没有特指(这台还是那台)
关联关系:一对一 1、在类1的成员方法中,把类2的对象作为形式参数,传递给类1的成员变量 self.类1的成员变量 = 类2的对象 左边就可以等价于右边(即类2的对象的地方,可以用类1的对象.成员变量表示 依赖关系和关系关系的区别 一、写法不同: 1、前者 在类1的成员方法中,把类2的对象作为形式参数 写法: 类1的成员方法(类2的对象): #这里类2的对象可以是冰箱,也可以是高压锅,多态 类2的对象.类2的成员方法() 2、后者 在类1的成员方法中,把类2的对象作为形式参数,传递给类1的成员变量 写法: 类1的成员方法(类2的对象): self.成员变量=类2的对象 说明:后面凡是用到类2对象的地方,可以用类1对象.成员变量代替 二、例子 1、前者的例子是大象装冰箱,打车(今天打这个车,明天打那个车) --(类比:关系比较轻,大象可以装不同的冰箱,你可以打不同的车) 后者的例子是男女朋友--(类比:关系更紧密)
关联关系中一对一和一对多的区别 一、写法不同 1、前者 男孩类的成员方法 def meet(self,girl): #参数是女孩对象 女孩对象传递给男孩的女朋友这个成员变量 self.girl_friend = girl #关键点 #男孩对象的成员变量-girl_friend就是女孩对象 2、后者 学校类的构造方法 self.__techer_list = [] 学校类的成员方法 def recruit(self,t): #招聘-成员方法 参数t是老师对象 self.__techer_list.append(t) 二、例子不同 1、前者的例子是男女朋友 2、后者的例子是学校和老师 扩展: 组合关系、聚合关系和关联关系的写法是类似的
四、特殊成员 特殊成员 1、写法 双下划线开头,双下划线结尾的方法 2、作用 特殊场景下,会自动执行 3、例子 __init__() 一、构造方法 1、创建对象的时候,会自动执行构造方法 __init__() 二、__call__()方法 1、用法 新建对象(),就会自动调用__call__()方法 2、对象后面加小括号 对象()是python特有的 三、__getitem__()方法 1、用法 对象名[key],就会自动调用__getitem__(key)方法 参数就是key 2、类似字典,可以从对象中获取key 四、__setitem__()方法 1、用法 对象名[key]=value,就会自动调用__setitem__(key,value)方法 参数是key,value 2、类似字典,相当于给对象添加一个键值对 五、__delitem__()方法 1、用法 del 对象名[key],就会自动调用__delitem__(key)方法 参数是key 2、类似字典,相当于给对象删除一个键值对 六、__enter__()方法 return var1 __exit__()方法 with 对象 as 变量: print var1 #这里的var1是__enter__方法的返回值 1、说明: with的执行过程 1、先执行__enter__方法 2、再执行with中的代码块 3、最后执行__exit__方法 七、__hash__()方法 1、类名和对象名默认都是可哈希的,不可变的,可以作为字典的key 原因是:万事万物都是对象,类名是object的子类 object这个类中有__hash__()方法 这个方法的存在,就表示可以哈希 2、__hash__ = None 在类中加上上面一行,类名就不可哈希,可变的,不能作为字典的key 注意点:这里是 =赋值 而不是==值的判断 八、__str__() 方法 1、__str__() 方法是Boy的父类object的方法,如果子类不重写的话 打印对象,就是打印对象的内存地址 2、子类重写__str__() 方法后 再次打印对象,就可以不输出对象的内存地址,而是自定义输出了 3、注意点: __str__() 方法的返回值的类型必须是字符串,而不能是元组,否则会报错 九、__new__(cls)方法 创建对象的步骤 1、加载类 2、开辟内存空间:通过__new__(cls)方法 3、创建对象: 通过__new__(cls)方法的返回值 object.__new__(cls)来创建对象 注意点:__new__()的参数是cls类,而不是对象(因为现在对象还没有创建出来) 4、初始化对象: 创建对象的过程中,自动调构造方法__init__(),初始化对象 把成员变量封装到对象中,就是初始化对象 5、使用对象: 1、打印对象 2、对象调成员方法 3、对象调成员变量