目录
1.复习:
2.今天的内容:反射
3.问题?
使用Python面向对象编写一个人类和学生类,其中人类是父类,有姓名,性别和年龄属性;学生类是子类,继承人类,特有的属性有学号和分数,特有的方法是学习和考试方法(在考试方法中使用随机数生成学生的分数)。
实例方法 | 形参:self,引用到对象本身。 |
类方法 @classmethod | 形参:cls,引用到类本身,访问到类属性,不能引用实例属性。 |
静态方法 @staticmethod | 系统不会自动加入类似于self或cls这样的形参:静态方法不能类属性和实例属性,”被隔离了”。 |
属性方法 @property | 把方法的函数调用格式编程了属性方法,应用场景:属性的getter|setter访问器。 |
封装起来:__属性名
代码如下:
class Student(Person):
def __init__(self,name,gender,no,age = 0,score = 0.0):
# 子类的构造方法需要像父类的构造方法传递参数,必须手工调用父类的构造方法
Person.__init__(self,name,gender,age)
# super(Student,self).__init__(name,gender,age)
self.No = no
self.Score = score
@property
def No(self):
return self.__no
@No.setter
def No(self,no):
if 1<=no<100:
self.__no = no
else:
print("学生的学号有效范围[1,100)")
@property
def Score(self):
return self.__score
@Score.setter
def Score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
print("学生的分数有效范围[0,100]")
def study(self):
print("%s正在学习..."%(self.Name))
def exam(self):
print("%s已经参加了考试"%(self.Name))
self.Score = random.randint(0,100)
print("其分数为%f"%(self.Score))
s = Student("ZhangSan","男",1,16)
s.study()
s.exam()
正向开发过程:
分析师进行系统分析设计,得到类图(类,属性,方法,类和类之间的关系)
开发工程师进行编码工作,实现类图中的类,创建对象,访问对象的属性,
调用对象的方法。
反射:开发工程师得到别的开发工程师传递过来的对象,对象所属的类
不太清楚对象有那些属性,那些方法?猜测的时候,得到的只是一些字符串,代码中需要访问的是对象的属性和方法,怎样将字符串映射成对象、对象的属性、对象的方法?
Python中的反射完成此工作。
可以对上述对象进行(增删改查):
hasattr | 查 |
setattr | 新增 |
getattr | 获取 |
delattr | 删除 |
代码如下:
"""
父类:人类Person
封装了类的属性,只有本类的方法可以直接访问属性,
提供访问属性的getter|setter访问器(属性方法)
属性的有效数据一般需要经过数据检验的
规定:只在属性的setter访问器进行属性的写操作
数据检验的代码只写在setter访问器中
"""
import random
class Person(object):
def __init__(self,name,gender,age = 0):
# 通过setter访问器给属性赋初始值
self.Name = name
self.Gender = gender
self.Age = age
@property
def Name(self):
return self.__name
@Name.setter
def Name(self,name):
if len(name) == 0:
print("人的姓名不能为空字符串")
else:
self.__name = name
@property
def Gender(self):
return self.__gender
@Gender.setter
def Gender(self,gender):
if gender == "男" or gender == "女":
self.__gender = gender
else:
print("人的性别只能是男或者女")
@property
def Age(self):
return self.__age
@Age.setter
def Age(self,age):
if 0<=age<200:
self.__age = age
else:
print("人的年龄的有效范围只能是[0,200)")
class Student(Person):
def __init__(self,name,gender,no,age = 0,score = 0.0):
# 子类的构造方法需要像父类的构造方法传递参数,必须手工调用父类的构造方法
Person.__init__(self,name,gender,age)
# super(Student,self).__init__(name,gender,age)
self.No = no
self.Score = score
@property
def No(self):
return self.__no
@No.setter
def No(self,no):
if 1<=no<100:
self.__no = no
else:
print("学生的学号有效范围[1,100)")
@property
def Score(self):
return self.__score
@Score.setter
def Score(self, score):
if 0 <= score <= 100:
self.__score = score
else:
print("学生的分数有效范围[0,100]")
def study(self):
print("%s正在学习..."%(self.Name))
def exam(self):
print("%s已经参加了考试"%(self.Name))
self.Score = random.randint(0,100)
print("其分数为%f"%(self.Score))
s = Student("ZhangSan","男",1,16)
# 你得到了s对象
# 假设你向打印s对象的属性值 ,
# 猜想:salary
#print(s.salary) # 抛出异常对象了,代码中如果没有处理异常,后续的代码就不会被执行了
# 使用反射来访问s对象的salary属性
# 好处:控制访问的场景
if hasattr(s,"salary"):
print(getattr(s,"salary"))
else:
print("s对象没有名称为salary的属性")
if hasattr(s,"exam"):
m = getattr(s,"exam")
m()
else:
print("s对象没有exam属性")
# 如果s对象没有play方法,就动态的添加play方法
if not hasattr(s,"play"):
setattr(s,"play",lambda self,hours:print(self.Name,"玩了",hours,"个小时"))
#动态调用方法
m = getattr(s,"play")
m(s,2)
#删除属性
print("Age = ",s.Age)
delattr(s,"__age")
print("Age = ",s.Age)
x = 10
print(x)