什么是对象
对象(Object)
既表示客观世界问题空间中的某个具体事情,又表示软件系统空间中的基本
元素
对象 = 属性 + 方法
对象以id作为标识,既包含数据(属性),也包含代码(方法),是某一类具体事物的特殊实例。
对象是类的实例,是程序的基本单元
要创建一个新的对象,首先必须定义一个类,用以指明该类型的对象所包含的内容(属性和方法)
同一类(class)的对象具有相同的属性和方法,但属性值和id不同。
对象名称
赋值语句给予对象以名称,对象可以有对个名称(变量引用),但只有一个id。
例:a = complex(1, 2)
对象实现了属性和方法的封装,是一种数据抽象机制
提高了软件的重用性,灵活性,扩展性
Python语言动态的特性,使得对象可以随时增加或删除属性或方法
例: print(f.fx, f.fy)
f.fz = 3.4
print(f.fz)
del f.fz
面向对象编程(OOP)是一种程序设计范型,,同时也是、一种程序开发方法
程序中包含各种独立而又能相互调用的对象,每个对象都能接受,处理数据并将数据传递给其他对象。
传统程序设计
将程序看作一系列函数或指令的集合
类的定义与调用
什么是类
- 类(class)是对象的模板,封装了对应现实实体的性质和行为
- 实例对象(Instance Object)是类的具体化
- 把类比作模具,对象则是用模具制造出来的零件
- 类的出现为面向对象编程的三个最重要的特性提供了实现的手段(
封装性
,继承性
,多态性
)
类和函数相似,类是一系列代码的封装
Python中约定,类名用大写字母开头,函数用小写字母开头,以便区分。
class语句:
class <类名>:
<一系列方法的调用>
类的初始化
class <类名>:
def __init__(self, <参数表>):
def <方法名>(self, <参数表>):
- _init_()是一个特殊的函数名,用于根据类的定义创建实例对象,第一个参数必须是self
<类名>(<参数>)
调用类会创建一个对象,(注意括号~
)
obj = <类名>(<参数表>)
返回一个对象实例
类方法中的self指这个对象实现~
使用点(.)操作符来调用对象里的方法
class Force: # 力
def __init__(self, x, y): # x, y方向分量
self.fx = x
self.fy = y
def show(self): # 打印出力的值
print("Force<%s, %s>"%(self.fx, self.fy))
def add(selfl, force2):
x = self.fx + force2.fx
y = self.fy + force2.fy
return Force(x, y)
# 生成一个力对象
f1 = Force(0, 1)
f1.show()
# 生成另一个力的对象
f2 = Force(3, 4)
# 合成为新的力
f3 = f1.add(f2)
f3.show()
类定义中的特殊的方法
特殊方法(special method)
也被称作魔术方法(magic method)
在类定义中实现一些特殊方法,可以方便的使用Python中一些内置操作
所有特殊方法的名称以两个(__)开始和结束
对象构造器 __init__(self, [...)实例化对象时调用
对象析构器 __del__(self, [...)
from os.path import join
class FileObject:
'''给文件对象进行包装从而确认在删除是文件流被关闭 '''
def __init__(self, filepath=’~‘, filename='sample.txt'):
# 读写模式打开一个文件
self.file = open(join(filepath, filename), 'r+')
def __del__(self):
self.file.close()
del self.file
算术操作符
__add__(self, other): 使用+操作符
__sub__(self, other): 使用-操作符
__mul__(self, other): 使用*操作符
__div__(self, other): 使用/操作符
反运算
当左操作数不支持相应的操作是被调用
__radd__(self, other)
__rsub__(self, other)
__rmul__(self, other)
__rdiv__(self, other)
大小比较
__eq__(self, other): 使用 == 操作符
__ne__(self, other): 使用 != 操作符
__lt__(self, other): 使用 < 操作符
__gt__(self, other): 使用 > 操作符
__le__(self, other): 使用 <= 操作符
__ge__(self, other): 使用 >= 操作符
例子:
class Force: # 力
def __init__(self, x, y): # x, y方向分量
self.fx = x
self.fy = y
def show(self): # 打印出力的值
print("Force<%s, %s>"%(self.fx, self.fy))
def add(selfl, force2):
x = self.fx + force2.fx
y = self.fy + force2.fy
return Force(x, y)
__add__ = add
def __str__(self):
return ”F<%s, %s>“%(self.fx, self.fy)
def __mul__(self):
x, y = self.fx * n, self.fy * n
return Force(x, y)
def __eq__(self, force2):
return (self.fx == force2.fx) and (self.fy == force2.fy)
# 操作符使用
f3 = f1 + f2
print("Fadd = %s"%(f3,))
f3 = f1 * 4.5
print("Fmul = %s"%(f3,))
print("%s == %s? ->%s"%(f1, f2, f1 == f2))
字符串操作
不仅数字类型可以使用+(__add__())和-(__sub__())的数学运算符,例如字符串类型可以使用+进行拼接,使用*进行复制
__str__(self): 自动转换为字符串
__repr__(self): 返回一个用来表示对象的字符串
__len__(self): 返回元素个数
自定义对象的排序
列表排序 sort()
对原列表进行排序,改变原列表内容。
如果列表中的元素都是数字,默认按升序排序
通过添加参数recerse=True可改变为降序排序
如果元素都是字符串,则会按照字母表顺序排序
>>> num = [4, 2, 7, 0,1]
>>> num.sort()
[0, 1, 2, 4, 7]
>>> num.sort(reverse = True)
>>> num
[7, 4, 2, 1, 0]
>>> name = ['John', 'Connor', 'Bruce', 'Arthur', 'Edward']
>>> name.sort()
>>> name
['Arthur', 'Bruce', 'Connor', 'Edward', 'John']
通用函数 sorted()
类似sort(),但返回的是排好序的列表副本,原列表内容不变
>>> name = ['John', 'Connor', 'Bruce', 'Arthur', 'Edward']
>>> sorted_name = sorted(name)
>>> sorted_name
['Arthur', 'Bruce', 'Connor', 'Edward', 'John']
>>> name
['John', 'Connor', 'Bruce', 'Arthur', 'Edward']
只有当列表中的所有元素都是同一种类型的时候,sort()和sorted()才会正常工作
特殊方法 __lt__(less than)
由于Python的可扩展性,每种数据类型可以定义特殊方法
def __lt__(self, y)
返回True视为比y小,排在前
返回False视为比y大,排在后
只要类定义了特殊方法__lt__
,任何自定义类都可以使用 x < y
这样比较。
class Student:
def __init__(self, name, grade):
self.name = name, self.grade = grade
# 内置sort()函数只引用 < 比较符来判断前后
def __lt__(self, other):
# 成绩比other高的,排在它前面
return self.grade > other.grade
# Student 的易读字符串表示
def __str__(self):
return "Student(%s, %s)"%(self.name, self.grade)
# Student的正式字符串表示,我们让它跟易读表示相同
__repr__ = __str__
# 构造一个列表,加入Student对象
s = list()
# 添加Student对象到list中
s.append(Student("Jack", 80))
s.append(Student("Jane", 75))
s.append(Student("Smith", 82))
s.append(Student("Cook", 90))
s.append(Student("Tom", 70))
print("Original: ", s)
# 对list进行排序,注意这里是内置sort()方法
s.sort()
# 查看结果,已经是按照成绩排好序了
print("Sorted: ", s)
>>> Original: [("Jack", 80), ("Jane", 75), ("Smith", 82), ("Cook", 90), ("Tom", 70)]
>>> Sorted: [("Cook", 90), ("Smith", 82), ("Jack", 80), ("Jane", 75), ("Tom", 70)]
>>> s[0] < s[1]
True
直接调用列表sort方法,可以根据 __lt__
定义排序。
直接检验 Student 对象的大小 s[i] < s[j]
另外可以定义其他比较符 __gt__
等(大于,小于,不等于···)
类的继承
继承(inheritance):如果一个类A继承自另一个类B,就把A称为子类,被继承的B称为父类(基类,超类)
代码复用:利用继承可以从已有类中衍生出新的类,添加或修改部分功能。
新类具有旧类中的各种属性和方法,而不需要进行任何复制。
类的继承机制
class Car:
def __init__(self, name):
self.name = name
self.remain_mille = 0
def fill_fuel(self, miles): # 加燃料里程
self.remain_mile = miles
def run(self, miles): # 跑miles英里
print(self.name, end=": ")
if self.remain_mile >= miles:
self.remain_mile -= miles
print("run %d miles!"%(miles,))
else:
print("fuel out!")
class GasCar(Car):
def fill_fuel(self, gas): # 加汽油gas升
self.remain_mile = gas *6.0 # 每升跑6英里
class ElecCar(Car):
def fill_fuel(self, power): # 充电power度
self.remain_mile = power * 3.0 # 每度电跑3英里
gcar = GasCar("BMW")
gcar.fill_fuel(50.0)
gcar.run(200.0)
>>> BMW: run 200 miles!
ecar = ElecCar("Tesla")
ecar.fill_fuel(60.0)
ecar.run(200.0)
>>> Tesla: fule out!
子类与父类
定义:如果两个类具有“一般 -- 特殊”的逻辑关系,那么特殊类就可以作为一般类的“子类”来定义,从“父类”继承属性的方法
class <子类名>(<父类名>):
def <重定义方法>(self, ...)
覆盖(Override)
子类对象可以调用父类方法,除非这个方法在子类中重新定义了。
如果子类同名方法覆盖了父类的方法,仍然还可以调用父类的方法。
子类还可以添加父类中没有的方法和属性
class GasCar(Car):
def __init__(self, name, capacity): # 名称和排量
super().__init__(name) # 父类初始化方法,只有名称
self.capacity = capacity
关于self
在类定义中,所有方法的首个参数一般都是self
self的作用:在类内部,实例化过程中传入的所有数据都赋给这个变量。
self实际上代表对象实例
<对象>.<方法>(<参数>) 等价于 <类>.<方法>(<对象>, <参数>)
gcar = GasCar("BMW")
gcar.fill_fuel(50.0)
gcar.fun(200.0) # 这里
GasCar.run(gcar, 200.0) # 和这里是等价的
异常处理
try-except语句
try:
<检测语句>
except <错误类型> [as e]:
<异常处理>
try-finally语句
try:
<检测语句>
except <错误类型> [as e]:
<异常处理>
finally:
<语句块>
else语句
try:
<检测语句>
except <错误类型> [as e]:
<异常处理>
else:
<语句块>
else: # 没有出错执行的代码
例子
try:
print("try...")
r = 10 / 'xyz'
print("result: ", r)
except TypeError as e:
print("TypeError:", e)
except ZeroDivisionError as e:
print("ZeroDivisionError:", e)
else:
print("no error!")
finally:
print("finally...")
print("END")
>>>try...
TypeError: unsupported operand type(s) for /: 'int' and 'str'
finally...
END
推导式
什么是推导式
推导式是从一个或者多个迭代器快速简洁地创建数据结构的一种方法。
将循环和条件判断结合,从而避免语法冗长的代码。
可以用来生列表,字典和集合。
列表推导式
[<表达式> for <变量> in <可迭代对象> if <逻辑条件>]
[x**x for x in range(10)]
[x+y for x in range(10) for y in range(10)]
[x*x for x in range(10) if x % 2 == 0]
[x.upper() for x in [1, ‘a’, 'b', True] if isinstance(x, str)]
>>> ['A', 'B']
字典推导式
{<表达式>:<元素表达式> for <变量> in <可迭代对象> if <逻辑条件>}
{"k%s"%(x,):x**3 for x in range(10)}
集合推导式
{<元素表达式> for <变量> in <可迭代对象> if <逻辑条件>}
{x**3 for x in range(10)}
生成器推导式
返回一个生成器对象,也是可迭代对象。
但生成器并不会立即产生全部元素,仅在要用到元素的时候才会生成,可以极大节省内存。
(<元素表达式> for <变量> in <可迭代对象> if <逻辑条件>)
>>> agen = (x**x for x in range(3))
>>> agen
<generator object <genexpr> at 0x1078f5620>
>>> for i in agen:
print(i)
0
1
2
生成器函数
什么是生成器
生成器(generator)是用来创建数据序列的一种对象。
使用它可以迭代庞大的序列,且不需要在内存中创建和储存整个序列、
通常生成器是为迭代器产生数据的。
如果要创建一个比较大的序列,生成器推导式将会比较复杂,一行表达式无法容纳,这是可以定义生成器函数。
生成器函数与普通函数
生成器函数的定义与普通函数相同,只是将return 换成 yield。
yield 与 return
- yeild 语句
立即返回一个值
下一下迭代生成器函数时,从yeild语句后的语句继续执行,直到再次yield返回,或终止。 - return 语句
终止函数的执行,下次调用会重新执行函数。
协同程序
可以运行的独立函数调用,函数可以暂停或挂起,并在需要的时候从离开的地方继续或重新开始。
def even_number(max):
n = 0
while n < max:
yield n
n += 2
for i in even_number(10):
print(i)
0
2
4
6
8
网友评论