Python像是OOP和FP的结合,就是既有OOP的特点,但是却不绝对的OOP,然后又有FP的特点,同样也不纯粹。OOP里的我们常见的getter和setter在Python却没有,当然了,这不影响实际的使用,OPP里的多态在Python中也表现的不那么明显。同样对于FP来说,Python无意中做了一些FP的支持,但是和纯粹的FP语言还是有很大的差异。在实际的开发中个人倾向于Python,因为面对一般的开发OOP能够满足大部分场景业务,同样FP的使用也能大大减轻纯OOP开发时的一些开发强度。

功能介绍

Python的类class实际上就是数据类型。Python的所有内置数据类型都是类。

使用说明

  1. #类的定义,伪代码
  2. class MyClass:
  3. body
  4. # 其中body部分由一系列的Python语句组成,通常包含变量赋值和函数定义语句。不过这些都不是必须的,可以至包含一条pass语句
  5. ## 类的定义
  6. class Person:
  7. def __init__(self,name,age):
  8. self.name = name
  9. self.age = age
  10. def hi(self):
  11. print(self.name+'say Hello at'+str(self.age))
  12. # 类的实例化
  13. instance = MyClass() #只需要降类名称作为函数进行调用,就可以创建该类的对象,即进行类的实例化
  14. ##Person实例化
  15. p = Person('关羽',17)
  16. #Person类中的__init__方法,类似Java中的构造器,但其实什么都没构造,只是可以用于初始化类的字段。与Java和C++不同,Python的
  17. #类只能包含一个__init__方法。

实例变量

实例变量是OOP的最基本的特征

  1. class Circle:
  2. def __init__(self):
  3. self.radius = 1
  4. # radius就是Circle的实例变量,在Python中,可以按需创建实例变量,只要给类实例的变量字段赋值即可
  5. #伪代码如下
  6. instance.variable = value
  7. #如果变量不存在,那么就会自动创建

方法

对于方法和函数的区别,有着各种的说法,也有认为两者没有区别的观点,在实际的使用中可能没有区别,但是当我看到这句话的时候,感觉两者之间的区别,清晰了起来,方法是与某个类关联的函数
方法从本质上来说就是一个函数,不过它的位置特殊,在某个类中,这样的解释个人认为是比较合理的。

  1. #方法调用,方法调用语句包括实例名,加上一个句点,再加上要再该实例上调用的方法
  2. class Circle:
  3. def __init__(self):
  4. self.radius = 1
  5. def area(self):
  6. return self.radius * self.radius * 3.14
  7. #area方法被定义为类定义内部的函数。方法的第一个参数一定是发起调用的实例,按惯例命名为self。在许多其他语言中,包括java,这里的实例通常命名为this

类变量

类变量是与类关联的变量,而不是与类的实例关联。

  1. class Circle:
  2. pi = 3.14 #此处的pi即为类变量,有点类似Java中的类常量
  3. def __init__(self):
  4. self.radius = 1
  5. def area(self):
  6. return self.radius * self.radius * Circle.pi

静态方法和类方法

与Java一样,即使没有创建类的实例,静态方法也是可以调用的,当然通过类的实例,也可以调用。使用@staticmethod装饰器来创建静态方法。
类方法与静态方法很相像,都可以在类的对象被实例化之前进行调用,也都能通过类的实例来调用。但是类方法隐式地将所属类作为第一个参数进行传递。使用@classmethod修饰器来创建类方法。

  1. class Circle:
  2. all_circles = []
  3. pi = 3.14
  4. def __init__(self, r=1):
  5. self.radius = r
  6. self.__class__.all_circles.append(self)
  7. def area(self):
  8. return self.__class__.pi * self.radius * self.radius
  9. # 静态方法
  10. @staticmethod
  11. def total_area():
  12. total = 0
  13. for c in Circle.all_circles:
  14. total = total + c.area()
  15. return total
  16. # 类方法
  17. @classmethod
  18. def total_area_cl(cls):
  19. total = 0
  20. for c in cls.all_circles:
  21. total = total + c.area()
  22. return total

继承

在Python中使用继承类通常有两个要求,第一个要求是定义类的层次结构;第二个要求是必须显式调用类的init方法

  1. class Animal:
  2. def __init__(self):
  3. self.name = 'Animal'
  4. class Tiger(Animal): #说明该Tiger类继承自类Animal
  5. def __init__(self, color):
  6. super().__init__()
  7. self.color = color
  8. def run(self):
  9. print('Tiger runs fast in ' + self.color)
  10. class Whale(Tiger):#同理,类Whale继承自Tiger类,虽然逻辑不合理,鲸鱼不会是老虎的子类
  11. def __init__(self, color):
  12. super().__init__(color) #调用父类的构造方法,将color初始化
  13. self.swimming = True
  14. def swim(self):
  15. if self.swimming:
  16. print('Swimming in sea with color ' + self.color)
  17. w = Whale('Blue')
  18. w.swim() #Swimming in sea with color Blue

私有变量和私有方法

大多数编程语言在定义私有变量时,都是通过类似private的关键字来实现。Python中的约定比较简单,名称以双下划线__开头但是不以它结尾的方法或实例变量,都是私有的,其他则都不是私有部分

  1. class Mine:
  2. def __init__(self):
  3. self.x = 2
  4. self.__y = 3 #私有变量
  5. def print_y(self):
  6. print(self.__y)
  7. m = Mine()
  8. print(m.x)#2
  9. print(m.__y)#报错
  10. m.print_y() #3

使用@property

在Python中没有我们常见的getter和setter方法,代码变得简洁了,但是在某些场合,可能需要setter和getter更方便一点。如把值赋给实例变量之前就需要先读取到该值,或者需要方便地动态计算出属性值。Python的解决方案是使用属性property。property既能够通过类似getter和setter的方法间接访问到实例变量,又能用上直接访问实例变量的句点表示法。(个人理解:用访问变量的方式来调用方法,亦或方法化的访问变量

  1. class Temperature:
  2. def __init__(self):
  3. self.temp_fahr = 0
  4. @property
  5. def temp(self):
  6. return (self.temp_fahr - 32) * 5 / 9
  7. @temp.setter
  8. def temp(self, new_temp):
  9. self.temp_fahr = new_temp * 9 / 5 + 32
  10. t = Temperature()
  11. print(t.temp) #-17.77777777777778
  12. t.temp = 34
  13. print(t.temp_fahr) #93.2

多重继承

多重继承是指对象从多个父类继承数据和行为。在Java中不允许多重继承,但是提供了接口机制。Python对多重继承没有类似的限制,类可以继承自任意数量的父类,方式与从单个父类继承是一样的。

  1. class E:
  2. pass
  3. class F:
  4. pass
  5. class G:
  6. pass
  7. class D(G):
  8. pass
  9. class C:
  10. pass
  11. class B(E,F):
  12. pass
  13. class A(B,C,D):
  14. pass
  15. #如果有多个类共用相同的方法名时,调用哪个方法取决于Python查找父类的顺序。在最简单的情况下,Python将按照从左到右的顺序查找所有基类,
  16. #但在进入下一个基类之前,总是会查看当前基类的所有祖先类。

创建过深的继承层次结构可能是一种危险的事情,从这点来说,个人不是很推荐使用多重继承。

鸭子类型Duck Type

在Python中有一个Java没有并且觉得稍微有点不可思议的特征,就是鸭子类型。什么是鸭子类型呢。

当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。

即对象的类型是什么没有关系,只要它满足被调用的要求,那么它就是该类型

  1. class Duck:
  2. def walk(self):
  3. print('Duck walk')
  4. class Whale:
  5. def walk(self):
  6. print('Whale Swimming')
  7. def walk(d): #对象d
  8. d.walk() #该对象需要有一个walk方法
  9. duck = Duck()
  10. whale = Whale()
  11. walk(duck) #duck类型有walk方法
  12. walk(whale) #whale类型也有walk方法,所以两个方法的调用都没有问题
  13. #以上打印如下

Duck walk Whale Swimming

练习题

  • 声明类Student,有属性名字name和年龄age,有方法学习study和run方法
  • 声明类Junior继承自Student类,增加exam方法(方法体自定义即可)