1.类成员
1.类变量
- 类的成员变量描述对象的属性值根据对象不同会产生区别,此时类变量称为实例变量
- 类变量的成员变量描述对象的属性值根据对象的不同不会产生区别,称此类变量为类变量
- 类变量是归属类的,实例变量是归属对象的
- 类变量书写在类定义的里面,实例变量书写在__init__方法中
class Dog:
var = "都是狗" #类变量 定义在类里
# 所以的对象都有这个变量值
def __init__(self, name, age): # 对象变量 定义在init里
self.name = name
self.age = age
# 类名.变量名 方式访问类变量
# 类名.变量名 = 变量值 方式修改
类变量名的访问
1.类名.类变量名(推荐)
2.对象名.类变量名
类变量名的修改
类名.类变量名 = 变量值
不允许使用 对象名.类变量名 = 变量名修改 这样会给该变声明一个独有属性 仅修改该对象的属性值
类变量可以私有化
作用:记录创建了多少个对象 +=1
记录一个总数 每个方法都能调用 且通用
2.类方法
定义格式:
在类方法中,类属性访问可以通过 cls.类属性名 来访问
class 类名:
@classmethod
def 方法名(cls, 形参):
方法体
调用格式:
类名.方法名(实参) (推荐) 对象名.方法名(实参) (不推荐)
如果类方法和成员方法名字冲突时,不能使用 对象名.方法名(实参) 调用方法,这样会调用写在后面的方法,
通过cls(变量名)可以创建一个对象
只要方法名称相同(无论修饰符是否一样) 就会出现覆盖的情况 后面写的会被调用
注意:类方法和成员方法之间的相互调用
类方法中不允许使用实例变量和实例方法
实例方法中允许使用类变量和类方法,推荐使用类名调用
class Dog:
var = "都是狗" #类变量 定义在类里
def __init__(self, name, age): # 对象变量 定义在init里
self.name = name
self.age = age
@classmethod # 定义一个类方法
def show_me(cls):
print("类方法的狗子")
# slef.show 成员方法无法调用类方法和类变量
def show(self): # 定义一个成员方法
print(Dog.var) # 类方法可以定义成员变量
Dog.show_me() #类方法可以调用成员方法
print("成员方法的狗子")
dog1 = Dog("狗子", 18)
dog1.var = "不是狗"
print(dog1.var)
dog1.show()
-
注意:self 和cls的自动补充:
这只是一个变量名而已,自动补充的 可以用任何变量名代替
-
静态方法(了解 不常用)
@staticmethod # 静态方法的创建 def show1(): print("一个静态方法")调用方法:
类名.方法名(实参) (推荐)
对象名.方法名(实参) (不推荐)
静态方法的定义与类无关,与对象无关,可以转化成函数定义
用途:用于存放工具类,使其存放在一起,类名.即可看到
3.面向对象名称的总结
- 公有变量:类中 有self.前缀的变量都是公有变量
- 全局变量:在文件的最外层,或者在函数中加了global的变量
- 局部变量:定义在函数中的,类中的方法里,成员变量名没有self的也是局部变量
- 独有变量:只有这一个对象才有的变量,
- 私有变量:类变量名前有2个下划线__的称为私有变量,只能在类的内部使用
- 类变量:定义在类的下边,没有在方法里面
- 成员变量 = 公有变量
- ______init__方法:构造方法
- 对象 可以称为实例
5.2继承
1.基础格式:
class 子类名称(父类名称):
pass
继承描述的是一种类间关系,一个类从另一个类获取成员信息的类间关系。
继承作用:继承父类的变量和方法;子类可以添加父类没有的东西,父类私有成员不可以被继承
2.继承的关系结构图
- object是所有类的父类
查看继承关系结构:类名.mro
class Anmail:
pass
class Cat(Anmail): #Anmail是cat的父类
pass
class SmallCat(Cat): # Cat是smallcat的父类
pass
print(SmallCat.__mro__)
# 此时输出:(<class '__main__.SmallCat'>, <class '__main__.Cat'>, <class '__main__.Anmail'>, <class 'object'>)
# 即 object是Anmail的父类,Anmail是Cat的父类,Cat是SmallCat的父类
3.重写
子类重写了__init__时,实例化子类,就不会调用父类已经定义的__init__,即被重写
- 在子类中可以定义与父类相同名称的方法,此时子类的方法对父类的方法构成了重写。 如果子类重写了父类的方法,使用子类对象调用被重写的方法时,执行子类中重写后的方法
__str__方法就是一个重写
调用父类被重写的方法:
1 父类名.init(self,参数)#注意名字是父类
2 super(子类名,self).init(参数)#注意名字是子类,而且init后是se1f之外的参数
调用格式一:父类名.方法名(对象)
调用格式二:super(本类名,对象).方法名()
调用格式三:super().方法名() (推荐)
重写后 父类和子类的信息都会有 而不是覆盖
class People:
def __init__(self, age):
self.name = None
self.age = age
def said(self):
print("父类说")
class Man(People):
def __init__(self):
super().__init__(None) # 子类重写时如何调用父类的成员变量? 参数不能写变量吗?
self.sex = "man"
def said(self):
print("子类说")
super().said()
people1 = People(18)
print(people1.age)
man1 = Man()
print(man1.age)
init方法中,子类要重新父类init时,父类传递了参数,子类也需要传参
class Person():
def __init__(self,name,age):
self.name = name
self.age = age
class Teacher(Person):
def __init__(self,name,age): 父类有
super().__init__(name,age)
self.id = "111"
4.多继承
格式: class 子类名(父类名1,父类名2,父类名3):
pass
如果方法,变量有冲突,则先选择写在前面的父类
重写:父类名.方法名(self)
如果写super().方法名(),则默认调用写在前面的父类名方法(父类名1)
需要查看具体重写的那个方法 同样用:类名.___ __mro _
5.多态
同一个对象,在不同的使用环境中以不同的形态展示其功能,称该对象具有多态特征
多态发生在继承关系的基础之上
# 同一个对象,在不同的使用环境中以不同的形态展示其功能,称该对象具有多态特征。
class Eat:
def breakfast(self):
print("吃饭")
class Sleep:
def bed(self):
print("睡觉")
class Man(Eat,Sleep):
def breakfast(self):
print("吃早饭呢")
def bed(self):
print("在床上睡觉")
class Demo:
def test(self,who):
who.breakfast()
eat1 = Eat()
man1 =Man() # 以多态的形式展现出来 需要eat 但是给了一个具有eat方法的子对象也行
demo1 = Demo()
demo1.test(man1)
鸭子类型
对象在语法层面满足调用关系,实际不具有对应的对象形态,称该对象此时具备鸭子类型
鸭子类型是一种特殊的多态表现形式 鸭子类型和多态就差了一个继承
class Eat:
def rice(self):
print("吃米饭")
class Paly:
def player(self):
print("玩游戏")
class Man(Eat,Paly): # 子类
def rice(self):
print("吃好吃的米饭")
def player(self):
print("玩好玩的游戏")
class Stdent: # 没有关系的类
def rice(self):
print("学生也不吃饭")
def play(self):
print("好学生不玩游戏")
class Demo:
def demo1(self,who):
who.rice()
demo = Demo()
man =Man()
std1 = Stdent()
demo.demo1(man) # 继承
demo.demo1(std1) # 鸭子类型(没有继承)