1. 面向对象编程

OOP ( Object  Oriented Programming) 即面向对象编程。

面向对象编程是一种编码思想,或是一种代码组织方式。如同编辑文章时,可以选择分段、分节的方式让文章看起来有层次、更方便阅读或修改。

编码时可以选择使用 OOP 方案,也可以选择不使用。如同行文一样,使用或不使用都不会对核心逻辑产生影响。

面向对象编程有自己的核心编码理论,对于任何一种计算机语言而言,如果选择支持此理论,则称此计算机语言支持面向对象编程。如 C++、Java、Python……

因每一种计算机语言语法上的差异性,在提供 OOP 实现时的语法规范会有很大的区别。除此之外,对于每一种语言而言,也可以在 OOP 基础理论上进行语法扩展或限制。如 Python 支持多继承。而 Java 语言只支持单根继承……

1.1 OOP 特点

要了解 OOP 的特点,可从 2 个角度进行阐述。

广义角度:让程序像人类解决问题一样去解决问题,让程序具有人的思维模式。

人类解决问题时,先是要了解问题域中会涉及到哪些对象,然后再深入了解每一个对象的特性或功能,最后再做出相应的决策。

比如:为班级选一名班长。

选班长就是现实世界的一个问题域,如何才能选择一名符合要求的班长?

  1. 首先确定此问题中涉及的对象(此处便是班上的所有学生)。
  2. 然后了解每一个学生的兴趣、爱好、性格……以及个人能力等等。
  3. 从了解的群体中匹配一个符合班长标准的学生便可。

面向对象编程中的对象一词,便是借鉴了现实世界中对象概念。

狭义角度:OOP 编码为整个程序维护带来的优势

OOP 组织的代码可让程序整体上有高度的可阅读性,除此之外,最主要的特点是可提高代码的复用性、安全性、可扩展性。

任何事情都会 2 面性,OOP 会增加代码的理解难度。

1.2 OOP 基本概念

OOP 中有两个很重要的概念,类和对象

对象从何而来?

现实世界中我们很少思考这个问题,在选班长时,不会思考学生是从哪里来的,即使思考这个问题,也会认为那是哲学家的事情。

我们不思考现实世界中的手机、电脑、电视机是怎么来的……因为我们不关心这个,我们关心的是使用它们所提供的功能。

如果我们思考一下手机是怎么出现的,则会发现:

  1. 首先需要工程师设计手机蓝图。
  2. 在工厂里根据手机蓝图进行生产(可能生产很多)。
  3. 用户购买手机,了解手机特性和功能,使用手机。

我们身边的诸如 电视机、洗衣机、电脑……无不例外的需要经过这几个过程后方能来到我们的世界。

即使是人也是女娲按自己的样子创建出来的……

同理,电脑世界里不会突然冒出手机、电脑、学生……如何才能让电脑出现此类对象。一样,先设计一个蓝图,此蓝图在电脑世界我们就称其为“类”

有了“类”之后才可以创建手机对象,有了对象后才能在程序代码中使用设计时为手机赋予功能完成程序逻辑。

现实世界设计手机蓝图时,需要设计手机的外观,如大小、形状、体重……需要赋予手机功能、如打电话、播放音乐、播放视频、上网……

在计算机的编码世界里,同样在设计类时需要为 “手机类” 设计外观和功能。OPP 中称外观为属性,称功能为方法。

类是蓝图,具有抽象性特征

对象是根据蓝图创建出来的个体,具有具体性、实用性特征

2. Python  实现 OOP

如需使用 OOP 理念实现程序逻辑,则需遵循如下流程:

2.1 分析问题

首先需要明确问题:如编写一个程序摸拟小狗的行为。

此问题中的对象便是小狗,所以程序中需要一只小狗。

按上所述,创建小狗之前需要设计“狗类”,因此需要为类的设计提供足够的信息。

分析可得在设计类时需要有小狗属性:姓名、年龄,小狗的行为:尊下、打滚。

2.2 类设计语法

class Dog():

    def __init__(self, name, age):
"""初始化属性name和age"""
self.name = name
self.age = age def sit(self):
"""小狗蹲下行为"""
print(self.name.title() + " 乖乖的尊下了!") def roll_over(self):
"""小狗打滚"""
print(self.name.title() + " 开始打滚哈!")

 如上为 python 中类设计的结构语法:

  • 类的函数称为方法,方法的第一个参数须是 self 关键字。
  • __init__ 方法是必须的,其方法名不得修改。此方法会在创建对象时被自动调用,用来初始化对象数据。
  • self.name 声明一个对象变量,此变量会保存对象的数据。

2.3 创建对象语法

有了类后,方可创建对象,有了对象后方可激活属性和方法。

my_dog = Dog('小雪', 6)
print("小狗的名字:"+my_dog.name.title()+".")
print("小狗今年"+str(my_dog.age)+" 岁了")
my_dog.sit()
my_dog.roll_over()

创建小狗时,需调用和类名相同的方法,如上述的 Dog( ) 方法,此方法也叫构造方法,此方法实质是调用了类设计中的 __init__ 方法。所以需要传递小狗的具体姓名和年龄初始 name 和 age 变量。

调用类中的方法时,不需要为方法声明时的 self  参数传递值。

有了对象后,如需要使用此对象的数据时,可使用 .  运算符。如上  my_dog.name 得到小狗的姓名。

当然,在创建小狗后,也可以根据需要修改小狗的姓名和年龄。

my_dog.name='小花'
my_dog.age=4

同样,也可以使用 . 运算符调用类设计时的方法。调用方法也不需要为第一个参数 self 传值。

运行结果:

小狗的名字:小雪.
小狗今年6 岁了
小雪 乖乖的尊下了!
小雪 开始打滚哈!

有了类之后,可以根据此类的设计方案,创建出多个对象。每一个对象有自己的数据空间,彼此之间的数据是独立且隔离的。

my_dog = Dog('小黑', 6)
your_dog = Dog('小白', 3)
print("我的小狗的名字: "+my_dog.name.title()+".")
print("我的小狗的年龄 "+str(my_dog.age)+"岁了.")
my_dog.sit()
print("\n你的小狗的名字: "+your_dog.name.title()+".")
print("你的小狗的年龄 "+str(your_dog.age)+" 岁了.")
your_dog.sit()

 如同现实世界一样。现在有了 2 只小狗,它们是独立的个体。修改其中一只狗的名字,对另一只小狗是没影响的。

我的小狗的名字: 小黑.
我的小狗的年龄 6岁了.
小黑 乖乖的尊下了! 你的小狗的名字: 小白.
你的小狗的年龄 3 岁了.
小白 乖乖的尊下了!

3. OOP 的封装性

封装性可以从 2 个角度上展开讨论:

3.1 广义角度:无处不封装

类就是一个封装体:它把数据以及对数据的相关操作方法封装在了一起。

方法也是一个封装体:封装了代码逻辑

封装的优点!

当我们通过对象使用数据和方法时,不需要了解其中的内部细节,如此实现了设计和使用的分离,和现实世界中我们使用手机一样,不需了解手机的内部结构和细节。

开发者在使用 python 提供的模块时,不需要了解模块中的相关实现细节,直接使用其功能便可。

设计和使用的分离能加速工业软件的开发效率。

3.2 狭义角度:保证内部数据的完整性

创建一只小狗后,可以编写如下代码修改小狗的年龄。

my_dog = Dog('小雪', 6)
my_dog.age=-4

显然这是不符合实际情况的,没有一只小狗的年龄可以是负 4 岁。但是,现在程序可以正常运行。

小狗今年-4 岁了

出现这样不合常理的想象,应该追究谁的责任。类的设计者还是对象使用者?

我们应该要追究类设计者的责任,就如同我刚买的手机不能充电一样,是设计者的设计缺陷引起的。

我们应该在设计类的时候提供一种内部安全检查机制,保护变量能被赋予一个正确的、可靠的值。

实施流程:

1. 在变量、方法的前面加上双下划线(__)让变量成为私有概念

python 的语法有很大的弹性。添加下划性只是一种象征性或类似于道德层面的约定。并不能真正意义上让外部不能访问。

class Dog():

    def __init__(self, name, age):
"""初始化属性name和age"""
self.name = name
#私有化
self.__age = age def sit(self):
"""小狗蹲下行为"""
print(self.name.title() + " 乖乖的尊下了!") def roll_over(self):
"""小狗打滚"""
print(self.name.title() + " 开始打滚哈!")

2.  在类中提供对应的 set 和 get 方法实现对内部变量的保护。

    def get_age(self):
return self.__age

# 对数据进行检查
def set_age(self, age):
if age<0:
print("小狗的年龄不可能为负数")
return
self.__age = age

3. 测试

my_dog = Dog('小雪', 6)
my_dog.set_age(-4) print("小狗的名字:"+my_dog.name.title()+".")
print("小狗今年"+str(my_dog.get_age())+" 岁了")

输出结果

小狗的年龄不可能为负数
小狗的名字:小雪.
小狗今年6 岁了

python 还有一种更优雅的解决方案。使用注解方式。

class Dog():

    def __init__(self, name, age):
self.name = name
# 私有属性,属性名(age)前面双下划线的名称
self.__age = age # 实例方法
def run(self):
print("{} 在跑……".format(self.name)) # 使用 @property 定义age属性的 get 方法
@property
def age(self):
return self.__age # 使用 @age.setter 定义 age 属性的 set 方法必须放在@property的后面
@age.setter
def age(self, age):
if age < 0:
print("小狗的年龄不能是负数")
return
self.__age = age #实例化小狗
dog = Dog("小红", 3)
print("{0} 狗狗的年龄是 {1}".format(dog.name, dog.age))
#修改年龄
dog.age = -4
print("{0} 狗狗的年龄是 {1}".format(dog.name, dog.age))

输出结果

小红 狗狗的年龄是 3
小狗的年龄不能是负数
小红 狗狗的年龄是 3

 

4 . 总结

面向对象编程可以用《人类简史》中的一句话总结,人类文明的进步不一一定能泽福到每一个个体。

类可以设计的很完美,但每一个对象做为个体可以有自己的命运。

封装是面向对象编程理念中最基本也是最重要的特性,没有封装便没有后续的更多。

封装可能让我们把相关联的数据与方法构建成一个逻辑上的整体,也可保护内部数据的安全性,毕竟没有数据安全性的程序是没有意义的。

Python 面向对象编程之封装的艺术的更多相关文章

  1. python基础-面向对象编程之封装、访问限制机制和property

    面向对象编程之封装 封装 定义:将属性和方法一股脑的封装到对象中,使对象可通过"对象."的方式获取或存储数据. 作用:让对象有了"."的机制,存取数据更加方便 ...

  2. Python 面向对象编程之进阶使用

    我们在https://www.cnblogs.com/yinsedeyinse/p/9976280.html中学习了面向对象的编程方法.现在学习他的进阶用法. 1. 静态方法 2. 类方法 3. 属性 ...

  3. python面向对象编程之组合

    前面讲了面向类与对象的继承,知道了继承是一种什么"是"什么的关系. 然而类与类之间还有另一种关系,这就是组合 先来看两个例子: 先定义两个类,一个老师类,老师类有名字,年龄,出生的 ...

  4. java学习笔记(基础篇)—面向对象编程之封装、继承、多态

    一. OOP中的基本概念 Java的编程语言是面向对象的,采用这种语言进行编程称为面向对象编程(Object-Oriented Programming, OOP), 它允许设计者将面向对象设计实现为一 ...

  5. JS面向对象编程之封装

    来源:https://segmentfault.com/a/1190000015843072 我们所熟知的面向对象语言如 C++.Java 都有类的的概念,类是实例的类型模板,比如Student表示学 ...

  6. python基础-面向对象编程之继承

    面向对象编程之继承 继承的定义:是一种新建类的方式,新建的类称之为子类或派生类,被继承的父类称之为基类或超类 继承的作用:子类会""遗传"父类的属性,从而解决代码重用问题 ...

  7. python基础-面向对象编程之反射

    面向对象编程之反射 反射 定义:通过字符串对对象的属性和方法进行操作. 反射有4个方法,都是python内置的,分别是: hasattr(obj,name:str) 通过"字符串" ...

  8. python基础-面向对象编程之多态

    面向对象编程之多态以及继承.抽象类和鸭子类型三种表现形式 多态 定义:同一种类型的事物,不同的形态 作用: 多态也称之为"多态性".用于在不知道对象具体类型的情况下,统一对象调用方 ...

  9. python基础-面向对象编程之组合

    面向对象编程之组合 定义:一个对象中拥有另一个或其他多个对象的属性和方法. 作用:减少代码的冗余,降低耦合度 关于耦合度的说明 耦合:通俗地讲,就是相互作用,相互影响的意思 耦合度越高,程序的可扩展性 ...

随机推荐

  1. 曼孚科技:“四管齐下”筑牢AI数据隐私安全防线

    谈及数据,绕不开的一个话题就是数据隐私与数据安全.随着数字化进程加快,数据安全事件频发,据Risk Based Security统计,去年国际数据泄露事件近5000起,被泄露数据近41亿条,数据造成的 ...

  2. 【刷题-LeetCode】122 Best Time to Buy and Sell Stock II

    Best Time to Buy and Sell Stock II Say you have an array for which the ith element is the price of a ...

  3. [一]Cesium利其器——Visual Studio Code

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ IDE Web前端刚入门的朋友,常常想选择一个快速.好用.流行( ...

  4. netty系列之:请netty再爱UDT一次

    目录 简介 netty对UDT的支持 搭建一个支持UDT的netty服务 异常来袭 TypeUDT和KindUDT 构建ChannelFactory SelectorProviderUDT 使用UDT ...

  5. Servlet Listener(监听器)

    监听器 Listener 是一个实现特定接口的 Java 程序,这个程序专门用于监听另一个 Java 对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即自动执行.监听器的相关概 ...

  6. golang中结构体和结构体指针的内存管理

    p1是结构体,p2是结构体指针. 2. 声明并赋值结构体和结构体指针 package main import "fmt" type Person struct { name str ...

  7. 『无为则无心』Python函数 — 39、Python中异常的传播

    目录 1.异常的传播 2.如何处理异常 1.异常的传播 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播.如果函数中没有对异常进行处理,则异常会继续向函数调用者传播.如果函数调 ...

  8. Clang-Format 个人常用配置

    Clang-Format 个人常用配置 本文记录 Clang-Format 个人常用配置. 欲了解更多配置选项,可查阅 官方文档. BasedOnStyle: Google AccessModifie ...

  9. ES_AutoCheck.sh

    #!/bin/bash #@es_check #@date 2019/11/26 #@auth tigergao status=`curl -s GET "http://172.16.71. ...

  10. numpy常用函数记录

    np.square() 函数返回一个新数组,该数组的元素值为源数组元素的平方. 源阵列保持不变. 示例: import numpy as np a = np.array([[1, 2, 3], [4, ...