一句废话都没有的Pycharm(十二):封装、继承、多态及特殊属性和方法
介绍
- 1.编程思想
- 1.1 面形对象
- 1.1.1. 封装
- 1.1.2 继承
- 1.1.3 多态
- 1.1.4 特殊属性和方法
- 1.1 面形对象
1.编程思想
首先我们要明确两大编程思想:面向过程和面形对象。
通俗来解释一下它们,我现在想吃佛跳墙,面向过程指的就是我自己按照烹饪的步骤一步一步去做;面向对象就是我直接去饭店,点了一份佛跳墙。这两种编程思想并不冲突,而是相辅相成的。 当遇到的对象比较简单时,我们很容易通过面性过程自己去解决它,当遇到的对象较为复杂时,我们很难一步一步解决它,面向对象可以帮助我们理清思路、将难化简。
1.1面形对象
面向对象的三大特征:
1.1.1. 封装
类是对属性和方法的封装。
python中没有专门的修饰符表示属性的私有,因此,如果不希望该属性在类对象外部被访问,前面加两个“_”。
如:
#封装
class Club_Mumber():
def __init__(self,name,age):
self.name=name
self.__age=age#该属性在类对象外部不能被访问
def info(self):
print(self.name,self.__age)
mem1=Club_Mumber('李雷',29)
mem1.info()
print(mem1.name)
#print(mem1.__age)#异常:'Club_Mumber' object has no attribute '__age'
结果:
但是如果想要访问加了两个“_”的属性,可以通过,内置函数dir()
查询指定对象的所有属性。
如:
print(dir(mem1))
结果(这里只截取里部分):
我们可以理解为__age
被更名为_Club_Mumber__age
,所以,print(mem1.__age)
不能输出age。接下来试着输出print(mem1._Club_Mumber__age)
结果:
当然,当我们设立了不想被在外部访问的属性,还是尽量不要去访问它。(既然你不想讲话,就不要开腔。😂)
1.1.2 继承
创建语法:
class 子类类名(父类1,父类2...):
pass
如果一个类没有继承任何类,则默认继承objec。
定义子类时,必须在其构造函数中调用父类的构造函数。
python支持多继承。
代码:
#继承
class Person(object):#Person继承objec类
def __init__(self,name,age):
self.name=name
self.age=age
def infor(self): #方法
print(self.name,self.age)
#定义子类
class Student1(Person):#Student1继承Person类
def __init__(self,name,age,numb):
super().__init__(name,age)#定义子类时,必须在其构造函数中调用父类的构造函数
self.numb=numb
class Teacher(Person):#Teacher继承Person类
def __init__(self,name,age,tea_year):
super().__init__(name,age)#定义子类时,必须在其构造函数中调用父类的构造函数
self.tea_year=tea_year
#创建对象
stu3=Student1('崔六',21,'10001')
tea1=Teacher('刘梅',56,30)
#调用
stu3.infor()
tea1.infor()
#多继承
class A(object):
pass
class B(object):
pass
class C(A,B):
pass
结果:
我们发现学生的学号和教师的教龄并没有输出,因此引入下面内容。
方法重写: 如果对父类的某个属性或方法不满意,可以在子类中对其进行重写。也就是说,父类不能满足我们的需求,子类就自己重写。
子类重写后的方法中,可以通过super.().xxx()
来将父类输出的和子类输出都输出来。
修改上面代码:
#继承
class Person(object):#Person继承objec类
def __init__(self,name,age):
self.name=name
self.age=age
def infor(self): #方法
print(self.name,self.age)
#定义子类
class Student1(Person):#Student1继承Person类
def __init__(self,name,age,numb):
super().__init__(name,age)#定义子类时,必须在其构造函数中调用父类的构造函数
self.numb=numb
def infor(self):#子类重写
super().infor()#将父类infor的内容也一起输出
print('学号:',self.numb)
class Teacher(Person):#Teacher继承Person类
def __init__(self,name,age,tea_year):
super().__init__(name,age)#定义子类时,必须在其构造函数中调用父类的构造函数
self.tea_year=tea_year
def infor(self): # 子类重写
super().infor() # 将父类infor的内容也一起输出
print('教龄:',self.tea_year)
#创建对象
stu3=Student1('崔六',21,'10001')
tea1=Teacher('刘梅',56,30)
#调用
stu3.infor()
tea1.infor()
结果:
object类:
object类是所有类的父类,也就是说所有类都包含object类的属性和方法。
object类中的_str_()
方法可以返回“对象的描述”,可以帮我们查询对象的信息.我们可以重写_str_()
,让它输出对象的属性值。
代码:
class Person(object):#Person继承objec类
def __init__(self,name,age):
self.name=name
self.age=age
def infor(self): #方法
print(self.name,self.age)
def __str__(self):
return '我叫{0},我今年{1}岁了。'.format(self.name,self.age)
Per1=Person('赵子',12)
print(Per1)
结果:
1.1.3 多态
多态是多种形态。动态语言的多态崇尚“鸭子类型”,也就是说,有一只鸟,它走路像鸭子,游泳像鸭子,那么它就可以被称为鸭子。也就是说,一个变量所引用的对象是什么类型,仍然可以通过,变量调用方法,动态决定调用哪个对象中的方法。
有点绕,看例子:
#多态
class Animal(object):
def eat(self):
print('动物要吃东西。')
class Duck(Animal):
def eat(self):
print('鸭子吃小鱼。')
class Tiger(Animal):
def eat(self):
print('老虎吃肉。')
class Human(object):
def eat(self):
print('人干饭。')
#定义一个函数
def fun(a):
a.eat()
#调用函数
fun(Animal())
fun(Duck())
fun(Tiger())
fun(Human())#Human和Animal、Duck、Tiger不存在继承关系,但是它有eat()方法,索引它也会调用Person当中的eat()方法
结果:
Human和Animal、Duck、Tiger不存在继承关系,但是它有eat()方法,索引它也会调用Person当中的eat()方法。
python是动态语言。
而静态语言要实现多态,需要以下三个必要条件:
- 继承
- 方法重写
- 父类引用指向子类对象
这里就不再过多说明。
动态语言关注方法,有就可以用,而静态语言关注继承关系。
1.1.4 特殊属性和方法
两个下划线开始两个下划线结束的属性和方法就叫特殊的属性和方法。
特殊属性:
骨骼图:
代码:
#特殊属性
class A(object):
pass
class B(object):
pass
class C(A,B):
def __init__(self,name,age):
self.name=name
self.age=age
class D(A):
pass
s=C('Tom',19)
print(s.__dict__)#输出对象所绑定的所有属性和方法的字典
print(s.__class__)#C 输出对象所属的类
print(C.__bases__)#A,B 输出其所有的父类
print(C.__base__)#A 输出其基类,离C最近的父类
print(C.__mro__)#C继承A继承B继承了objec,类的层次结构
print(A.__subclasses__())#输出子类的 列表
结果:
特殊方法:
骨骼图:
代码:
##特殊方法
class ST(object):
def __init__(self,name):
self.name=name
def __add__(self, other):
return self.name+other.name
def __len__(self):
return len(self.name)
st1=ST('Peter ')
st2=ST('Alice')
print(st1+st2)
print(len(st1))
#__new__()、__init__()
class PE(object):
def __new__(cls, *args, **kwargs):
print('__new__()已执行,cls的id为{0}'.format(id(cls)))#140395033954768
p=super().__new__(cls)
print('创建的对象的id为{0}'.format(id(p)))#4331788752
return p
def __init__(self,name,age):
print('__init__()被调用,self的id值{0}'.format(id(self)))#4331788752
self.name = name
self.age = age
print('object的id为:{}'.format(id(object)))#4328974608
print('PE的id为:{}'.format(id(PE)))#140395033954768
pe1=PE('唐丽',11)
print('pe1的id为:{0}'.format(id(pe1)))#4331788752
结果:
关于__new__()、init()的传参: