面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,素以Dog也是一个Animal。继承可以让子类具有父类的特性,提高了代码的复用性。继承从设计上是一个增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法
- 实例化:创建一个类的实例,类的具体对象。
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
封装
隐藏对象的属性和实现细节,只对外提供必要的方法,相当于将“细节封装起来”,只对外暴露“相关的调用方法”。封装可以通过“私有属性、私有方法”的方式,实现封装。
实例
如果要让内部属性不被外部访问,可以把属性的名称前加上两个下划线__,在Python中,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
代码如下:class Student(object): def __init__(self, name, score): self.__name = name self.__score = score def print_score(self): print('%s: %s' % (self.__name, self.__score))
如果外部代码要获取name和score,可以给Student类增加
get_name
和get_score
这样的方法:class Student(object): #这里的代码和上面一样,定义两个私有属性__name和__score ... def get_name(self): return self.__name def get_score(self): return self.__score
同时又允许外部代码修改score可以再给Student类增加set_score方法:
class Student(object): #代码同上 ... def set_score(self, score): self.__score = score
继承
我们不想把同一段代码写好几次,之前使用的函数避免了这种情况。但现在又有个更微妙的问题。如果已经有了一个类,又想建立一个非常类似的类,只是添加几个方法。
比如有人类,我们又想在人类的基础上建立学生类、医生类,教师类。因为他们都具有共同的属性和方法,比如都有 姓名 、年龄 、性别 等共同属性,还有吃饭、睡觉等共同方法。我们就可以写一个人类作为父类,包括姓名、年龄、性别等属性和吃饭睡觉等方法。然后再写多个子类继承父类的这些属性和方法。
但需要注意的是,父类的私有属性和方法不会被子类继承
子类对父类方法的重写
子类继承父类时,子类的方法签名和父类一样,此时子类重写了父类的方法,当生成子类对象时,调用的是子类重写的方法。
下面上代码:#父类 class Person(): def __init__(self,name=None,age=None,sex=None): self.name=name self.age=age self.sex=sex def eat(self): print("%s正在吃饭"%self.name) #学生子类:继承人类父类的属性 class Student(Person): def __init__(self,name=None,age=None,sex=None,score=None): # self.name=name # self.age=age # self.sex=sex #Person.__init__(self,name,age,sex) super().__init__(name,age,sex) self.score=score def study(self): self.eat() print("%s在学习,考了%d分"%(self.name,self.score)) #方法的重写,调用的时候调用子类的方法 #可以对自定义的方法进行重写 def eat(self): print("%d的%s正在吃饭,他是%s的"%(self.age,self.name,self.sex)) #也可以对自带的object类的方法进行重写。 def __str__(self): return "姓名:{0},年龄:{1},性别:{2},成绩:{3}".format(self.name,self.age,self.sex,self.score) def __lt__(self,other): """ if isinstance(other,Student): return self.age<other.age else: return False """ if self.name==other.name: return self.age<other.age else: return self.name<other.name #实例化 stu=Student("汤姆",20,"男",80) stu.study() stu.eat() list1=[] stu1=Student("杰克",20,"男",90) stu2=Student("杰森",21,"男",20) stu3=Student("杰森",12,"女",50) list1.append(stu) list1.append(stu1) list1.append(stu2) list1.append(stu3) for student in list1: print(student) list1.sort() for student in list1: print(student)
Python支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:
class 子类类名(父类1[,父类2,...])class A: def __init__(self,a=None): self.a=a def test(self): print("A...test") class B: def __init__(self,b=None): self.b=b def test(self): print("B...test") class C(B,A): def __init__(self,a): A.__init__(self,a) def t(self): A.test(self)#调用A的test() super().test()#这个调用的也是B的test print("C....t") c=C("aa") #默认调用的是父类B的test方法,因为在class C(B,A),B在A前面 c.test() c.t()
如果在类定义中没有指定父类,默认父类是object类,也就是说,object是所有类的父类,里面定义了一些所有类共有的默认实现,如:__new__()。
定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:
父类名.__init__(self,参数列表)
class Person: def say_age(self): print('不知道') class Student(Person):#子类中为空 pass s = Student() s.say_age()
运行结果为:不知道
从上面一个简单地例子来看,子类Student已经继承了父类Person,并且可以自由调用方法。
class Person: def __init__(self,name,age): self.name = name self.__age = age #私有属性 def say_age(self): print('不知道') class Student(Person): def __init__(self,name,age,score): Person.__init__(self,name,age) #引用中形参是子类中的形参,不是父类中的。而且必须显式的调用,不然解释器不会调用 self.score = score s = Student('cys',18,100) s.say_age() print(s.name) print(s._Person__age)
运行结果为:不知道
cys
18
从上面代码中可以看出,继承成功后子类一样可以调用父类中的属性,私有属性继承后相当于子类的私有属性,需要使用调用私有属性的方法调用。
多态
当子类和父类都存在相同的方法时,我们说,子类的方法覆盖了父类的方法,在代码运行的时候,总是会调用子类的方法。这样,我们就获得了继承的另一个好处:多态。(指同一个方法调用由于对象的不同会产生不同的行为。)
让用户输入要选择的汉堡,他不需要知道内部是如何制作的,只要得到一个选择的汉堡实例对象就可以
#创建汉堡的父类,并根据父类创建几个子类 class Hamburger: def make(self): print("您没有正确选择要制作的汉堡,请重新输入") class FishHamburger(Hamburger): def make(self): print("您的鱼肉汉堡已经制作好了") class BeafHamburger(Hamburger): def make(self): print("您的牛肉汉堡已经制作好了") class ChickenHamburger(Hamburger): def make(self): print("您的鸡肉汉堡已经制作好了") #工厂类,用来判断用户输入的值并创建相应的对象 class HamburgerFactory: @classmethod def getinput(cls,temp): if temp=="1": ch=FishHamburger() elif temp=="2": ch=BeafHamburger() elif temp=="3": ch=ChickenHamburger() else: ch=Hamburger() return ch #主方法,通过用户输入的值调用工厂的类方法 while True: temp=input("请输入您要制作汉堡的序号,1.鱼肉汉堡,2.牛肉汉堡,3.鸡肉汉堡") if temp=="1" or temp=="2" or temp=="3": ch=HamburgerFactory.getinput(temp) ch.make() break else: ch=Hamburger() ch.make() continue
补充
通过类的方法mro()或者类的属性_mro_可以输出这个类的继承层次结构。
通过类的方法dir()查看对象属性
lass A:
pass
class B(A):
pass
class C(B):
pass
#mro()查看类的继承层次结构
print(C.mro()) #或者用 print(C.__mro__)
#dir()查看对象属性
a=A()
print(dir(a))
#结果如下:
[<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__',
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
第一次出这么详细的东西,不对的地方还请多多指教,平时学业繁忙,在准备专升本,见谅