python-面向对象
目录
面向对象
封装
继承
重写
重载
多态
单下划线、双下划线、头尾双下划线说明:
面向对象
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
# 创建类 Stuent是类名 包含name和age两个属性
class Stuent:
name=None
age=0
# stu是Stuent类变量,也就是对象
stu=Stuent()
#通过对象引用类属性
stu.age=18
stu.name="张三"
print("stu.name ",{stu.name },"stu.age",{stu.age})
成员方法
类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。
-
self 代表类的实例,self 在定义类的方法时是必须有的,但是调用时不必传入相应的参数。
- self 代表的是类的实例,代表当前对象的地址,而 self.__class__ 则指向类,通过self可以调用类的属性
- self 不是 python 关键字,我们把它换成其他变量也是可以正常执行的
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
def printf(self,name,age):
print(self)
self.name=name
self. age=age
print("name ", {self.name}, "age", {self.age},"self.__class__",self.__class__)
stu=Student()
stu.printf("张三",18)
构造方法
__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法
python里一个class不可以定义多个构造函数,一个class只能有一个用于构造对象的__init__函数,这时,可以使用不定长参数接收多个参数
析构函数 __del__ ,__del__在对象销毁的时候被调用,当对象不再被使用时,__del__方法运行
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
# 成员方法
def printf(self):
print(self)
print("name ", {self.name}, "age", {self.age},"self.__class__",self.__class__)
# 构造方法
def __init__(self,name,age):
self.name=name
self.age=age
stu=Student("张三",18) #创建对象 调用构造方法
stu.printf()
内置方法
一个类中,包含了多种内置方法,实现了不同的功能,称为魔术方法
1、字符串转换:控制类对象的转化
正常打印类对象时,得到的是类变量的内存地址
str方法:返回自定义字符串,执行此类对象的print方法,自动调用str方法
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
# 成员方法
def printf(self):
print(self)
print("name ", {self.name}, "age", {self.age},"self.__class__",self.__class__)
# 构造方法
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return f"Student变量: name={self.name},age={self.age}"
stu=Student("张三",18) #创建对象 调用构造方法
print(stu)
2、lt:小于比较
直接对两个类对象,进行比较是不可以的。要通过lt方法制定比较规则
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
# 构造方法
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return f"Student变量: name={self.name},age={self.age}"
def __lt__(self, other):
return self.age<other.age
stu=Student("张三",18) #创建对象 调用构造方法
stu1=Student("张三",18) #创建对象 调用构造方法
print(stu<stu1)
3、le:小于等于比较
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
# 构造方法
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return f"Student变量: name={self.name},age={self.age}"
def __le__(self, other):
return self.age<=other.age
stu=Student("张三",18) #创建对象 调用构造方法
stu1=Student("张三",18) #创建对象 调用构造方法
print(stu<=stu1)
4、eq方法:判断是否相等
不重写eq方法,默认比较的是两个对象的内存地址,肯定不相等
# Student类包括两个成员属性 name和age,还包括一个成员方法
class Student:
name=None
age=0
# 构造方法
def __init__(self,name,age):
self.name=name
self.age=age
def __str__(self):
return f"Student变量: name={self.name},age={self.age}"
def __eq__(self, other):
return self.name==other.name
stu=Student("张三",10) #创建对象 调用构造方法
stu1=Student("张三",18) #创建对象 调用构造方法
print(stu==stu1)
关系运算是比较2个对象,包括:
关系运算 | 含义 |
---|---|
__lt__ | X<Y |
__gt__ | X>Y |
__le__ | X<=Y |
__ge__ | X>=Y |
__eq__ | X==Y |
__ne__ | X!=Y |
__cmp__ | 比较X和Y,用于sorted,返回值是-1,1,0 |
面向对象有三大特征:封装、继承、多态
封装
封装:将现实中的事物转化为类
私有属性,只可以在类中被使用,在其余地方都无法使用
class Student:
__age=10 #age是私有变量
__name="张三" #name是私有变量
def __printf(self): #私有方法 对象不可以调用此方法
print("name ", {self.__name}, "age", {self.__age})
def init(self): #公开方法
self.__printf()
stu=Student()
stu.init()
继承
子类继承父类,得到父类的公开属性
python支持多继承:一个子类可以继承多个父类,如果多个父类中包含了同名属性,以左侧的父类为准
class Aniaml:
name=None
__age=0
def eat(self):
print(self.name+"正在吃东西")
#Bird类继承了Aniaml父类,得到了Aniaml类的公开属性
class Bird (Aniaml):
def fly(self):
print("鸟在飞")
bird =Bird()
bird.name="糖豆"
bird.fly()
bird.eat()
在python中继承中的一些特点:
- 子类不重写 __init__,实例化子类时,会自动调用父类定义的 __init__。
- 子类重写了__init__ 时,实例化子类,就不会调用父类已经定义的 __init__
- 子类重写了__init__ 时,要使用父类的构造方法,可以使用 super 关键字,语法:super(子类,self).__ init __(参数);也可以使用如下格式调用:父类名.__init__(self, 参数列表
这里和java不一样的是,java是子类先帮父类构造,如果父类只包含无参的构造方法,创建子类对象会自动先调用父类无参的构造方法,如果父类存在包含参数的构造方法,就要使用super关键字显示调用
class A:
age=0
def __init__(self,*args):
self.age=args[0]
print("父类A的有参构造方法",{self.age})
print("离开父类的有参构造方法")
class B (A):
def __init__(self,age):
print("子类B的构造方法")
super(B, self).__init__(age)
print("离开子类B")
class C(B,A): #这里不是A,B这样的传参顺序,是因为B类继承了A类,如果是A,B顺序,先创建A对象,创建B对象也会创建A对象,python不允许这样
def __init__(self, age):
super(C, self).__init__(age)
print("子类C的构造方法")
print("离开子类C")
C(10)
- 2、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)
重写
子类可以对父类方法重写,调用时执行重写后的方法
class Aniaml:
name=None
__age=0
def eat(self):
print(self.name+"正在吃东西")
#Bird类继承了Aniaml父类,得到了Aniaml类的公开属性
class Bird (Aniaml):
def fly(self):
print("鸟在飞")
def eat(self): #对父类的这个方法进行重写
print("有一只鸟正在吃东西")
bird =Bird()
bird.fly()
bird.eat()
super关键字:在子类中调用父类属性
super().成员变量
super().成员方法()
重载
Python 是一种动态语言,不需要声明变量类型。该函数可以接受任何类型的参数,因此不支持根据参数类型进行重载。但是可以支持运算符重载
python支持运算符如下:
class A:
def __init__(self,x,y):
self.x=x
self.y=y
def __str__(self):
return f"x={self.x},y={self.y}"
def __sub__(self, other):
return A(self.x-other.x,self.y-other.y)
a=A(1,2)
b=A(3,6)
print(a.__sub__(b)) # 1-3=-2 2-6=-4
多态
在完成某一个行为时,通过不同的对象,执行不同的方法
class AC:
def ac(self):
pass
pass关键字起到占位符的作用,ac方法没有方法体,pass是为了让ac方法符合语法规定添加的。
这样没有方法体的方法称为抽象方法,包含抽象方法的类就是抽象类
抽象类是要被继承的,子类要重写抽象父类的抽象方法
class AC:
def ac(self):
pass
class A (AC):
def ac(self):
print("A子类重写父类AC的ac方法")
class B (AC):
def ac(self):
print("B子类重写父类AC的ac方法")
def printf(tmp :AC):
tmp.ac()
printf(A())
printf(B())
printf方法的执行,取决于参数tmp的实际类型
tmp是A类型,它实际上拥有自己的 ac()方法。调用 tmp.ac()总是先查找它自身的定义,如果没有定义,则顺着继承链向上查找,直到在某个父类中找到为止。
python是动态类型的语言,所以,传递给函数 printf(tmp)的参数tmp 不一定是 AC 或 AC 的子类型。任何数据类型的实例都可以,只要它有一个ac()的方法即可
单下划线、双下划线、头尾双下划线说明:
-
__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。
-
_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *
-
__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。