一、编程范式
编程范式:按照什么方式来去编程,去实现一个功能。举个例子:做饭可以用电磁炉,也可以用燃气灶。不同的编程范式本质上代表对各种类型的任务采取的不同的解决问题的思路,两种最重要的编程范式分别是面向过程编程和面向对象编程。
二、两大编程范式
1、面向过程编程
面向过程的思想是把一个项目、一件事情按照一定的顺序,从头到尾一步一步地做下去,先做什么,后做什么,一直到结束。这种思想比较好理解,其实这也是一个人做事的方法,我们之前编程的思想也都是使用这种思想。这种编程思想只要前面有一个步骤变了,那么后面的就也要变,维护成本高。
面向过程多用于编写一次性脚本或代码量极少的简单小程序。
2、面向对象编程
面向对象--Object Oriented Programming,简称oop。面向对象的思想是把一个项目、一件事情分成更小的项目,或者说分成一个个更小的部分,每一部分负责什么方面的功能,最后再由这些部分组合而成为一个整体。这种思想比较适合多人的分工合作,就像一个大的机关:分各个部门,每个部门分别负责某样职能,各个部门可以不用理解其他部门的事,只要完成自己那一部分的事情就OK了。
三、面向对象的优点
对于编程初学者来讲,OOP不是一个很容易理解的编程方式,虽然大家都很清楚概念以及语法,但是一到真正写程序的时候,还是喜欢用函数式编程来写代码。特别是初学者,很容易陷入一个窘境就是“我知道面向对象,我也会写类,但我依然没发现在使用了面向对象后,对我们的程序开发效率或其它方面带来什么好处,因为我使用函数编程就可以减少重复代码并做到程序可扩展了,为啥子还用面向对象?”无论用什么形式来编程,我们都要明确记住以下原则:
1、写重复代码是非常不好的低级行为
2、你写的代码需要经常变更
开发正规的程序跟写个运行一次就扔了的小脚本一个很大不同就是:你的代码总是需要不断的更改,不是修改bug就是添加新功能等。所以为了以后更方便程序的修改及扩展,代码一定要遵循易读、易改的原则(专业数据叫可读性好、易扩展)。
函数的出现帮我们轻松的解决重复代码的问题,其实OOP编程的主要作用也是使你的代码修改和扩展变的更容易,易维护、减少代码量。
那么要问了,函数都能实现这个需求了,还要OOP干什么用? 呵呵,说这话就像古时候,人们打仗杀人都用刀,后来出来了枪,它的功能跟刀一样也是杀人。然后小白就问,既然刀能杀人了,那还要枪有什么用。显而易见,因为枪能更好更快更容易的杀人。函数编程与OOP的主要区别就是OOP可以使程序更加容易扩展和易更改。
四、面向对象特性
面向对象的三大特性:封装、继承、多态
1、类:class
类,对比现实世界来说就是一个种类,一个模型。一个类即是对一类拥有相同属性的对象的抽象、蓝图、原型。
在类中定义了这些对象的都具备的属性(variables(data))、共同的方法。类由属性和方法组成,类的属性是对数据的封装,而类的方法是对类的行为的封装
例:鸟类的相同的属性就包含:有翅膀,会飞,能吃,能叫,就可以抽取出一个蓝图原型为鸟类
2、对象:object
对象,也就是指模型造出来的具体的东西
一个对象即是一个类的实例化后实例,一个类必须经过实例化后才可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性。就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同。
3、实例化
初始化一个类,造了一个对象。把一个类变成一个具体的对象的过程,叫做实例化。
4、封装
把一些功能的实现细节不对外暴露,类中对数据的赋值、内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的数据和方法。
比如说造的一个人,你把他身体内部的什么心肝脾肺肾都封装起来了,其他人都看不到,你直接找这个人。
5、继承
一个类可以派生出子类,在这个父类里定义的属性、方法自动被子类继承。比如说你继承了你父亲的姓。
python3中多继承都是广度优先,python2中经典类的多继承是深度优先,新式类的多继承是按照广度优先的。
继承是为了代码的重用
6、多态
对不同类的对象发出相同的消息将会有不同的行为。一种接口,多种实现
比如:你的老板让所有员工在九点钟开始工作, 他只要在九点钟的时候说:“开始工作”即可,而不需要对销售人员说:“开始销售工作”,对技术人员说:“开始技术工作”, 因为“员工”是一个抽象的事物, 只要是员工就可以开始工作,他知道这一点就行了。至于每个员工,当然会各司其职,做各自的工作。
多态就是抽象化的一种体现,把一系列具体事物的共同点抽象出来, 再通过这个抽象的事物, 与不同的具体事物进行对话。
为什么要用多态?应用程序不必为每一个子类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。
五、类
一些概念:
属性:属性就是类里面的一个变量,有类变量和实例变量。类变量是类在定义的时候就有的,实例变量是在实例化的时候才产生的变量。这个可以理解为,人是一个类,他的名字、年龄、性别就是它的属性。
方法:方法就是类的功能,也就是定义在类里面的函数,它实现了某个功能,比如说人有睡觉的功能。
构造函数:什么是构造函数,就是类在实例化的时候做的某些初始化操作,比如说人,你造一个汽车的时候,它得有颜色、型号等等。
析构函数:析构函数就是这个实例在销毁的时候做的一些操作。
1、定义类:
定义类使用class关键字,类名一般我们开发的时候首字母要大写
Python中有两种类,经典类和新式类
经典类和新型类在写的方面的区别就是经典类没有集成object的父类,新式类继承了object。
Python3.x中,类继承或不继承object类,经典类和新型类的没有区别,默认都继承object
Python2.x和Python3.x新型类和经典类区别是,在多继承时Python3.x是广度优先,Python2.x是深度优先。
# class Person(object):#这是经典类 class Person:#类,类名都以大写字母开头(这是新式类) country = 'China' #类变量 eyes = 2 ears = 2 mouth = 1 def __init__(self,name):#构造函数:函数就是这个类在初始化的时候执行的 self.name = name #绑定属性 #实例变量,成员变量 def __del__(self): #析构函数,这个实例被销毁的时候自动执行的 print("这是析构函数") def cry(self): # 方法 print('%s 哇哇哇'%self.name) print(Person.country) # 获取类属性 类名.类属性名 haha = Person('哈哈')#实例化,因为在上面的构造函数里面指定了必须传name,所以在实例化的时候要把name传进去 haha.cry() #调用实例方法
执行结果如下:
2、继承
class F: # 这是父类 def __init__(self, name, sex): self.name = name self.sex = sex def info(self): # 方法 print('name is %s sex is %s ' % (self.name, self.sex)) class S(F): # 子类,继承F这个类 pass s1 = S('牛牛', '男') # 实例化子类 s1.info() # 因为继承父类,所以父类的方法他都有
如果在父类里面有一个方法,子类里面也有同名方法,但是子类想重写一下父类的方法增加新功能。这么写:
# 继承构造函数,新式类通过super来继承,经典类通过父类类名来继承。就可以在继承基类原有的属性的同时,为本类添加特有的属性 class Animal(): # 父类 def __init__(self, name,age): self.name = name self.age = age def eat(self): print('%s在吃东西'%self.name) class Bird(Animal): # 子类 def __init__(self, name, age,color): #子类增加颜色属性 # Animal.__init__(self,name,age) #修改父类的方法,这是经典类里面的写法 super(Bird, self).__init__(name,age) # 修改父类方法,这是新式类里面的写法 # 注:init中为基类中所含有的所有属性 self.color = color def demo(self): print('%s的颜色是%s'%(self.name,self.color)) obj = Bird('啄木鸟',1,'red') #实例化子类 obj.eat() obj.demo()
多继承:
上面写的都是单继承的,python里面还支持多继承,多继承就是继承多个父类。
在python3中多继承都是广度优先的,在python2中有点不同,经典类是深度优先,新式类是广度优先。
class A: def say(self): print('A') class B(A): def say(self): print('B') class C(A): pass class D(C, B): pass s = D() s.say()
3、多态
多态:python里面是不直接支持多态的,可以通过别的方法来实现多态
通过下面的例子就可以实现一种接口,多种实现
对于下面的cry方法来说,不管你传入的是什么对象,只要有cry的方法,都会去调用它的cry方法,不用再一个个的去调用了。
# 多态 class Animal(object): # 父类 def __init__(self, name): self.name = name class Dog(Animal): # 狗类,有叫的方法 def cry(self): print('狗 [%s] 汪汪汪' % self.name) class Cat(Animal): # 猫类,有叫的方法 def cry(self): print('猫 [%s] 喵喵喵' % self.name) def cry(obj): #定义一个函数,去调用传进来的实例的cry方法 obj.cry() d1 = Dog('大黄') # 实例化狗 d2 = Dog('小黄') # 实例化狗 c1 = Cat('小白') # 实例化猫 c2 = Cat('小黑') # 实例化猫 cry(d1) # 把对象d1传进来 cry(d2) # 把对象d2传进来 objs = [d1, d2, c1, c2] # 把上面实例化的对象都放到一个list里面 for obj in objs: # 循环统一调用 cry(obj)
4、私有方法、私有属性
私有就是只有在类里面可以访问,实例化之后不可以访问和调用,有私有方法和私有属性。
私有就把变量名或者函数名前面加上"__"两个下划线,其实就是通过私有来实现封装的。
class Dog: __type = '狗' #私有属性 def cry(self): self.__test() #调用私有方法 print('私有属性%s'%self.__type) print('狗[%s]汪汪汪'%self.name) def __test(self):#私有方法 self.name = 'test' d = Dog() d.cry() #可以正常调用 d.__type() #报错,因为是私有属性,在外面不能访问 d.__test() #报错,因为是私有方法,在外面不能访问
5、静态方法、类方法
类方法:就是被classmethod()函数处理过的函数,能够直接通过类名和实例化对象进行调用(注:类方法中不能使用对象属性)
静态方法:静态方法相当于类层面的全局函数,可以通过类名和实例化对象调用。通过staticmethod()定义静态方法,静态方法没有self参数。(注:静态方法如果使用类属性,则通过类名调用)
class Stu(object): country = 'china' # 类变量,类变量 def __init__(self, name): self.name = name @staticmethod # 静态方法,不接受self。和类本身没有什么关系了,就相当于在类里面定义了一个方法而已 def say(): print('xxx') print(Stu.country) #调用类变量直接通过类名访问 @classmethod # 类方法,和静态方法不同的是,它可以使用类变量,必须要传一个值,代表的就是这个类 def hello(cls): print(cls.country) def hi(self): # 这个是实例方法 print(self.name) t = Stu('name') Stu.hello() #通过类名直接调用 Stu.say() t.hi() t.say() t.hello()
六、Python的垃圾回收机制
Python采用垃圾回收机制来清理不再使用的对象,Python中提供了gc模块来释放不再使用的对象。
python采用“引用计数”的方式来处理回收,也就是说当某个对象在其作用域内再也不被其它对象引用的时候,Python就自动清除对象。
Python中也提供了collect()函数,来一次性收集所有待处理的对象,并返回待处理对象的数目(gc.collect())