Python面向对象

学习地址

面向过程

如何做
  1. 把完成某一个需求的所有步骤从头到尾逐步实现
  2. 根据开发需求,将某些功能独立的代码封装成一个又一个函数
  3. 最后完成的代码,就是顺序地调用不同的函数
特点
  1. 注重步骤与过程,不注重职责分工
  2. 如果需求复杂,代码会变得很复杂
  3. 开发复杂项目,没有固定的套路,开发难度大

面向对象

相比较函数,面向对象是更大的封装,根据职责再一个对象中封装多个方法

如何做
  1. 在完成某一个需求前,首先确定职责–要做的事情(方法)
  2. 根据职责确定不同的对象,在对象内部封装不同的方法
  3. 最后完成的代码,就是顺序地让不同地对象调用不同的方法
特点
  1. 注重对象和职责,不同的对象承担不同的职责,
  2. 更加适合应对复杂的需求变化,是专门应对复杂项目开发,提供的规定套路
  3. 需要在面向过程的基础上,再学习一些面向对象的语法

类和对象


  1. 类是对一群具有相同特征或者行为的事物的一个统称,不能直接使用
    特征 被称为 属性
    行为 被称为 方法

  2. 对象
    对象是由类别创建出来的一个具体的存在,可以直接使用
    由哪一个类创建出来的对象,就拥有那一个类中定义的方法与属性

  3. 关系
    类只有一个,对象可以有很多个
    不同对象之间属性可能会各不相同

类的设计

使用面向对象开发前,应该首先分析需求,确定一下程序中需要包含哪些类!
对于每个类,紧扣属性与方法
类名: 比如动物,人类,大驼峰命名法(单词首字母大写,不用下划线)
属性: 这类事物的特征,比如人有年龄身高
方法:事物具有的行为,比如人会吃饭睡觉

类名确定

名词提炼法:分析整个业务流程,出现的名词,通常就是找到的类

属性和方法的确定

对象的特征描述,通常定义成属性
对象具有的行为(动词)通常可以定义成方法

面向对象基础语法

目标:

  1. dir内置函数
  2. 定义简单的类(只包含方法)
  3. 方法中的self参数
  4. 初始化方法
  5. 内置方法和属性
dir内置函数

在Python中对象几乎是无处不在的,如何验证对象呢:

  1. 标识符/数据 后面接一个.,然乎按下tab键,会显示该对象能调用的常用方法列表
  2. 使用内置函数dir,在dir()函数中传入标识符/数据,可以查看对象内的所有属性与方法

__方法名__格式的方法是Python中提供的内置方法/属性
常用几个:

  1. __new__ : 方法,创建对象时,会被自动调用
  2. __init__: 方法,对象被初始化时,会被自动调用
  3. __del__: 方法,对象被从内存中销毁前,会被自动调用
  4. __str__: 方法,返回对象描述信息,print函数输出使用
定义简单类

语法格式:

1
2
3
4
5
6
7
8
9
10
class ClassName:
def fun1(self,parameter_list):
pass
def fun2(self,parameter_list):
pass
class name:
def fun1(self,parameter_list):
pass
def fun2(self,parameter_list):
pass

方法定义无特殊之处,但参数列表第一个必须是self

创建对象

语法格式:object_name=ClassName()

简单面向对象程序
  1. 需求
    • 小猫鱼,小猫要
  2. 分析
    • 定义一个猫类Cat
    • 定义两个方法eatdrink
    • 按照需求– 不需要定义属性
  3. 实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
      class Cat:
       def eat(self): # 哪一个对象调用了方法,self就是那一个对象的引用
           print('eat fish!')
    def drink(self):
    print('drink water!')

    cat1=Cat() # 创建对象
    cat1.drink() # 调用方法

    - - - - - - - - - - -
    drink water!
关于引用的概念

在上述代码中,使用类创建对象后,cat1变量中仍然记录的是对象在内存中的地址,即cat1变量引用了新建的猫对象
使用print输出对象变量,默认情况下,是能够输出这个变量引用的对象是由哪一个类创建的对象,以及在内存中的十六进制地址

1
2
3
4
5
6
print(cat1)
addr=id(cat1)
print('%d , %x' %(addr,addr))
- - - - - - - - - - -
<__main__.Cat object at 0x7f0166bddcf8>
139643995413752 , 7f0166bddcf8

思考:如果再创建另一个对象,这两个对象是一样的吗?

  • 答案是否的,但如果用等号赋值,那么就是用一个引用了
方法中的self参数

案例改造:给对象增加属性
实现很容易,但并不建议使用,对象属性的封装应该在类的内部

1
2
3
4
5
cat1.name='Tom' # 直接给新增的属性赋值就可以了
print(dir(cat1))

- - - - - - - - - - -
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'drink', 'eat', 'name']

之前的代码中介绍过self表示调用方法的那个对象的引用,那么也可以在类中用self访问新增的属性,但是在类中没有定义这个属性就很不方便了。

初始化方法

当使用类名()创建对象时,对自动执行以下操作:

  1. 在内存空间中为对象分配空间 - - 创建对象
  2. 为对象的属性设置初始值 - - 初始化方法(init)

这个初始化方法就是__init__方法,这个方法时对象的内置方法,专门用来定义一个类中具有哪些属性的方法

1
2
3
4
5
6
7
8
 class Cat:
   def __init__(self): # 创建对象时自动调用
       print('this is init')

tom=Cat()

- - - - - - - -
this is init

在初始化方法内部定义属性

__init__方法内部使用self.属性名=属性的初始值就可以定义属性,在创建对象时新的对象都会拥有该属性
这样,我们就可以把外部新增属性的代码写进初始化方法__init__中即可

使用参数设置属性初始值

其实就是希望在新建对象时同时赋初始值,这些初始值需自己指定

1
2
3
4
5
6
7
8
9
class Cat:
def __init__(self,name):
self.name=name

cat1=Cat('Tom')
print(cat1.name)

- - - - - - - - - - - - -
Tom

内置方法和属性
  1. __del__方法
    __init__方法相反,但类似,也可以在函数体中做希望做的事,在所有代码执行结束之后会自动调用,也可以使用del 对象名手动销毁,__del__函数体中的方法自动执行,这即是我们希望对象在被销毁前做的事。

  2. 生命周期
    从使用类名创建,生命周期开始,到__del__方法调用,生命周期结束。注意这些内置方法不用手动定义也会自动执行,我们手动定义也只是希望在自动调用时希望做的事。

__str__方法

前面提到过使用print输出对象变量 时,默认情况下会输出这个变量引用的对象是由哪一个类创建的,以及16进制地址
在开发中,如果希望使用print输出对象变量时,能打印出自定义的内容,就可以利用__str__这个内置方法。注意:__str__方法必须返回一个字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Cat:
def __init__(self,name):
self.name=name
def __del__(self):
print('goodbye!')
def __str__(self):
return "I'm a cat %s" %self.name

cat1=Cat('Tom')
print(cat1)

- - - - - - - - - - - -
I'm a cat Tom
goodbye!