首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Python指南:面向对象程序设计

Python指南:面向对象程序设计

作者头像
王强
发布于 2018-08-09 09:31:21
发布于 2018-08-09 09:31:21
59830
代码可运行
举报
文章被收录于专栏:Python爬虫实战Python爬虫实战
运行总次数:0
代码可运行

Python 是一种多泛型语言,它没有强制程序员使用某种特定的程序设计风格,而是允许程序员采用过程型、函数型或面向对象的程序设计风格,也可以是这些编程风格的有效组合。对于大多数程序而言,尤其对中等规模或大规模的程序,采用面向对象的程序设计风格提供了很多优势。

1、面向对象方法

接下来将基于使用程序对圆进行描述这一问题,来解释纯过程型程序设计方法存在的问题。用于描述一个圆所需要的最少数据包括圆心坐标(x, y)以及圆的半径,简单的方法是使用一个三元组对圆进行描述,比如:circle = (25, 80, 12)

如果只给出这个表示,那么我们可以理解为x = 25, y = 80, radius = 12, 也可以理解为x = 25, radius = 80, y = 12,二义性是其一个不足之处。另外一个不足在于,只能通过索引位置对其中的值进行存取,还是得提前知道元组中每个位置所代表的含义。

可以使用 namedtuple 解决获取元素顺序的问题(假设distance_from_origin函数已定义):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import collections

Circle = collections.namedtuple('Circle', 'x, y, radius')
circle = Circle(13, 84, 9)
# 假定 distance_from_origin 函数已经定义
distance = distance_from_origin(circle.x, circle.y)

虽然可以解决元素顺序的问题,但是如果半径给定的值为负值,这个数据是不合理的,假设会在 distance_from_origin 函数中进行检查,但这只有在调用的时候才能检查,并不能在创建 Circle 对象的时候进行验证,这就是纯过程型程序设计的弊端。

对象:我们之前见过的 dict、int、str 等数据类型其实是一个类,我们也可以称之为一个 对象。

对象中通常包含属性——方法是可调用的属性,其他属性则是数据。方法其实也是一个函数,只不过其第一个参数是调用该方法的实例本身(self)。在属性名前以两个下划线引导,Python就会阻止无心的访问,因此可以认为是私有的。

面向对象的优势之一是如果我们有一个类,就可以对其进行专用化,这意味着创建一个新类,新类继承原始类的所有属性(数据和方法),通常可以添加或替换原始类中的某些方法,或添加更多的实例变量。

2、自定义类

创建自定义类的两种语法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class className:
    suit

class className(base_classes):
    suit

2.1 属性与方法

我们从简单的类 Point 开始,该类存放坐标 (x, y),定义于文件 Shape.py 中,其完整实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import math

class Point:
    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y


    def distance_from_origin(self):
        return math.hypot(self.x, self.y)


    def __eq__(self, other):
        return self.x == other.x and self.y == other.y


    def __repr__(self):
        return "Point({0.x!r}, {0.y!r})".format(self)


    def __str__(self):
        return "({0.x!r}, {0.y!r})".format(self)

Point 类有两个数据属性(self.x和self.y),还包含5个方法(不包括继承来的方法),其中4个属于特殊方法。导入 Shape 模块后, Point 类就可以像其他类一样进行使用,其属性可以直接存取。

01.Point继承关系

对 Point 类的基本使用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Shape

a = Shape.Point()
repr(a) # returns: 'Point(0, 0)'

b = Shape.Point(3, 4)
str(b)    # returns: '(3, 4)' 
b.distance_from_origin()    # returns: 5.0

对方法进行调用时,Python 会自动提供第一个参数——这个参数是对对象自身的对象引用(在 C++ 与 Java 中称为 this)。我们必须在参数列表中包含这一参数,根据约定,这一参数称为self。所有的对象属性都必须由self进行限定。

创建一个对象,需要两个步骤:调用特殊方法 __new__() 来创建该对象,之后调用特殊方法 __init__() 对其进行初始化。

2.2 继承与多态

接下来我们新建一个继承自 Point 类的 Circle 类,添加一个额外的属性(radius)以及3个新方法,此外重新实现Point类的几个方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Circle(Point):
    def __init__(self, radius, x=0, y=0):
        super().__init__(x, y)
        self.radius = radius


    def edge_distance_from_origin(self):
        return abs(self.distance_from_origin() - self.radius)


    def area(self):
        return math.pi * (self.radius ** 2)


    def circumference(self):
        return 2 * math.pi * self.radius


    def __eq__(self, other):
        return self.radius == other.radius and self.x == other.x and self.y == other.y


    def __repr__(self):
        return "Circle({0.radius!r}, {0.x!r}, {0.y!r})".format(self)


    def __str__(self):
        return repr(self)

Circle 类的继承关系如下:

02.Circle继承关系

在 __init__() 方法中,使用 super() 来调用基类的 __init__() 方法,从而创建并初始化 self.x 属性与 self.y 属性。下面给出两个使用实例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
p = Shape.Point(28, 45)
c = Shape.Circle(5, 28, 45)
p.distance_from_origin()    # returns: 53.0
p.distance_from_origin()    # returns: 53.0

多态意味着,给定类的任意对象在使用时都可以看做该类的任意某个基类的对象,这也是为什么在创建子类时只需要实现我们需要的附加方法,必须重新实现的也只是那些需要替代的方法。

2.3 使用特性进行属性存取控制

property() 修饰器函数是一个内置函数,至多接受4个参数:一个获取者函数,一个设置者函数,一个删除者函数以及一个 docstring

为将属性转换为可读/可写的特性,我们必须创建一个私有属性,其中实际上存放了数据并提供获取者方法与设置者方法。接下来我们对 Circle 类的 radius 属性进行验证。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Circle(Point):
    def __init__(self, radius, x=0, y=0):
        super().__init__(x, y)
        self.radius = radius

    @property
    def radius(self):
        """ The circle's radius

        >>>circle = Circle(-2)
        Traceback(most recent call last):
        ...
        AssertionError:radius must be nonzero and non-negative
        >>>circle = Circle(4)
        >>>circle.radius = -1
        Traceback(most recent call last):
        ...
        AssertionError:radius must be nonzero and non-negative
        >>>circle.radius = 6
        """
        return self.__radius

    @radius.setter
    def radius(self, radius):
        assert radius > 0, "radius must be nonzero and non-negative"
        self.__radius = radius

    ...

测试:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import Shape
circle = Shape.Circle(-4)

执行之后会报错:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
AssertionError: radius must be nonzero and non-negative

这样就会在创建 Circle 对象时进行验证了。

本文介绍了 Python 对面向对象程序设计的基础知识。展示了纯过程型程序设计的一些不足,并使用面向对象来克服这些不足。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-05-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 C与Python实战 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
3 条评论
热度
最新
所以中间件就是对本来要做的事,进行了封装?
所以中间件就是对本来要做的事,进行了封装?
221举报
也可以这么理解
也可以这么理解
回复回复点赞举报
貌似是的
貌似是的
回复回复点赞举报
推荐阅读
JavaScript——ES6新增语法特性
ES的全称是ECMAScript,它是由ECMA国际标准化组织制定的一项脚本语言的标准化规范
岳泽以
2022/10/26
4840
JavaScript——ES6新增语法特性
前端成神之路-es6-ES6概念&新增语法&内置对象拓展
ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。
海仔
2021/01/29
4880
ES6相关概念及新增语法
ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。
星辰_大海
2020/10/27
4300
ES6相关概念及新增语法
「JS高级」ES6
请注意,本文编写于 2056 天前,最后修改于 169 天前,其中某些信息可能已经过时。
曼亚灿
2023/05/17
1.9K0
「JS高级」ES6
ES6归纳总结
let 的特点 let声明的变量只在所处的块级有效(块级作用域不受外部影响具有暂时死区特性),也就是说在{ }内声明的变量,只在 { }中可以使用,在其他地方不能使用。 防止循环变量,变成全局变量。 for(var i=0;i<3;i++){ } console.log(i);// 输出 3 for(let i=0;i<3;i++){ } console.log(i);/// 未定义 不存在变量提升 具有暂时死区 var num = 10; if (true){ console.log(num); //
用户4344670
2020/02/24
6850
前端架构师之01_ES6_基础
简单来说,ECMAScript是JavaScript语言的国际标准,JavaScript是实现ECMAScript标准的脚本语言。
张哥编程
2024/12/13
2180
箭头函数
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this
清出于兰
2020/10/26
1.4K0
中高级前端高频面试题分享
代码比较简单,我们只是在setTimeout的方法里面又调用了一次setTimeout,就可以达到间歇调用的目的。
前端迷
2019/05/28
9000
ES6相关概念与ES6新增语法
ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。
梨涡浅笑
2020/10/28
4720
ES6相关概念与ES6新增语法
二、ES6新语法
图中可对比看出,如果用var声明,在循环外部还是可以使用i变量;但用let声明变量,循环外部不可以使用n变量
Dreamy.TZK
2020/07/03
4250
前端基础-JavaScript函数进阶
这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式(Function Expression)
cwl_java
2020/03/26
5880
java8的stream流
在1.8新特性中有一个stream流 可以对集合进行很多操作,在开发里大量用到 先创建两个类,用于我们操作 import java.util.ArrayList; /** * @ClassName: StringList * @Date: 2020/6/21 0021 21:08 * @Description: 一个继承了ArrayList<String>的类 * @Author: <achao1441470436@gmail.com> */ public class StringList ex
阿超
2022/08/16
4210
mybatis常用条件查询总结(迭代一)
目录 1.mybatis中大于等于小于等于的写法 2.mybatis动态查询条件组装 3.mybatis批量条件 4.mybatis时间查询实现分页总结 1.mybatis中大于等于小于等于的写法 第一种写法(1): 原符号 < <= > >= & ' " 替换符号 < <= > >= & ' " 例如:sql如下: create_date_time >= #{s
挑战者
2018/06/29
2.8K0
JavaScript的箭头函数与普通函数区别?
箭头函数用更简洁的方式,来完成普通函数的功能,但是不具备普通函数拥有的属性: this 、 arguments 、 super 、 new.target,有两种表达形式:
Learn-anything.cn
2021/11/27
7310
es6新语法+vue2的学习笔记分享
shigen
2023/09/15
3230
es6新语法+vue2的学习笔记分享
VUE基础讲解
回调地狱:上一个接口还没有走完,下一个接口已经开始了,但是下一个接口需要上一个接口的数据
叶秋学长
2022/07/17
3810
VUE基础讲解
JS进阶系列02-JS面向对象的三大特征之封装
JS 作为面向对象的一门语言,拥有和其他面向对象语言一样的三大特征,即封装(encapsulation)、继承(inheritance )和多态(polymorphism )。关于继承的概念和实现,在本系列不在赘述,有兴趣的同学可以看看JS入门难点解析12-原型链与继承。
love丁酥酥
2018/08/27
8380
JS箭头函数之:为何用?怎么用?何时用?
在现代JS中最让人期待的特性就是关于箭头函数,用=>来标识。箭头函数有两个主要的优点:
Clearlove
2019/08/29
4.5K0
js遍历数组的几种方法
2、map:支持return,相当与原数组克隆了一份,把克隆的每项改变了,也不影响原数组
jamesjiang
2022/11/20
1.5K0
js遍历数组的几种方法
彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-完善用户管理EP04
    书接上回,上一回我们完成了用户管理页面的构建,并且通过前端的Vue.js框架动态地获取表单数据,同时异步请求后端Iris接口进行入库操作,过程中使用函数封装可复用的逻辑。 本回我们将继续完善用户管理功能。
用户9127725
2022/09/23
6310
彩虹女神跃长空,Go语言进阶之Go语言高性能Web框架Iris项目实战-完善用户管理EP04
相关推荐
JavaScript——ES6新增语法特性
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验