人生苦短,我爱python
- 一、基本概念介绍
- 1.1 什么是对象
- 1.2 什么是类
- 1.3 类里有啥
- 1.4 为什么要面向对象编程?
- 二、类的语法(终于进入了正题)
- 1. 类的声明:
- 2. 类的构造函数
- 3. 类的数据成员
- 4. 类的方法
- 5. 类的私有和公有属性
- 6. 创建对象
- 7. 访问属性
- 三、类的高级语法
- 1. 继承
- 1.1 公有属性
- 1.2 私有属性
- 1.3 保护属性
- 2. 重写
- 3. 增加新方法
- 4. 运算符重载
- 四、上文例子
接上篇薛钦亮的python教程(四)十分钟搞明白python的函数。
一、基本概念介绍
1.1 什么是对象
回答很简单:万物皆对象。凡是我们可以见到,可以想象到的东西都是对象,小到一个int,大到一个宇宙,都是一个对象。
1.2 什么是类
类是对象的抽象,同属一个类的对象有相同的行为和特性。
举个例子大家就更明白了:人类是一个类,具体的一个人是一个对象,所以之后别再说自己没对象了(图文无关)。
1.3 类里有啥
我们已经知道类是对象的抽象,那在程序设计中类里面有啥呢?答案是数据和方法(函数)。一个设计良好的类做的事情是,将数据封装起来,并且设计一些方法去使用更好地数据。(什么叫更好,请接着看)
1.4 为什么要面向对象编程?
这里简单谈两点(其实理由有很多):
- 模块化编程更加方便。如果我们完全按照C语言的风格,定义很多全局或者局部变量,再写很多与之相关的方法,对于编程者和其他读代码的人是一个挑战,因为你不知道哪些方法要使用哪些数据,以及如果有针对不同数据的两个相似的方法,在使用时也比较容易造成迷惑。
- 隔离复杂度。可能主函数中只会调用几个方法,有很多函数只是辅助函数,完全没必要全部展示出来。例如相机是一个类,提供给用户的方法可以是开机和照相两个按钮,但如何成像,如何用电,如何存储,不是用户所关心的。面向过程的编程会把这些接口全部开放,反而造成了迷惑。
举个例子,例如我们有个类是银行卡,一个必要的数据是余额,提供了两个方法是存钱和取钱。如果面向过程,在编写程序上需要定义一个float变量,再定义两个函数,参数均为余额和存取的金额,这样在设计上其实那个变量和两个方法都是没有关联的。
def take(balance,money):
'''取钱的函数
Args:
balance (float): 银行卡余额
money (float): 要取的金额
Returns:
float: 取钱后的银行卡余额
Raises:
ValueError: 余额不足
'''
if money > balance:
raise ValueError("余额不足")
return balance - money
def save(balance,money):
'''存钱的函数
Args:
balance (float): 银行卡余额
money (float): 要存的金额
Returns:
float: 存钱后的银行卡余额
'''
return balance + money
balance = 1000000
'''float: 银行卡余额'''
'''下面进行存钱取钱的演示'''
balance = take(balance, 1000)
balance = save(balance, 100000)
balance = take(balance, 100)
balance = take(balance, 1000)
上面那是只有一个账户的简单例子。如果假设有多个账户在各自存钱取钱呢?会不会出现眼花缭乱呢?如果我想获取近期的交易记录呢?如何去保存和输出?
如果我现在还要设计更复杂的情形呢:有一个新的类叫作人,一个人可以有多个银行卡账户,人可以对属于自己的银行卡账户进行存取呢?如果更复杂一点,银行卡有多种,中农工建四大行存取方法是相同的,但卡的类型要予以区分,我们该如何设计呢?如果还按照面向过程的思路,我们定义更多的变量表示不同账户余额,定义不同的函数负责存取不同银行的卡,然后定义一个人到底对应了哪几个银行卡的余额……
这个复杂的情况,我们等学习了类的语法再来详细分析(如果想看可以直接到文末)。
二、类的语法(终于进入了正题)
我们直接写一个例子来说明吧(未完待续,关注我持续更新)。
class Card:
'''银行卡
Attributes: 类的成员变量
__balance (float):账户余额
'''
__balance = 0 #类的私有变量
__recordlist = []
def __init__(self, money=0):
'''类的构造函数,创建对象的时候会自动调用。
如果用户不自定义构造函数,类会有一个默认的构造函数(简单理解为什么也不做)'''
self.__balance = money
def take(self, money):
'''取钱的函数'''
if money > self.__balance:
raise ValueError("余额不足")
self.__balance -= money
self.__record(-money)
def save(self, money):
'''存钱的函数'''
self.__balance += money
self.__record(money)
def get_balance(self):
'''查看余额的函数'''
return self.__balance
def print_record(self):
'''打印存取记录'''
for i in self.__recordlist:
print(i)
def __record(self,money):
'''添加存取记录'''
import datetime
if money > 0:
self.__recordlist.append(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+" 存%.2f元"%(money))
else:
self.__recordlist.append(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")+" 取%.2f元"%(-money))
card = Card()
card.save(10000)
card.take(1000)
card.save(20000)
card.save(2000)
card.take(15000)
print(card.get_balance())
card.print_record()
1. 类的声明:
class ClassName:
类的内容
class后面接类名,后面加冒号(:),下面缩进加内容。
2. 类的构造函数
构造函数__init__
,在对象的创建时自动调用,如果不定义,则为默认构造函数。
在这个函数中,需要做一些对象创建必须做的事情,第一个参数必须为self,但调用的时候无需指定这一参数(这一点对所有的类的普通成员函数都适用)。
3. 类的数据成员
类中所含的变量,例如上面类中的:__balance
,__recordlist
。
4. 类的方法
类中所含的函数,例如上面类中的:take(self, money)
,__record(self,money)
等。
5. 类的私有和公有属性
类的数据成员和方法的名称前如果加了“__
”(双下划线),说明这个是私有的,只允许该类内部访问,如果前面不加下划线,则是公开的变量或方法。
对于出于安全考虑不能公开的属性(例如:__balance,余额公开会导致外部可以随意修改,不合逻辑)、出于简介不必要公开的属性(例如:__record(self, money)只是在存钱取钱的时候自动调用以记录,无需公开)的变量,应设置为私有类型。
6. 创建对象
用对象名 = 类名(构造函数要求的参数)来创建。对于上面的类,有以下两个例子来做说明。
c1 = Card() #默认参数为0
c2 = Card(10000) #初始化参数为10000
7. 访问属性
在类中调用类的方法或者变量,可以用self.xxxx
的方式,在类外通过对象调用,可以用object.xxxx
的方式,具体见上面的代码。
三、类的高级语法
1. 继承
类与类之间的继承关系,在真实世界中表现为范畴关系。例如:水果是一个类,西瓜