面向对象基础之 —— 面向对象编程与面向过程编程

一、面向过程(procedure-oriented programming):

  在了解面向对象编程前,我们需要先了解面向过程编程,那么什么是面向过程

  之前所写的代码大多是面向过程的,即以流程为导向,先做...后做...这其中 programer 的角色像是流水线员工、士兵,按部就班执行任务。其核心是过程,过程即解决问题的步骤,其目的是将一个复杂的问题拆分为若干个小问题,按步骤一一解决(流程化)基于该思想编写程序偏流水线式,是一种机械式思维方式

简单讲就是一种思维方式,流程化解决问题

  优点:复杂的问题流程化、进而简单化

  缺点:扩展性差,维护性差

  使用场景:主要用于底层开发,对扩展性要求较低的软件,如系统内核,脚本程序,Apache HTTP服务器

二、函数式

将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可

三、面向对象(object-oriented programming):

   实现功能的方式是各个对象的交互,面向对象编程本质:使用不同对象来完成程序。其核心是对象,对象是具有某些具体功能\特征的具体事物,它具有某些属性,基于该思想编写的程序类似与创世界中上帝的思维方式

简单说就是对象间交互

  优点

  •  I.减少代码量
  • II.可扩展性强
  • III.各个对象之间耦合度低
  • IV.可维护性高

  缺点

  • I.复杂度高于面向过程
  • II.无法预知执行结果

使用场景:需要较高的扩展性时(需要与用户交互的软件,如QQ)

 

为什么使用面向对象:

当前很多程序与用户直接打交道,而用户的需求千变万化,所以对扩展性要求非常高

面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现。类和对象是面向对象编程的两个主要方面。

就是一个模板,模板里可以包含多个函数,函数里实现一些功能,而对象是这个根据模板创建的实例,通过实例对象可以执行类中的函数。

对象:(类的实例化/实例)即具备某些特征和技能的结合体,是具体存在的某个物体。 程序中对象指方法和属性

:抽象概念,一系列对象的结合体(站的角度不同,总结出类是截然不同的)

  作用:用于标识对象与对象之间的差异,通过类就能大致了解一个对象的特征和行为

生活中是先有对象再根据对象的特征和技能 得到一个类型,程序中是先有类才能通过类来产生对象。类包括初始化方法__init__,可以理解为构造;self,理解为this等等。

 

在面向对象编程中,需要遵循以下规则:

  1.程序中必须先定义类

在python中程序的类用class关键字定义,程序中特征用变量标识,技能用函数标识,因而类中最常见的就是变量和函数的定义

class OldboyStudent: # 类名用大驼峰体,首字母都大写
                     # 补充小驼峰形式:第一个单词首字母小写,第二个首字母大写
  school='oldboy'      # 用变量来描述特征

  def choose_course(self): #定义一个函数
    print('is choosing course')
  # print('==========>')      # ==========>
强调:在类定义阶段类体代码就会立刻执行,会产生一个类的名称空间,将类体代码执行过程中产生的名字都丢进去
通过__dict__可以获取一个对象中包含的内容
print(OldboyStudent.__dict__)  # 查看类的名称空间{'__module__': '__main__', 'school': 'oldboy', 'choose_course': <function OldboyStudent.choose_course at 0x00000189231B1A60>, '__dict__': <attribute '__dict__' of 'OldboyStudent' objects>, '__weakref__': <attribute '__weakref__' of 'OldboyStudent' objects>, '__doc__': None}
print(OldboyStudent.__dict__['school'])        # oldboy
print(OldboyStudent.__dict__['choose_course']) # <function OldboyStudent.choose_course at 0x00000206BFA41A60>

OldboyStudent.__dict__['choose_course'](123)   # OldboyStudent.__dict__['choose_course']
类中的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数而已,意味着需要完全遵守函数的传参原则
OldboyStudent.__dict__['choose_course']()      # 报错

   使用对象的属性(访问属性使用 .语法)

python提供了专门访问属性(名称空间中的名字)的语法: 名称.属性

OldboyStudent.country='China' # OldboyStudent.__dit__['country']='China'
OldboyStudent.country='CHINA' # OldboyStudent.__dit__['country']='China'
print(OldboyStudent.school) # oldboy
print(OldboyStudent.choose_course) # <function OldboyStudent.choose_course at 0x0000020FDD0D1A60>
OldboyStudent.choose_course(111) # is choosing course

  类的本质就是一个名称空间/容器,从类的名称空间中可以增/删/改/查名字

OldboyStudent.school      #
OldboyStudent.school='Oldboy'  #
OldboyStudent.x=1              #
del OldboyStudent.x       #

  2.后调用类来产生对象,创建对象,类名称后加括号即可。调用类的过程,又称为类的实例化,实例化的结果称为类的对象/实例

OldboyStudent()

# 类+()不是运行类体代码,调用类会得到返回值,该返回值就是类的一个具体存在的对象/实例

# 类名+([参数]):类实例化的方式,参数是__init__方法中除了第一个self参数之外的其他参数

类中的函数第一个参数必须是self。类中定义的函数叫做 “方法”

属性与方法

对象本质也就是一个名称空间,用于存放对象自己独有的名字/属性-------成员属性(实例属性)    # 这个人有自己的姓名。

类中存放的是已经定义好(名称和值)的属性---------公共属性  

在声明类时,会定义好成员属性(成员属性的值是个变量)
在定义对象时,为成员属性(变量)赋值(位置参数)

公有属性与成员属性

公有属性/静态属性 可以直接通过类直接访问,也可以直接通过实例进行访问;
通过类的某个实例对公有属性进行修改,实际上是为该实例添加了一个与类的公有属性名称相同的成员属性,
对真正的公有属性是没有影响的,因此它不会影响其他实例获取的该公有属性的值; 通过类对公有属性进行修改,必然是会改变公有属性原有的值,对该类所有的实例是都有影响的。

成员属性可以直接通过实例对象来访问和更改;不能通过类来访问和修改
成员属性是每个实例对象独有的,更改实例A的属性不会影响其他实例对象的相同属性的值;
存放属性的位置有两个:一个是类中,一个是对象中

当每个对象的某些特征都相同时则放入类,当每个对象的某些特征都不相同时则放入对象

class OldboyStudent:     
    school='oldboy'        

    def choose_course(self):   
       print('is choosing course')
stu1=OldboyStudent()
def init(obj,x,y,z):
    obj.name=x
    obj.age=y
    obj.sex=z
# stu1.name='张三'
# stu1.age=12
# stu1.sex='male'

init(stu1,'张三',13,'male')
print(stu1.__dict__)    #{'name': '张三', 'age': 12, 'sex': 'male'}

 

在实例化过程中为对象定制自己独有的特征 __init__方法(初始化函数)

注意:该方法是在对象产生之后才会执行,只用来为对象进行初始化操作,会在创建对象时,自动执行,并传入调用类时传递的参数,可以有任意代码,但一定不能有返回值

class OldboyStudent:
    school='oldboy'
    count=0
    def __init__(self,x,y,z):    # self不需要手动传递,是一个形参,代表对象自己。可改,不建议
        self.name=x
        self.age=y
        self.sex=z
        OldboyStudent.count+=1   # 类的属性发生改变,所有的属性都会发生改变
    def choose_course(self):
        print('is choosing course')


stu1=OldboyStudent('赵大',18,'male')
stu2=OldboyStudent('王二',17,'male')
stu3=OldboyStudent('张三',16,'male')

print(OldboyStudent.count)
print(stu1.count)
print(stu2.count)
print(stu3.count)
 

调用类时发生两件事

  • 1.创造一个空对象
  • 2.自动触发类中__init__功能执行,将stu1以及调用类括号内的参数一同写入

init函数用于初始化对象,它会在创建对象时自动执行,并传入调用类时传递的参数,第一个参数表示要初始化的对象本身

属性查找

类有两种属性:数据属性和函数属性

  • 1. 类的数据属性是所有对象共享的(id都一样)
  • 2. 类的函数属性是绑定给对象用的(obj.method称为绑定方法,内存地址都不一样)

  id是python的实现机制,并不能真实反映内存地址,如果有内存地址,还是以内存地址为准

对象名称空间中定义的只有数据属性,而且是对象所独有的数据属性

查找顺序 —— 对象==》类。在obj.name会先从obj自己的名称空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常  

class OldboyStudent:
    school='oldboy'
    count=0
    def __init__(self,x,y,z):
        self.name=x
        self.age=y
        self.sex=z
        OldboyStudent.count+=1   # 类的属性发生改变,所有的属性都会发生改变
    def choose_course(self,x):
        print('is choosing course',self)

stu1=OldboyStudent('赵大',18,'male')
stu2=OldboyStudent('王二',17,'male')
stu3=OldboyStudent('张三',16,'male')

print(stu1.name)
print(stu1.school)
print(stu1.age)
类中定义的函数是类的函数属性,类可以使用,但使用的就是一个普通的函数,意味着需要完全遵循函数的参数规则
类中定义的 函数是共享个所有对象的,对象也可以使用
print(stu1.choose_course)
stu1.choose_course()
print(stu1)

对象的创建和初始化步骤时分开的,通常对象一旦创建 就应该进行初始化,所以最好将创建于初始化进行绑定

绑定方法(默认为绑定给对象):

在类中声明,没有加装饰器的函数,类下的对象可以调用。

特点:绑定给谁就应由谁调用,谁来调用就会将谁当作第一个参数(self)自动传入

绑定到对象的方法的这种自动传值的特征,决定了在类中定义的函数都要默认写一个参数self,self可以是任意名字,但是约定俗成地写出self。

class OldboyStudent:
    school='oldboy'
    count=0
    def __init__(self,x,y,z):
        self.name=x
        self.age=y
        self.sex=z

    def choose_course(self,x):
        print('%s is choosing course'%self.name)

stu1=OldboyStudent('赵大',18,'male')
# stu2=OldboyStudent('王二',17,'male')
# stu3=OldboyStudent('张三',16,'male')

stu1.choose_course(1)
# 类中定义的函数(没有被任何装饰器装饰的),其实主要是给对象使用的,而且是绑定到对象的,虽然所有对象指向的都是相同的功能,但是绑定到不同的对象就是不同的绑定方法
# 绑定方法分为两种 一种是绑定给对象的,一种绑定给类的。当要处理的数据包含在类中时,就应该绑定给类。当要处理的数据包含在对象中时,就应该绑定给对象。
# 绑定给类的方法 使用一个装饰器叫classmethod,必须有一个参数,表示当前类,参数名可自定义,不建议改

# 这是绑定给类的方法
    @classmethod
    def print_school(cls):  # 输出类里面叫school的属性
        print(cls.school)

    # 这是绑定给对象的方法
    def sayHello(self):
        print(self.name, " 说: 你好")
类的绑定方法,对象和类都能调用,并且能够自动传入这个类
 Student.print_school()  #类的调用

  stu1 = Student("印度阿三","woman",20)   #对象的调用
  stu1.print_school()

了解:

在python3中统一了类与类型,类即类型,2没有
#类型dict就是类dict
>>> list
<class 'list'>
class Foo:
    pass
obj=Foo()
print(type(obj))    # <class '__main__.Foo'>

l=[1,2,3]
print(type(l))      # <class 'list'>
l.append(4)    # 绑定~~~

非绑定方法

即不绑定给类也不绑定给对象。

特点:没有自动传入参数的效果,类和对象都能调用,就是一个普通函数。不需要访问类的数据,也不需要访问对象的数据,就可以作为一个非绑定方法。 

class Teacher:
    def __init__(self,name,sex):
        self.name = name
        self.sex = sex

    # @staticmethod 用于定义个非绑定方法
    @staticmethod
    def test_func(num):
        print("test_func run!")
        print(num)

Teacher.test_func(1)

t1 = Teacher("张三","")
t1.test_func(100)
print(t1.test_func)

 

对象之间交互

设计王者荣耀中的英雄类,每个英雄对象可以对其他英雄对象使用技能
具备以下属性:英雄名称,等级,血量和Q_hurt,W_hurt,E_hurt 三个属性,表示各技能的伤害量
具备以下技能:Q W E
三个技能都需要一个敌方英雄作为参数,当敌方血量小于等于0时输出角色死亡
class Hero(object):
    def __init__(self, name, level, hp, Q_hurt, W_hurt, E_hurt):
        self.name = name
        self.level = level
        self.hp = hp
        self.Q_hurt = Q_hurt
        self.W_hurt = W_hurt
        self.E_hurt = E_hurt

    def use_Q(self, use1):
        if use1.hp <= 0:
            print("%s挂了" % use1.name)
        else:
            use1.hp -= self.Q_hurt
            print("%s HP-%s" % (use1.name, self.Q_hurt))

    def use_W(self, use1):
        if use1.hp <= 0:
            print("%s挂了" % use1.name)
            del use1
        else:
            use1.hp -= self.W_hurt
            print("%s HP-%s" % (use1.name, self.W_hurt))

    def use_E(self, use1):
        if use1.hp <= 0:
            print("%s挂了" % use1.name)
            del use2
        else:
            use1.hp -= self.E_hurt
            print("%s HP-%s" % (use1.name, self.E_hurt))

aich = Hero("aich", 10, 1000, 500, 600, 750)
galen = Hero("galen", 11, 2000, 400, 500, 600)
raven = Hero("raven", 11, 2000, 400, 550, 660)

aich.use_Q(galen)
aich.use_Q(galen)
aich.use_Q(galen)
print(galen.hp)

raven.use_E(aich)
自己写的代码
class Garen:        #定义英雄盖伦的类,不同的玩家可以用它实例出自己英雄;
    camp='Demacia'  #所有玩家的英雄(盖伦)的阵营都是Demacia;
    def __init__(self,nickname,aggressivity=58,life_value=455): #英雄的初始攻击力58...;
        self.nickname=nickname  #为自己的盖伦起个别名;
        self.aggressivity=aggressivity #英雄都有自己的攻击力;
        self.life_value=life_value #英雄都有自己的生命值;
    def attack(self,enemy):   #普通攻击技能,enemy是敌人;
        enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

class Riven:
    camp='Noxus'  #所有玩家的英雄(锐雯)的阵营都是Noxus;
    def __init__(self,nickname,aggressivity=54,life_value=414): #英雄的初始攻击力54;
        self.nickname=nickname  #为自己的锐雯起个别名;
        self.aggressivity=aggressivity #英雄都有自己的攻击力;
        self.life_value=life_value #英雄都有自己的生命值;
    def attack(self,enemy):   #普通攻击技能,enemy是敌人;
        enemy.life_value-=self.aggressivity #根据自己的攻击力,攻击敌人就减掉敌人的生命值。

>>> g1=Garen('草丛伦')
>>> r1=Riven('锐雯雯')

# garen_hero.Q()称为向garen_hero这个对象发送了一条消息,让他去执行Q这个功能,类似的有:garen_hero.W() garen_hero.E() garen_hero.R()
大神写的代码

 

posted @ 2019-05-25 09:36  呔!妖精。。。  阅读(303)  评论(0编辑  收藏  举报