Python像是OOP和FP的结合,就是既有OOP的特点,但是却不绝对的OOP,然后又有FP的特点,同样也不纯粹。OOP里的我们常见的getter和setter在Python却没有,当然了,这不影响实际的使用,OPP里的多态在Python中也表现的不那么明显。同样对于FP来说,Python无意中做了一些FP的支持,但是和纯粹的FP语言还是有很大的差异。在实际的开发中个人倾向于Python,因为面对一般的开发OOP能够满足大部分场景业务,同样FP的使用也能大大减轻纯OOP开发时的一些开发强度。
功能介绍
Python的类class实际上就是数据类型。Python的所有内置数据类型都是类。
使用说明
#类的定义,伪代码class MyClass:body# 其中body部分由一系列的Python语句组成,通常包含变量赋值和函数定义语句。不过这些都不是必须的,可以至包含一条pass语句## 类的定义class Person:def __init__(self,name,age):self.name = nameself.age = agedef hi(self):print(self.name+'say Hello at'+str(self.age))# 类的实例化instance = MyClass() #只需要降类名称作为函数进行调用,就可以创建该类的对象,即进行类的实例化##Person实例化p = Person('关羽',17)#Person类中的__init__方法,类似Java中的构造器,但其实什么都没构造,只是可以用于初始化类的字段。与Java和C++不同,Python的#类只能包含一个__init__方法。
实例变量
实例变量是OOP的最基本的特征
class Circle:def __init__(self):self.radius = 1# radius就是Circle的实例变量,在Python中,可以按需创建实例变量,只要给类实例的变量字段赋值即可#伪代码如下instance.variable = value#如果变量不存在,那么就会自动创建
方法
对于方法和函数的区别,有着各种的说法,也有认为两者没有区别的观点,在实际的使用中可能没有区别,但是当我看到这句话的时候,感觉两者之间的区别,清晰了起来,方法是与某个类关联的函数。
方法从本质上来说就是一个函数,不过它的位置特殊,在某个类中,这样的解释个人认为是比较合理的。
#方法调用,方法调用语句包括实例名,加上一个句点,再加上要再该实例上调用的方法class Circle:def __init__(self):self.radius = 1def area(self):return self.radius * self.radius * 3.14#area方法被定义为类定义内部的函数。方法的第一个参数一定是发起调用的实例,按惯例命名为self。在许多其他语言中,包括java,这里的实例通常命名为this
类变量
类变量是与类关联的变量,而不是与类的实例关联。
class Circle:pi = 3.14 #此处的pi即为类变量,有点类似Java中的类常量def __init__(self):self.radius = 1def area(self):return self.radius * self.radius * Circle.pi
静态方法和类方法
与Java一样,即使没有创建类的实例,静态方法也是可以调用的,当然通过类的实例,也可以调用。使用@staticmethod装饰器来创建静态方法。
类方法与静态方法很相像,都可以在类的对象被实例化之前进行调用,也都能通过类的实例来调用。但是类方法隐式地将所属类作为第一个参数进行传递。使用@classmethod修饰器来创建类方法。
class Circle:all_circles = []pi = 3.14def __init__(self, r=1):self.radius = rself.__class__.all_circles.append(self)def area(self):return self.__class__.pi * self.radius * self.radius# 静态方法@staticmethoddef total_area():total = 0for c in Circle.all_circles:total = total + c.area()return total# 类方法@classmethoddef total_area_cl(cls):total = 0for c in cls.all_circles:total = total + c.area()return total
继承
在Python中使用继承类通常有两个要求,第一个要求是定义类的层次结构;第二个要求是必须显式调用类的init方法
class Animal:def __init__(self):self.name = 'Animal'class Tiger(Animal): #说明该Tiger类继承自类Animaldef __init__(self, color):super().__init__()self.color = colordef run(self):print('Tiger runs fast in ' + self.color)class Whale(Tiger):#同理,类Whale继承自Tiger类,虽然逻辑不合理,鲸鱼不会是老虎的子类def __init__(self, color):super().__init__(color) #调用父类的构造方法,将color初始化self.swimming = Truedef swim(self):if self.swimming:print('Swimming in sea with color ' + self.color)w = Whale('Blue')w.swim() #Swimming in sea with color Blue
私有变量和私有方法
大多数编程语言在定义私有变量时,都是通过类似private的关键字来实现。Python中的约定比较简单,名称以双下划线__开头但是不以它结尾的方法或实例变量,都是私有的,其他则都不是私有部分
class Mine:def __init__(self):self.x = 2self.__y = 3 #私有变量def print_y(self):print(self.__y)m = Mine()print(m.x)#2print(m.__y)#报错m.print_y() #3
使用@property
在Python中没有我们常见的getter和setter方法,代码变得简洁了,但是在某些场合,可能需要setter和getter更方便一点。如把值赋给实例变量之前就需要先读取到该值,或者需要方便地动态计算出属性值。Python的解决方案是使用属性property。property既能够通过类似getter和setter的方法间接访问到实例变量,又能用上直接访问实例变量的句点表示法。(个人理解:用访问变量的方式来调用方法,亦或方法化的访问变量)
class Temperature:def __init__(self):self.temp_fahr = 0@propertydef temp(self):return (self.temp_fahr - 32) * 5 / 9@temp.setterdef temp(self, new_temp):self.temp_fahr = new_temp * 9 / 5 + 32t = Temperature()print(t.temp) #-17.77777777777778t.temp = 34print(t.temp_fahr) #93.2
多重继承
多重继承是指对象从多个父类继承数据和行为。在Java中不允许多重继承,但是提供了接口机制。Python对多重继承没有类似的限制,类可以继承自任意数量的父类,方式与从单个父类继承是一样的。
class E:passclass F:passclass G:passclass D(G):passclass C:passclass B(E,F):passclass A(B,C,D):pass#如果有多个类共用相同的方法名时,调用哪个方法取决于Python查找父类的顺序。在最简单的情况下,Python将按照从左到右的顺序查找所有基类,#但在进入下一个基类之前,总是会查看当前基类的所有祖先类。
创建过深的继承层次结构可能是一种危险的事情,从这点来说,个人不是很推荐使用多重继承。
鸭子类型Duck Type
在Python中有一个Java没有并且觉得稍微有点不可思议的特征,就是鸭子类型。什么是鸭子类型呢。
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。
即对象的类型是什么没有关系,只要它满足被调用的要求,那么它就是该类型
class Duck:def walk(self):print('Duck walk')class Whale:def walk(self):print('Whale Swimming')def walk(d): #对象dd.walk() #该对象需要有一个walk方法duck = Duck()whale = Whale()walk(duck) #duck类型有walk方法walk(whale) #whale类型也有walk方法,所以两个方法的调用都没有问题#以上打印如下
练习题
- 声明类Student,有属性名字name和年龄age,有方法学习study和run方法
- 声明类Junior继承自Student类,增加exam方法(方法体自定义即可)
