Python中的所有的事物都是以对象形式存在,从简单的数值类型到复杂的代码模块都是对象
对象=属性+方法:对象以id作为标识,既包括数据(属性),也包括代码(方法),是某一类具体事物的特殊实例
# 在python concole中输入,为区分输入输出加了>>>
>>>id(1) # 整数1这个对象保存的地址
140711440851344
>>>type(1) # 类型
<class 'int'>
>>>dir(1) # 查看属性和方法
['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
函数也是对象
>>>id(abs)
1795808880264
>>>type(abs)
<class 'builtin_function_or_method'> # 内置的函数或者方法
>>>dir(abs)
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__text_signature__']
对象是类的实例,是程序的基本单元。
要创建一个新的对象,首先必须定义一个类,用以证明该类型的对象所包含的内容(属性和方法)。
同一类(class)的对象具有相同的属性和方法,但属性值和id不同。
对象的名称:赋值语句给予对象名称,对象可以有多个名称(变量引用),但只有一个id
例:a=complex(1,2)
b=a \quad # b也指向complex(1,2)这个对象
对象实现了属性和方法的封装,是一种数据抽象机制
引用形式:<对象名>.<属性名>
可以跟一般的变量一样用在赋值语句和表达式中
例:“abc”.upper() 变成全大写 "abc"为字符串对象w
(1+2j).real
(1+2j).imag
Python语言动态的特征,使得对象可以随时增加或者删除属性或者方法 del f3.fz
面向对象编程(OOP)是一种程序设计范型,同时也是一种程序开发方法。
程序中包含各种独立而又能 互相调用的对象。
每个对象都能接受、处理数据并将数据传递给其他对象。
类(class)是对象的模板,封装了对应现实实体的性质和行为。
实例对象是类的具体化。
把类比作模具,对象则是用模具制造出来的零件。
类的出现,为面向对象编程的三个最重要的特性提供了实现的手段:封装性、继承性、多态性。
和函数相似,类是一系列代码的封装。
Python中约定,类名用大写字母开头,函数用小写字母开头,以便区分。
class语句:
class <类名>:
<一系列方法的调用>
类的初始化
class <类名>:
def __init__(self, <参数表>):
def <方法名>(self, <参数表>):
__init__() 是一个特殊的函数名,用于根据类的定义创建实例对象,第一个参数必须是self
<类名>(<参数>)
调用类会创建一个对象,(注意括号)
obj = <类名>(<参数名>)
返回一个对象实例
类方法中的self指这个对象实例本身
使用点(.)操作符来调用对象里的方法
t = turtle.Pen() # 生成海龟
t.forward(100) # 这里的t指向对象实例的变量
t.self(90)
例:
class Force: # 力
def __init__(self, x, y): # x,y方向变量
self.fx, self.fy = x, y
def show(self):
print("Force<%s,%s>" % (self.fx, self.fy))
def add(self, 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()
结果为:
Force<0,1>
Force<3,5>
特殊方法:在类定义中实现的一些特殊方法,可以方便地使用Python的一些内置函数。
所有特殊方法的名称以两个下划线(__)开始和结束。
对象构造器: __init__(self,[…) 对象的构造器,实例化对象时调用
析构器:__del__(self,[…) 销毁对象时使用
算术操作符
__add__(self,other): 使用 + 操作符
__sub__(self,other): 使用 - 操作符
__mul__(self,other): 使用 * 操作符
__siv__(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): 使用 >= 操作符
在类的定义后边加上:
__add__ = add
def __str__(self):
return "F<%s,%s>" % (self.fx, self.fy)
def __mul__(self, n):
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)
结果为:
Fadd=F<3,5>
Fmul=F<0.0,4.5>
F<0,1>==F<3,4>? -> False
字符串操作:
不仅数字类型可以使用像 +(__add__())和 - (__sub__()) 的数学运算符,例如字符串类型可以使用+进行拼接,使用* 进行复制
__str__(self):自动返回字符串
__repr__(self):返回一个用来表示对象的字符串
__len__(self):返回元素个数
列表方法sort()
对原列表进行排序,改变原列表的内容
若元素为字符串,则按照字母表顺序排列
# 在python concole中输入,为区分输入输出加了>>>
>>>num = [4,2,7,0,1]
>>>num.sort() # 默认升序
>>>num
[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(),但返回的是排好序的列表副本,不改变原列表的内容
只有当列表中所有元素都是同一种类型时,sort()和sorted()才会正常工作
>>>name = ['John', 'Connor', 'Bruce', 'Arthur', 'Edward']
>>>sorted_name = sorted(name)
>>>sorted_name
['Arthur', 'Bruce', 'Connor', 'Edward', 'John']
>>>name
['John', 'Connor', 'Bruce', 'Arthur', 'Edward']
特殊方法__lt__ (<)
由于Python的可扩展性,每种数据类型可以定义特殊方法 def __lt__ (self,y) 返回 True 视为比y小,排在前;返回False 视为比y大,排在后
只要类定义中定义了特殊方法__lt__ ,任何自定义类都可以使用 x 例子:Student 姓名name,成绩grade 按照成绩由高到低排序 注意:对于定于的__lt__ 方法,为什么return self.grade > other.grade 使用大于号,在b站老师的直播答疑课上是这样说的:比较谁的体重轻,轻的排在前,用小于号(self 构造一个Python List对象 结果为: print(s[0] < s[1]) 的结果为True 直接调用列表sort方法:可以根据__lt__ 定义排序 重新定义__lt__ 方法,改为比较姓名 结果为: 继承:如果一个子类A继承自另一个子类B,就把继承者A称为子类,被继承的类B称为父类、基类或超类。 代码复用: 结果: 如果两个具有“一般-特殊”的逻辑关系,那么特殊类就可以作为一般类的“子类”来定义,从“父类”继承属性和方法 覆盖: 子类还可以添加父类中没有的方法和属性 在类定义中,所有方法的首个参数一般都是self self的作用:在类内部,实例化过程中传入的所有数据都赋给这个变量 self实际上代表对象实例 包含属性:name, city 结果: 在这有几个问题 结果如下,并没有改变 而将第二行再次赋值给a,就可得移动后的结果 而直接使用上边那个方法,则不用将值重新赋给a. 问题2:关于 是People的子类,新增属性school 在上面的基础上添加子类 结果为: 创建一个Mylist类,继承自内置数据类型list(列表) 结果: 结果为: 补充 设计一个学生类(Student),其中的数据成员有:字符串类型sname表示录入的学生姓名,整型值mscore代表学生的数学成绩,整型值cscore代表学生的语文成绩,整型值escore代表学生的英语成绩。 然后要求根据录入的学生成绩(各不相同),输出总分最高的学生姓名和各科目成绩。 输入: jack tom 输出: jack 95 90 85 给定一个列表和一个整数目标,其中列表中的元素都为整数,要求返回列表中的两个元素的索引编号(以列表形式打印,为确保结果唯一,小的编号在前),使这两个元素的和为这个特定的目标。 输入:共两行,第一行为列表中的元素值(各不相同),以空格隔开,第二行为一个整数。 0 2 3 输出:共一行,为一个列表。 给定两个非负整数x和y,如果某一整数等于 x i + y j x^i+y^j xi+yj,其中整数 i>= 0 且 j>=0,那么我们认为该整数是一个"精致"的数。返回值小于或等于n(n<=200)的所有精致的数组成的列表。 输入:共三行,每一行为一个整数,分别是x y n 1 输出:共一行,为一个列表。 [2, 3, 5] 给定一个列表alist,alist由一些正整数(代表长度)组成,返回由alist中的三个长度组成的有效三角形的最大周长。如果所有的长度组合都不能构成有效三角形,则返回 0。 输入:共一行,列表中的元素以空格隔开。 2 1 2 输出:共一行,为一个非负整数,是最大三角形的周长 5可扩展的“大小”比较及排序
class Student:
def __init__(self, name, grade):
self.name, self.grade = name, grade
# 内置sort函数只引用 < 比较符判断前后,那我们就定义一个__lt__特殊方法,这样就可以使用x
# 构造一个Python List对象
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方法,即调用了上面定义的__lt__特殊方法
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]成绩好,排在前
直接比较Student对象的大小:s[i] 还可以定义其他比较符:__gt__等
只需在上面的代码基础上改__lt__ 方法,就可使sort方法按照姓名来排序 def __lt__(self, other):
# 姓名字母顺序在前,排在前面
return self.name < other.name
Original: [(Jack,80), (Jane,75), (Smith,82), (Cook,90), (Tom,70)]
Sorted: [(Cook,90), (Jack,80), (Jane,75), (Smith,82), (Tom,70)]
类的继承
类的继承机制
利用继承可以从已有类中衍生出新的类,添加或修改部分功能
新类具有旧类中的各种属性和方法,而不需要进行任何复制class Car:
def __init__(self, name):
self.name = name
self.remain_mile = 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 EleCar(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)
ecar = EleCar('Tesla')
ecar.fill_fuel(60.0)
ecar.run(200.0)
BMW:run 200 miles!
Tesla:fuel out!
子类与父类
class <子类名>(<父类名>):
def <重定义方法>(self,...):
子类对象可以调用父类方法,除非这个方法在子类中重新定义了
如果子类同名方法覆盖了父类的方法,仍然还可以调用父类的方法# 加上排量
class GasCar(Car):
def __init__(self, name, capacity): # 名称和排量
super().__init__(name) # 父类初始化方法,只有名称
# 调用父类的init生成一个汽车对象
# 此时父类的__init__已被覆盖,使用super()返回父类
self.capacity = capacity # 增加了排量属性
关于self
<对象>.<方法>(<参数>)
等价于 ⇕ \quad \Updownarrow ⇕
<类>.<方法>(<对象>,<参数>)
这里的对象就是selfgcar = GasCar("BMW")
gcar.fill_fule(50.0)
gcar.run(200.0)
GasCar.run(gcar, 200.0) # 等价于上一行
上机练习
创建一个类People:
可以转换为字符串形式(__str__)
包含方法movato(self, newcity)
可以按照city排序
创建4个人对象,放到列表中进行排序class People:
def __init__(self, name, city):
self.name, self.city = name, city
def __str__(self):
return "(%s, %s)" % (self.name, self.city)
def moveto(self, new_city):
self.city = new_city
def __lt__(self, other):
return self.city < other.city
__repr__ = __str__ # 一定要加这一句,才能正常显示结果
s = list()
s.append(People("Jack", "qingdao"))
s.append(People("Amy", "jinan"))
s.append(People("Lillian", "shanghai"))
s.append(People("Nay", "beijing"))
print("Original:", s)
s.sort()
print("Sorted:", s)
Original: [(Jack, qingdao), (Amy, jinan), (Lillian, shanghai), (Nay, beijing)]
Sorted: [(Nay, beijing), (Amy, jinan), (Jack, qingdao), (Lillian, shanghai)]
问题1. 定义moveto()方法时,我写的是return People(self.name, new_city)
,
此时a = People("Jack", "qingdao")
a.moveto("guangzhou")
print(a)
Jack, qingdao
a = People("Jack", "qingdao")
a = a.moveto("guangzhou")
print(a)
# 结果为:
Jack, guangzhou
如果还是写a = a.moveto("guangzhou")
的话,会提示:moveto没有返回任何值。__repr__
与__str__
区别可参见python中 str__和__repr. 这说的是在交互式命令行下的区别。
而我在实践过程中(用的是pycharm),若单独输出一个对象时print(a)
,不加__repr__ = __str__
结果也正常显示。而创建多个对象,将其放在列表并排序,就必须要加__repr__ = __str__
. 还是不太理解原理。创建一个类Tercher
movate方法改为newschool
按照school排序
创建4个教师对象,放到列表中进行排序class Teacher(People):
def __init__(self, name, city, school):
super().__init__(name, city)
# self.name = name
# self.city = city
self.school = school
def __str__(self):
return "(%s, %s, %s)" % (self.name, self.city, self.school)
__repr__ = __str__
def moveto(self, new_school):
self.school = new_school
def __lt__(self, other):
return self.school < other.school
s = list()
s.append(Teacher("Jack", "qingdao", "zhenhua"))
s.append(Teacher("Amy", "jinan", "chaoyang"))
s.append(Teacher("Lillian", "shanghai", "shuangyu"))
s.append(Teacher("Nay", "beijing", "guokai"))
print("Original:", s)
s.sort()
print("Sorted:", s)
Original: [(Jack, qingdao, zhenhua), (Amy, jinan, chaoyang), (Lillian, shanghai, shuangyu), (Nay, beijing, guokai)]
Sorted: [(Amy, jinan, chaoyang), (Nay, beijing, guokai), (Lillian, shanghai, shuangyu), (Jack, qingdao, zhenhua)]
创建一个mylist类
增加一个方法“累乘”product
def product(self):
返回所有数据项的乘积class Mylist(list):
def product(self):
m = 1
for i in self:
m *= i
return m
a = Mylist([1, 2, 3, 4])
print(a)
print(sum(a))
b = a.product()
print(b)
c = Mylist(range(1, 10))
print(c)
d = c.product()
print(d)
[1, 2, 3, 4]
10
24
[1, 2, 3, 4, 5, 6, 7, 8, 9]
362880
课后习题
选择题
class Person:
def __init__(self, id):
self.id = id
tom = Person(123)
tom.__dict__['age'] = 20 # __dict__可以除了类内定义的属性外,额外定义一个属性
print(tom.__dict__)
print(tom.age+len(tom.__dict__)) # len()为2
{
'id': 123, 'age': 20}
22
字典类型:len(dict)
计算字典元素个数,即键的总数。
Python中定义私有变量的方法是: __变量名
.
假设a为类A的对象且包含一个私有数据成员“__value”,那么在类的外部通过对象a直接将其私有数据成员“__value”的值设置为3的语句可以写作 a._A__value=3
(不建议这样做)学生成绩排序
输入分为4个部分:
先输入学生姓名,以空格分隔;
然后输入学生的数学成绩(各不相同的正整数),也以空格分隔;
再输入学生的语文数学成绩(各不相同的正整数),也以空格分隔。
最后输入学生的英语数学成绩(各不相同的正整数),也以空格分隔。
学生姓名个数和成绩个数一定会相同。
95 84
90 75
85 90
共一行,为总分最高的学生姓名和各科目成绩,以空格分隔。class Student:
def __init__(self, n, m, c, e):
self.n, self.total = n, m+c+e
self.m, self.c, self.e = m, c, e
def __lt__(self, other):
return self.total < other.total # 判断条件为True时self排在前面,即较小的在前面
def __str__(self):
return '%s %d %d %d' % (self.n, self.m, self.c, self.e)
names = input().split()
mscore = list(map(int, input().split()))
cscore = list(map(int, input().split()))
escore = list(map(int, input().split()))
s = []
for i in range(len(names)):
s.append(Student(names[i], mscore[i], cscore[i], escore[i]))
# 此时s为 [jack 95 90 85, tom 84 75 90]
s.sort() # 调用上边的特殊方法__lt__ 进行排序
print(s[-1])
两数求和问题
(只对应确定的唯一一组解,并且不能使用同一个元素两次。)
5
[1, 2]def select(lst, s):
for i in lst:
for j in lst:
if i != j and i+j == s:
return sorted([lst.index(i), lst.index(j)])
lst = list(map(int, input().split()))
s = int(input())
print(select(lst, s))
"精致"的数
结果列表中每个值最多出现一次,同时请使用sorted保证结果唯一。
2
5def select(x, y, n):
r = set() # 集合可以去重
for i in range(n):
for j in range(n):
s = x**i + y**j
if s <= n:
r.add(s)
return sorted(r) # 输入值可以为任何容器,返回值为列表
x = int(input())
y = int(input())
n = int(input())
print(select(x, y, n))
最大的周长
a_list = list(map(int, input().split()))
a_list.sort() # 从小到大排序
while len(a_list) >= 3:
a = a_list.pop() # 取出最大值
if a < a_list[-1] + a_list[-2]: # 看跟次小的两个可否组成三角形
print(a + a_list[-1] + a_list[-2])
break
else: # 全都无法构成三角形
print(0)
.pop()
函数用于移除列表中的一个元素(默认最后一个元素),更新列表并且返回移除元素的值。