DAY 8
Python中,方法没有重载
Python 中,方法的的参数没有声明类型(调用时确定参数的类型),参数的数量也可以由 可变参数控制。因此,Python 中是没有方法的重载的。定义一个方法即可有多种调用方式, 相当于实现了其他语言中的方法的重载。
如果我们在类体中定义了多个重名的方法,只有最后一个方法有效。
方法的动态性
Python 是动态语言,我们可以动态的为类添加新的方法,或者动态的修改类的已有的方法。
#测试方法的动态性
class Person:
def work(self):
print("努力上班!")
def playgame(a):
print("{0}在玩游戏".format(a))
def work2(a):
print("好好工作,努力上班!")
Person.Play = playgame #可以定义新的方法
p = Person()
p.work() #结果:努力上班!
p.Play() #等价于Person.Play(p)
#结果:<__main__.Person object at 0x0000024BEBC20FD0>在玩游戏
Person.work = work2 #还可以修改老的方法
p.work() #结果:好好工作,努力上班!
私有私有属性和私有方法(实现封装)
Python 对于类的成员没有严格的访问控制限制,这与其他面向对象语言有区别。关于私有 属性和私有方法,有如下要点:
- 通常我们约定,两个下划线开头的属性是私有的(private)。其他为公共的(public)。
- 类内部可以访问私有属性(方法)
- 类外部不能直接访问私有属性(方法)
- 类外部可以通过“_类名__私有属性(方法)名”访问私有属性(方法)
方法本质上也是属性
#测试私有属性、私有方法
class Employee:
__school = "NJUST" #私有类属性
def __init__(self,name,age):
self.name=name
self.__age=age #age为私有属性
def __work(self): #私有方法
print("好好工作!")
print("年龄:",self.__age) #类内部可以访问私有属性
print("学校:",Employee.__school)
e = Employee('Lee',20)
print(e.name)
print(e._Employee__age) #访问私有属性的方法,因为私密属性就是以此名字保存
e._Employee__work() #调用私有方法
print(Employee._Employee__school)
结果:
Lee
20
好好工作!
年龄: 20
学校: NJUST
NJUST
@property 装饰器
@property 可以将一个方法的调用方式变成“属性调用”。
@property 主要用于帮助我们处理属性的读操作、写操作。
#简单测试@property的用法
class Employee:
@property
def salary(self):
print("salary running")
return 10000
emp1 = Employee()
print(emp1.salary)
#结果:salary running
# 10000
class Employee:
def __init__(self,name,salary):
self.__name=name
self.__salary=salary
def get_salary(self):
return self.__salary
def set_salary(self,salary):
if 1000<salary<50000:
self.__salary = salary
else:
print("录入错误,薪水应在1000~50000")
emp1 = Employee("Lee",20000)
print(emp1.get_salary()) #结果:20000
emp1.set_salary(30000)
print(emp1.get_salary()) #结果:30000
@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作:
只定义getter方法,不定义setter方法就是一个只读属性
使用@property装饰器实现上功能:
class Employee:
def __init__(self,name,salary):
self.__name=name
self.__salary=salary
@property #相当于 salary 属性的 getter 方法
def salary(self):
return self.__salary
@salary.setter
def salary(self,salary):
if 1000<salary<50000: #相当于 salary 属性的 setter 方法
self.__salary = salary
else:
print("录入错误,薪水应在1000~50000")
emp1 = Employee("Lee",20000)
print(emp1.salary) #结果:20000
emp1.salary = 30000
print(emp1.salary) #结果:30000
属性和方法命名总结
· _xxx:保护成员,不能用“from module import * ”导入,只有类对象和子类对象能访 问这些成员。
· xxx:系统定义的特殊成员
· __xxx: 类中的私有成员,只有类对象自己能访问,子类对象也不能访问。(但,在类外 部可以通过“对象名. _类名__xxx”这种特殊方式访问。Python 不存在严格意义的私有成员)
注:再次强调,方法和属性都遵循上面的规则。
类编码风格
- 类名首字母大写,多个单词之间采用驼峰原则。
- 实例名、模块名采用小写,多个单词之间采用下划线隔开。
- 每个类,应紧跟“文档字符串”,说明这个类的作用。
- 可以用空行组织代码,但不能滥用。在类中,使用一个空行隔开方法;模块中,使用两 个空行隔开多个类。
第五章实操作业
1.定义一个函数实现反响输出一个整数。比如:输入 3245,输出 5432.
a = input("请输入一个整数:")
def t1(x):
z = reversed(list(a))
n = ''.join(list(z))
return n
print(t1(a))
- 编写一个函数,计算下面的数列:
a = int(input("输入一个数字:"))
def f1(x):
b = 0
for i in range(x):
b += (i+1)/(i+2)
print(b)
f1(a)
- 输入三角形三个顶点的坐标,若有效则计算三角形的面积;如坐标无效,则给出提 示。
import math
def isvalid(a=0.0, b=0.0, c=0.0):
"""判断三条边长是否符合三角形的定义:任意两边之和大于第三边或者任意两边之差小于第三边"""
side = [a, b, c]
side.sort() #升序排序
if side[0] + side[1] > side[2] or side[2] - side[1] < side[0]:
return True
else:
return False
def calculate_area():
"""获取三角形的三个顶点坐标并计算该三角形的面积"""
x1, y1 = map(int, input('请输入第一个顶点坐标(格式:横坐标 纵坐标):').split())
x2, y2 = map(int, input('请输入第二个顶点坐标(格式同上):').split())
x3, y3 = map(int, input('请输入第三个顶点坐标(格式同上):').split())
# 计算三条边长
side1 = math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
side2 = math.sqrt((x1 - x3) ** 2 + (y1 - y3) ** 2)
side3 = math.sqrt((x2 - x3) ** 2 + (y2 - y3) ** 2)
# 调用 isvalid() 函数,判断是否能够构成三角形
if isvalid(side1, side2, side3):
# 计算半周长
s = (side1 + side2 + side3) / 2
# 计算面积
area = (s * (s - side1) * (s - side2) * (s - side3)) ** 0.5
print('三角形的面积为:{:.2f}'.format(area))
else:
print('坐标无效,无法构成三角形')
if __name__ == '__main__':
calculate_area()
- 输入一个毫秒数,将该数字换算成小时数,分钟数、秒数。
def f1():
ms = int(input('请输入毫秒数:')) # 保留两位小数,但若ms太小,h就会显示为0。
s = round(ms / 1000, 2) #四舍五入,保留两位小数
m = round(s / 60, 2)
h = round(m / 60, 2)
print('{0}换算后等于{1}秒,等于{2}分钟,等于{3}小时'.format(ms, s, m, h))
f1()
5.使用海龟绘图。输入多个点,将这些点都两两相连。
import turtle as t
def connect_dot(*args):
"""将任意两点相连"""
# 从第1个点开始依次进行两两连线(不重复)
for i in range(len(args) - 1):
for j in range(i + 1, len(args)):
t.penup()
t.goto(*args[i])
t.pendown()
t.goto(*args[j])
t.done()
if __name__ == '__main__':
# 输入n个点
n = int(input("请输入n个点(n>1):"))
# 将每个点以元组形式组合成一个列表作为参数传入 connect_dot() 函数
list_ = [tuple(map(int, input(f'请输入第{i + 1}个点坐标:').split())) for i in range(n)]
connect_dot(*list_)#*param(一个星号),将多个参数收集到一个“元组”对象中