编程范式(面向过程、面向对象)

编程范式:面向过程、面向对象

  • 面向过程
  • 面向对象
    • 对象
          • 析构函数
          • 构造函数
    • 一切皆对象
    • 面向对象可拓展总结
    • 继承与重用性
    • 继承与实现原理
    • 子类重用父类中的方法或属性
    • 组合
    • 抽象类
    • 多态与多态性
    • 封装
    • 绑定方法与非绑定方法
      • 使用场景
    • 反射
    • 内置方法介绍
    • 元类
        • exec的使用
        • type
        • 手动模拟class创建类的过程
        • 自定义元类控制类的行为
    • 异常处理
        • 语法错误
          • 逻辑错误

面向过程

其实就是一个解决问题的步骤,设计一条流水线,完成机械式的操作
优点:复杂的问题流程化,进而简单化
缺点:可扩展性差(流水线式开发中,当需要对其中进行扩展的时候,很可能对后面的功能造成影响导致扩展非常困难)
适用于扩展需求低的开发项目
应用场景:简单流程特点的脚本程序

面向对象

就是特征与功能的结合体,三大特性:继承、多态
优点:可扩展性强
(可扩展性是软件质量的指标之一)
编程范式(面向过程、面向对象)_第1张图片
缺点:编程复杂度高
应用场景:用户需求经常变化,互联网用用,游戏,企业内部应用

一系列对象相似的特征与功能的结合体
强调:不同角度得到的分类是不一样的。现实世界的认知中,是先有一个个具体的对象,后面才有类的概念;在程序的世界里,一定得先定义类,后调用类来产生对象

#先定义类
class Employee:
    company= 'sony'
    def career(self):
        print('python programmer')
    def salary(self,money):
        print('月薪:%d $'%(money))
#后产生对象
emp1=Employee()
emp2=Employee()
emp3=Employee()

定义类阶段,内部代码就会运行;调用类可以‘.’直接操作属性

对象

析构函数

*setitem()
*getitem()
*delitem()
*del()

构造函数

*init()用来为对象定制对象自己独有的方法

class Employee:
    .......
    def __init__(self,name,sex,age,):
         self.Name=name
         self.Sex=sex
         self.Age=age
    ........
    ........

emp1=Employee('lida','男',29) 
emp2 .........
emp3 .........

带__init__方法后实例化的步骤:
1,先产生一个空对象
2,触发调用__init__()函数
类实例化成对象,类中的数据属性(变量),是所有对象共有的:

  print(Employee.company,id(Employee.company))
  print(emp1.company,id(emp1.company))
  print(emp2.company,id(emp2.company))
  print(emp3.company,id(emp3.company))

输出:
sony 1574809750192
sony 1574809750192
sony 1574809750192
sony 1574809750192
(地址相同,可以看出对象取共有属性是直接取类里面的)
类中函数属性,是绑定给对象,绑定到不同的对象是不同的绑定方法

print(Employee.career)
print(emp1.career)
print(emp2.career)
print(emp3.career)

输出:

main.Employee object at 0x0000021AAF73B7F0>>
main.Employee object at 0x0000021AAF73B828>>
main.Employee object at 0x0000021AAF73B860>>
(内存地址不同)
对象调用绑定方式时,会把对象本身当成第一个参数给self

emp1.salary(8000)

输出:
月薪:8000 $

属性查找顺序:(对象本身只存放独有属性,相似特征放在类里面) 调用时优先找对象属性,如果没有再去类里面找,如果没有会去父类里找(总之查找范围在类及其父类里面),未找到则报错

xxx='from global'
class A:
    ..........
A.x='x from class'
A.xx='xx from class'
a=A()
a.x='from object'
print(a.x)
print(a.xx)
print(a.xxx)

输出:
from object
xx from class
Traceback (most recent call last):
File “F:/pyCode/test/object.py”, line 37, in
print(a.xxx)
AttributeError: ‘A’ object has no attribute ‘xxx’

一切皆对象

python3统一了类与类型的概念
定义一个类型实际上就是实例化一个对象

面向对象可拓展总结

将数据与专门操作该数据的功能整合到一起

继承与重用性

class A:
     ......
     def fun(self):
        print('from A')
 class B(A):
      .......
 b = B()
 b.fun()

输出:
from A

继承与实现原理

python允许多继承
查找顺序:合并了所有父类的MRO列表,遵循:1,子类优先父类 1,多个父类根据他在列表中的顺序被检查,如果存在多个选择则选择第一个
查找方式:深度优先(对于经典类)和广度优先(新式类),python3都是新式类

子类重用父类中的方法或属性

方式一:不依赖继承,在子类中直接调用父类的方法或属性
方式二:依赖继承,super(子类的类名,self)

组合

class student:
    def __init__(self,name,age):
         self.name=name
         self.age=age
  
 class course:
    def __init__(self,course_name,course_time):
         self.course_name=course_name
         self.course_time=course_time

yexb = student('ye xiabin',31)
java=course('java',31)
yexb.course=java

这其中student类的对象以course类对象作为其属性,这种重用的方式叫做类的组合

抽象类

#与一般类的区别:抽象类只能被继承不能被实例化

import abc
class warrior(metaclass=abc.ABCMeta):           
      playable_race='人类,兽人,牛头人'
      #定义抽象方法,无需实现功能
      @abc.abstractmethod              
      def skill(self):
          pass
      @abc.abstractmethod
       def blood(self):
           pass
      @abc.abstractmethod
      def armor(self):
          pass

class player(warrior):
     def skill(self):
          print('这是技能函数')
     def blood(self):
          print('这是生命值函数')
     def armor(self):
         print('这是护甲值函数')
         
play_a=player()
play_a.skill()
print(paly_a.playable_race)

抽象类与一般类的区别:抽象类只能被继承不能被实例化定义抽象类的方法(@abc.abstr
actmethod),在子类里面必须实现

多态与多态性

多态:同一类事物的多种形态
多态性:不用考虑对象的类型的情况下而直接使用对象
多态的好处:

def func(warrior):
    warrior.skill()
func(play_a)

1.增加了程序的灵活性
2.增加了程序的拓展性

封装

先解释下什么是隐藏属性:
双下划线开头:__xxxx, 在定义阶段会发生变形

class A:
    __x=1
    def __init__(self,name):
          self.__name=name
    def __foo(self):
        print('run foo')
    
  a=A('zoro')
  print(a.__dict__)

输出:
{’_A__name’: ‘zoro’}

(可见: __name变形成_A__name)

特点:
1.在类外部无法直接使用它obj._attrName
2.在类内部可以直接使用 (原理:因为在你引用之前,在类的定义阶段就已经自动重命名为_className__attrName的形式了)
3.子类无法覆盖父类的隐藏属性

关于变形的注意事项:
1.这种机制并没有真正限制从外部访问隐藏属性,只要知道类名和属性名就可以拼出访问属性(_类名__属性名)
2.变形过程只在类的定义发生一次,在定义后的赋值操作不变形(外部无法对类再设置隐藏属性)
3.继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的(__className)
封装的意义和用法:
封装属性:类里面隐藏一个方法,再创建一个调用这个方法的接口,外部直接使用这个接口来设置属性

class A:
     def __init__(self,name):
          self.__name=name
     def tell_info(self):
          print(self.__name)
a=A('li')
a.tell_info()

封装方法:隔离复杂度

class ATM:
    def __card(self):
        print('插卡')
    def __input(self):
        print('输入取款金额') 
    def __take_money(self):
        print('取款')
    def withdraw(self):
         self.__card()
         self.__input()
         self.__take_money()
aa=ATM()
aa.withdraw()

property

class People:
    def __init__(self,name,weight,height):
        self.name=name
        self.__weight=weight
        self.__height=height
    @property
    def bmi(self):
        return self.__weight / (self.__height**2)

p1=People('egon',75,1.85)
print(p1.bmi)

输出:
21.913805697589478
可以像访问数据属性一样调用一个方法
**也可以另写一个加上@bmi.setter的函数,实现修改

class People:
     ............
     @bmi.setter
     def weight(self,val):
         if isinstance(val,int):
             self.__weight=val
         else:
              print('值必须是数字')
p=People()
p.weight=70

输出:
20.45288531775018

绑定方法与非绑定方法

在类内部定义的函数分为:
一.绑定方法:(绑定给谁,就应该谁来调用,谁来调用就会把调用者当作第一个参数传入)
1.绑定到对象:(一般是没有被装饰器修饰的函数)
2.绑定到类:(由@classmethod修饰)
二.非绑定方法
由@staticmethod修饰无自动传值功能,就是类里定义的普通工具,类和对象均能使用它

使用场景

xSetter.py :

name='lida'
sex='boy'
age=29

(实例化成对象的不同方式:)

import xSetter
import hashlib
import time
class Person:
    def __init__(self,name,sex,age):
        self.id=self.create_id()
        self.name=name
        self.sex=sex
        self.age=age

    def get_person(self):
        print('名字:%s 证件号:%s 性别:%s 年龄:%s'%(self.name,self.id,self.sex,self.age))

    @classmethod
    def conf_setter(cls):
        obj=cls(xSetter.name,xSetter.sex,xSetter.age)
        return obj

    @staticmethod
    def create_id():
        local_time = str(time.time())
        m=hashlib.md5(local_time.encode('utf-8'))
        return m.hexdigest()

p=Person.conf_setter()       *#通过绑定到类的实例化*
p.get_person()
p1 = Person('fiona','woman',31)    *#绑定到对象的实例化*
p1.get_person()    

输出:
名字:lida 证件号:f6242afac4a7b7126de2728070b4661c 性别:boy 年龄:29
名字:fiona 证件号:1b70e5784986d242c231f3d284f7c3aa 性别:woman 年龄:31

反射

通过字符串映射到一个对象(或类)的属性
hasattr(obj,‘name’) # 判断对象是否存在一个叫name的属性
getattr(obj,‘name’,none) #获取属性name
setattr(obj,‘age’,29) #新增(或修改)对象的age属性
delattr(obj,‘age’) #删除属性

我们就可以实现字符串反射到属性:

class service:
    def run(self):
        while True:
            choose = input(">>>>>:")
            if hasattr(self,choose):
                func = getattr(self,choose)
                func()

    def get(self):
        print("get....")

    def put(self):
        print("put....")

obj = service()
obj.run()

内置方法介绍

构造函数
析构函数

元类

元类是类的类,是类的模板
元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为

exec的使用

exec参数:
参数一:字符串形式的命令
参数二:全局作用域(字典形式),如果不指定,默认为globals()
参数三:局部作用域(字典形式),如果不指定,默认为locals()

type

调用元类type(也可以自定义)来产生类

手动模拟class创建类的过程

创建类主要分为三部分:类名,类的父类,类体
编程范式(面向过程、面向对象)_第2张图片
1.创建一个空字典,再用exec去执行类体
class_dic={}
exec(class_body,globals(),class_dic)
2.调用元类type(也可以自定义)来产生类Chinense
Foo=type(class_name,class_bases,class_dic) #实例化type得到对象Foo,即我们用class定义的类Foo
print(Foo)
print(type(Foo))
print(isinstance(Foo,type))

打印:
main.Chinese’>

True

我们看到,type 接收三个参数:
第 1 个参数是字符串 ‘Foo’,表示类名
第 2 个参数是元组 (object, ),表示所有的父类
第 3 个参数是字典,这里是一个空字典,表示没有定义属性和方法
**补充:若Foo类有继承,即class Foo(Bar):… 则等同于type(‘Foo’,(Bar,),{})

自定义元类控制类的行为

异常处理

程序发生异常的信号,如果没有处理程序就会抛出异常,运行随之结束
异常错误法分为两种:

语法错误

逻辑错误

你可能感兴趣的:(笔记)