Bootstrap

Python入门基础(6)--面向对象/类和对象/魔术方法

 

面向对象基本概述

  • 面向对象(Object Oriented Programming,OOP)编程:扩展性更强、可读性更好。面向对象的编程将数据和操作数据封装到对象中,组织代码和数据的方式更接近人的思维,提高编程效率。
  • python支持面向对象、面向过程、函数式编程等多种编程范式

面向对象与面向过程编程的区别与联系


面向过程procedure oriented思维

  1. 按照解决问题的逻辑去编写代码,根据业务逻辑从上到下写代码,
  2. 面向过程编程:“程序的逻辑流程”,适合编写小范围的程序。
  3. 在思考问题时,首先分析‘怎么按照步骤去实现’,然后将问题解决拆解成若干个步骤,并将这些步骤对应成方法,一步一步的最终完成这个功能
  4. 没有精力考虑别的事情,只专注于如何完成,因此不适合做大项目


面向对象object oriented思维

  1. 是一种python的编程思想,将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程
  2. 面向对象编程:“软件中对象之间的关系”,有更多的精力去做别的事情,因此适合编写大规模的程序
  3. 思考方式:名词—类—根据需求确定属性和方法—确定之间关系
  4. 关注设计的思维(让别人去做),像是洗车找谁去洗车

例如:

第一种洗车方式(面向过程)--关注过程

  1. 自己上某宝买洗车工具。
  2. 根据自己的不多的预算买,抹布,水泵,清洁剂。
  3. 跟店小二狂砍一个小时,便宜了2块钱。
  4. 等了一周,买的东西到了,开始洗车
  5. 洗到一半,水泵坏了,泡泡还没洗干净

第二种洗车方式(面向对象)--关注结果

  1. 找一家靠谱的洗车店
  2. 给钱洗车

函数式

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

面向对象&面向对象过程:

面向对象:按人们认识客观世界的系统思维方式,采用基于对象(实体) 的概念建立模型,模拟客观世界分析、设 计、实现软件的办法。(万事万物皆对象)

面向对象编程(Object Oriented Programming-OOP):是一种解决软件复用的设计和编程方法。这种方法把软件系统中相近相似的操作逻辑和操作,应用数据、状态,以类的形式描述出来, 以对象实例的形式在软件系统中复用,以达到提高软件开发效率的作用。

面向对象的基本功能

继承、多态、封装(python无法实现像其他高级语言一样的隐藏,此处的封装就是逻辑意义上的封装)等。

面向对象编程的好处

扩展性更强、可读性更好、简化编程过程。面向对象编程就是将数据和操作对应数据相关的方法封装到类对象中。

类和对象

类和对象是面向对象编程中重要的概念

就是一个模板,模板里可以包含多个函数,函数里实现一些功能

对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

类相当于制造汽车的图纸,用这个图纸制造的汽车相当于对象


  • 类:也称为类对象,类的实例称为实例对象,类是具有一组相同或者相似特征/属性,行为/功能的一系列/多个对象的组合
  • 类(Class)由3个部分构成
    类的名称: 类名
    类的属性: 一组数据 (车的颜色,大小等)
    类的方法: 允许对进行操作的方法 (行为) (车的跑,倒车等)
  • 类在创建时,不占用内存空间,只有实例化的时候才会分配内存空间

对象

  • 对象:对象是实实在在的一个东西,是类的实例化,具象化,
  • 类是对象的抽象化,而对象是类的一个实例

类的抽象

具有相同(或者类似)属性和行为的一系列对象的集合都可以抽像出一个类

例1:小明开着他家的宝马去逛街
         小明 ->可以抽象中人类
         宝马 ->可以抽象出车类

例2:抽象坦克大战中的类
         坦克
         --类名:Tank
         --属性:血量 类型
         --方法:发射子弹
         墙
         --类名: Wall
         --属性:血量 类型
         --方法:阻挡
         子弹
         --类名:Bullet
         --属性:杀伤力

语法(类和对象)

-类名符合标识符规则:首字母大写,采用大驼峰规则
-类体中可以定义属性和方法

-属性用来描述数据,方法(即函数)来描述数据相关的操作

 

 

实例方法与属性

在类的内部(class内部定义),使用 def 关键字可以定义一个实例方法,第一个参数默认是self【名字标识可以是其他的】,实例方法是归于类的实例所有,与一般函数定义不同,类方法必须包含参数 self(可以不叫self,但是必须有这个关键字),且为第一个参数

实例方法是指所属权利归实例所有,每一个实例都可以调用

属性:

类里面定义的变量。定义在类里面,方法外面的属性称之为类属性

定义在方法里面使用self引用的属性称之为实例属性【通过类似于 self.变量名 定义】,实例属性的归属于实例

(定义属性最好不要重名,不管是哪种属性)

(两者的区别在系统分配内存空间是会有明显的不同)

 

# 定义类和对象
# 类结构  类名  属性  方法
# class 类名:
#     属性
#     方法

class Person:
    '''
    对应人的特征
    '''
    # name='小明'  #类属性
    age=20       #类属性
    '''
    对应人的行为  实例方法
    '''
    def __init__(self):
        self.name='小明'   #实例属性
        pass
    def eat(parms):
        print("大口的吃饭")
        pass
    def run(self):   #实例方法
        print('飞快的跑')
        pass
    pass
def printInfo():
    '''
    普通方法
    :return:
    '''
    pass
# 创建一个对象【类的实例化】
# 规则格式  对象名=类名()
xm=Person()
xm.eat() #调用函数
xm.run()
print("{}的年龄是:{}".format(xm.name,xm.age))

# 创建另外一个实例对象
xw=Person()
xw.eat()  #实例方法

class GoodStudent:
    def __init__(self,name,score): #self必须位于第一个参数
        self.name=name
        self.score=score
    def say_score(self):
        print("{0}的分数是:{1}".format(self.name,self.score))
s1=GoodStudent("hzh",18). #调用构造方法
s1.say_score()

__init__(self) 方法

__init__(self) 方法,初始化方法,实例化对象的时候自动调用,主要用于实例属性的声明,和完成一些初始化设置,系统在创建对象是自动调用,不需要手动调用。

*方法名左右都有下划线的方法我们称为魔术方法,是系统内部已经定义好的方法

__init__传参

如果init方法里面的属性固定了,每个类创建出来的对象属性都一样,这个时候我们是不是考虑将属性当参数在实例化对象的时候传进去,让类更通用?

 

# class Pepole:
#     def __init__(self):##init方法的创建
#         '''
#         实例属性的声明
#         '''
#         self.name='小倩'
#         self.sex='女生'
#         self.age=20
#         pass
#     def eat(self):
#         '''
#         吃的行为
#         :return:
#         '''
#         print('喜欢吃榴莲')
#     pass
#传统添加实例属性的两种方式
# xq=Pepole() 
# xq.name='小倩'  #添加实例属性
# xq.sex='女生'   #添加实例属性
# xq.age=20    #添加实例属性,直接赋值了
# xq.eat()      #传统的添加实力属性方式
# # print(xq.name,xq.sex,xq.age)
#
# xl=Pepole()  #创建出来的(完全独立的对象仍然需要重新实例化属性)
# xl.name='小倩'  #添加实例属性
# xl.sex='女生'   #添加实例属性
# xl.age=20    #添加实例属性
####添加init方法后可以直接使用
# xm=Pepole()  #在创建新对象的时候 是自动执行的,不需要专门调用init的方法
# print(xm.name) #直接输出的是默认值(在class内部就已经定义好的,如果此处再次赋值则是修改了)
# xm.name='小明'##修改class内部已经定义好的属性
# print(xm.name)

# 如果有n个这个对象  被实例化  那么就需要添加很多次这样的属性了 显然是比较麻烦
#####引入init方法
# init传递参数 改进
class Pepole:
    def __init__(self,name,sex,age):
        '''
        实例属性的声明
        '''
        self.name=name
        self.sex=sex
        self.age=age
        pass
    def eat(self,food):
        '''
        吃的行为
        :return:
        '''
        print(self.name+'喜欢吃'+food) #最好用format格式化一下
    pass

zp=Pepole('张鹏','男生',18)
print(zp.name,zp.age)
zp.eat('香蕉')
lh=Pepole('李辉','男生',28)
lh.eat('苹果')
print(lh.name,lh.age)

xh=Pepole('小花','女生',20)
xh.eat('橘子')
print(xh.name,xh.age)

总结 __init__

  1. python 自带的内置函数 具有特殊的函数   使用双下划线 包起来的【魔术方法】
  2. 是一个初始化的方法 用来定义实例属性 和初始化数据的,在创建对象的时候自动调用  不用手动去调用
  3. 利用传参的机制可以让我们定义功能更加强大并且方便的 类

Self

是什么?

self和对象指向同一个内存地址,可以认为self就是对象的引用。

self传参问题

所谓的self,可以理解为对象自己,某个对象调用其方法时,python解释器会把这个对象作为第一个参数传递给self,所以开发者只需要传递后面的参数即可。

*self本身就一个对象,实例化时,自动把创建的对象和self对应上了,因此在传参的时候不需要为self传递参数

##证明self和实例对象是同一个对象
class Person:
    def __init__(self,pro,name,food):
        
    '''
   定义类
    '''
    def eat(self):
        '''
        实例方法
        :return:
        '''
        # print('self-%s',id(self)) 
        pass
    pass
##xm是一个新的实例化对象
xm=Person()
print('xw=%s',id.(xw))
xw.eat()
###实例化对象和self的内存地址都是相同的,self和xw是同一个对象
###self就是指的实例对象本身(当类方法里只有一个self参数时)

##self传参

class Person:
    def __init__(self,pro,name,food):
        '''

        :param pro: 专业
        :param name: 姓名
        :param food: 食物
        '''
        self.pro=pro  #实例属性的定义
        self.name=name
        self.food=food
        print('----init-----函数执行')
        pass
    '''
   定义类
    '''
    def eat(self,name,food):
        '''
        实例方法
        :return:
        '''
        # print('self=%s',id(self))
        print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
        pass
    def __str__(self):
        '''
        打印对象 自定义对象 是内容格式的
        :return:
        '''
        return '%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro)
        pass
    def __new__(cls, *args, **kwargs):
        '''
        创建对象实例的方法  每调用一次 就会生成一个新的对象 cls 就是class的缩写

        场景:可以控制创建对象的一些属性限定 经常用来做单例模式的时候来使用
        :param args:
        :param kwargs:
        '''
        print('----new-----函数的执行')
        return object.__new__(cls) #在这里是真正创建对象实例的
        pass
    pass


# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')##self本身就一个对象,实例化时,自动把创建的对象和self对应上了,因此在传参的时候不需要为self传递参数
print(xw)  #直接输出对象 输出的是地址

小结  self特点

  1. self只有在类中定义 实例方法的时候才有意义,在调用时候不必传入相应的参数 而是由解释器 自动去指向
  2. self的名字是可以更改的  可以定义成其他的名字,只是约定俗成的定义成了 self
  3. self 指的是 类实例对象本身, 相当于java中 this

魔术方法

概述

在python中,有一些内置好的特定的方法,方法名是“__xxx__”,在进行特定的操作时会自动被调用,这些方法称之为魔法方法。
下面介绍几种常见的魔法方法。
__init__方法:初始化一个类,在创建实例对象为其赋值时使用。
__str__方法:在将对象转换成字符串  str(对象)  测试的时候,打印对象的信息。
__new__方法:创建并返回一个实例对象,调用了一次,就会得到一个对象。
__class__方法:获得已知对象的类 ( 对象.__class__)。
__del__方法:对象在程序运行结束后进行对象销毁的时候调用这个方法,来释放资源。
……

__str__方法

直接打印对象,输出结果只一串类似id地址的信息。

输出结果

 在类中定义给__str__方法

输出结果

print(xw)  #直接输出对象 输出的是地址
#__str__可以输出对象的一些信息

class Person:
    def __init__(self,pro,name,food):
        '''

        :param pro: 专业
        :param name: 姓名
        :param food: 食物
        '''
        self.pro=pro  #实例属性的定义
        self.name=name
        self.food=food
        print('----init-----函数执行')
        pass
    '''
   定义类
    '''
    def eat(self,name,food):
        '''
        实例方法
        :return:
        '''
        # print('self=%s',id(self))
        print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
        pass
#####str方法定义
    def __str__(self):
        '''
        打印对象 自定义对象 是内容格式的
        :return:
        '''
        return '%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro)
        pass
    pass


# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw)  #直接输出对象,这回就输出了信息,魔术方法默认在调用对象时就会执行

__new__方法

 创建对象实例的方法  每调用一次 就会生成一个新的对象 cls 就是class的缩写

  场景:可以控制创建对象的一些属性限定 经常用来做单例模式的时候来使用

class Person:
    def __init__(self,pro,name,food):
        '''

        :param pro: 专业
        :param name: 姓名
        :param food: 食物
        '''
        self.pro=pro  #实例属性的定义
        self.name=name
        self.food=food
        print('----init-----函数执行')
        pass
    '''
   定义类
    '''
    def eat(self,name,food):
        '''
        实例方法
        :return:
        '''
        # print('self=%s',id(self))
        print('%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro))
        pass
    def __str__(self):
        '''
        打印对象 自定义对象 是内容格式的
        :return:
        '''
        return '%s 喜欢吃 %s 修的专业是:%s'%(self.name,self.food,self.pro)
        pass
    def __new__(cls, *args, **kwargs):
        '''
        创建对象实例的方法  每调用一次 就会生成一个新的对象 cls 就是class的缩写

        场景:可以控制创建对象的一些属性限定 经常用来做单例模式的时候来使用
        :param args:
        :param kwargs:
        '''
        print('----new-----函数的执行')
        pass
    pass


# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw)  #直接输出对象

##加了new魔术方法打印结果
----new-----函数的执行
None
##加了new,str没有创建成功,有new时先执行new,新创建了个对象,那么就肯定没有内容
#改为:
 def __new__(cls, *args, **kwargs):
        '''
        创建对象实例的方法  每调用一次 就会生成一个新的对象 cls 就是class的缩写

        场景:可以控制创建对象的一些属性限定 经常用来做单例模式/对象的时候来使用
        :param args:
        :param kwargs:
        '''
        print('----new-----函数的执行')
        return object.__new__(cls) #在这里是真正创建对象实例的,return必须有,object是超类对象,至少有一个cls这个参数,代表要实例化的类,此参数由python解释器自动提供,不需传递
        pass
    pass
# xw是一个新的实例化对象
xw=Person('心理学','小王','榴莲')
# print('xw=%s',id(xw))
# xw.eat('小王','榴莲')
print(xw)  #直接输出对象

#打印结果
----new-----函数的执行
----init-----函数执行
小王 喜欢吃 榴莲 修的专业是:心理学

__new__和__init___函数的区别

  1.  __new__ 类的实例化方法 必须要返回该实例(return) 否则对象就创建不成功
  2.  __init___ 用来做数据属性的初始化工作  也可以认为是实例的构造方法  接受类的实例 self 并对其进行构造
  3. __new__   至少有一个参数是 cls 代表要实例化的类 ,此参数在实例化时由python解释器自动提供
  4. __new__  函数 执行要早于 __init___ 函数

案例---决战紫禁之巅(双人对战)

问题分析:

决战紫禁之巅有两个人物,西门吹雪以及叶孤城
        属性:
            name 玩家的名字
            blood 玩家血量

         方法:
            tong() 捅对方一刀,对方掉血10滴
            kanren() 砍对方一刀,对方掉血15滴
            chiyao() 吃一颗药,补血10滴
            __str__ 打印玩家状态

实现步骤:

1、定义类,创建__init__方法

2、创建玩家技能方法

 3、创建__str__方法,输出玩家状态

4、创建西门吹雪以及叶孤城两个人物

5、两个开始互砍

输出结果

 

 

 

;