面向对象2
1.对象属性的增删改查
class Student:
def __init__(self, name, age, study_id, scores):
self.name = name
self.age = age
self.study_id = study_id
self.scores = scores
# 在打印一个对象的时候,系统会自动用这个对象去调用__repr__方法,并且获取这个方法的返回值。返回值是什么就打印什么(返回值必须是字符串)
def __repr__(self):
return str(self.__dict__)
stu1 = Student('小明', 18, '001', 86)
stu2 = Student('小王', 18, '002', 84)
print(stu1, stu2){'name': '小明', 'age': 18, 'study_id': '001', 'scores': 86} {'name': '小王', 'age': 18, 'study_id': '002', 'scores': 84}
1.查 - 获取对象属性的值
对象.属性
getattr(对象, 属性名, 默认值) - 可以做到动态获取属性的值,并且可以赋默认值,如果属性名不存在,不会报错且返回默认值
print(stu1.name)
print(getattr(stu1, 'name'))
value = input('请输入要获取的属性的属性名:')
print(getattr(stu1, value))
2.增/改
对象.属性 = 值
属性存在就是改,属性不存在就是增加
setattr(对象, 属性名, 值)
stu1.name = '小轩'
print(stu1) # {'name': '小轩', 'age': 18, 'study_id': '001', 'scores': 86}
stu1.weight = 130
print(stu1) # {'name': '小轩', 'age': 18, 'study_id': '001', 'scores': 86, 'weight': 130}
setattr(stu1, 'weight', 125)
print(stu1) # {'name': '小轩', 'age': 18, 'study_id': '001', 'scores': 86, 'weight': 125}
3.删 - 删除对象属性
del 对象.属性
delattr(对象, 属性名)
del stu1.study_id
print(stu1) # {'name': '小轩', 'age': 18, 'scores': 86, 'weight': 125}
delattr(stu1, 'weight')
print(stu1) # {'name': '小轩', 'age': 18, 'scores': 86}
2.类方法和静态方法
-
对象方法
怎么定义:直接定义在类中的函数
怎么调用:通过 ‘对象.方法名’ 的形式来调用
特点:自带参数self,用对象调用方法的时候参数self不需要传参,系统会自动将当前对象传给self
(self:谁调用就指向谁)
什么时候用:如果实现函数功能需要用到对象属性,那么这个函数就定义成对象方法 -
类方法
怎么定义:在定义前加装饰器@classmethod
怎么调用:类.方法名
特点:有个默认参数cls,这个参数在调用的时候不用传参,系统会自动将当前类传给cls
什么时候用:实现函数的功能在不需要对象属性的前提下需要类就使用类方法 -
静态方法
怎么定义:在定义前加装饰器@staticmethod
怎么调用:类.方法名()
特点:没有默认参数(相当于类中的普通函数)
什么时候用:实现函数的功能在不需要对象属性的前提下不需要类就使用静态方法
class Student:
num = 100
def __init__(self, name='张三'):
self.name = name
def func1(self):
# 对象方法
print(self.name)
@classmethod
def func2(cls):
# cls:Student
print(f'cls:{cls}')
print('类方法', Student.num)
@staticmethod
def func3():
print('静态方法')
print('Student:', Student)
Student.func2() # 类方法 100
Student.func3() # 静态方法
s1 = Student()
s1.func1() # 张三
3.内置类属性
class Person:
"""
我爱学习,学习使我快乐!
"""
num = 50
def __init__(self, name='张三', age=18, gender='男'):
self.name = name
self.age = age
self.gender = gender
def eat(self, food='面条'):
print(f'{self.name}在吃{food}')
@classmethod
def message(cls):
print(f'python班级中的人数是:{cls.num}')
@staticmethod
def goal():
print('学技术,拿高薪')
p1 = Person()
# 1. 类.__doc__ - 获取类大的说明文档
print(Person.__doc__) # 我爱学习,学习使我快乐!
# 2. 类.__module__ - 获取指定类所在的模块
print(list.__module__) # builtins
print(Person.__module__) # __main__
# 3. 对象.__class__ - 获取指定对象对应的类型,和type(对象)功能一样
print(p1.__class__) # <class '__main__.Person'>
print(type(p1)) # <class '__main__.Person'>
# 4. 类.__name__ - 获取类名
print(Person.__name__) # Person
# datas = ['abc', -0.123, '你好', 34, 80, 12.7]
# for data in datas:
# with open(f'files/{data.__class__.__name__}.txt', 'a', encoding='utf-8') as f:
# f.write(str(data)+'\n')
# 5. 类.__dict__ - 将类转换成字典,key是字段名,值是字段对应的值
# 对象.__dict__ - 将对象转换成字典,对象属性名作为key,属性值作为value
print(Person.__dict__)
print(p1.__dict__) # {'name': '张三', 'age': 18, 'gender': '男'}
# 6. 类.__base__ - 获取指定类的父类
# 类.__base__ - 获取指定类的父类
# object是python中所有的基类
print(Person.__base__) # <class 'object'>
print(Person.__bases__) # (<class 'object'>,)
4.getter和setter
1.getter和setter
-
getter
什么时候用:在获取对象属性前,如果要对别的属性做什么事情,就可以给这个属性添加getter
怎么用:
第一步:在需要添加getter的属性的属性名前加_
第二步:在装饰器@property后面定义一个函数:a.函数名就是属性名去掉下划线;b.函数没有参数,需要一个返回值(获取这个属性真正得到的结果)
第三步:通过对象去获取属性的时候,属性不需要带下划线 -
setter - 添加setter之前必须先添加getter
什么时候用:如果要在给某个对象属性赋值之前做别的什么事情,就给这个属性添加setter
怎么用:
第一步:在需要添加setter的属性的属性名前加_
第二步:在装饰器@getter名.setter后面定义一个函数
函数名就是属性名去掉_,函数有一个参数(这个参数指向的是赋值的时候赋的值),没有返回值
第三步:通过对象给属性赋值的时候,属性不需要带下划线
# 练习:给Person添加属性age 要求:age中保存年龄值,获取age属性的时候得到的是这个年龄值对应的阶段状态:
# 儿童(0~4)、少年(5~12)、青年(13~28)、壮年(29~40)、中年(41~55)、老年(55岁以上)
class Person:
def __init__(self, age=20):
self._age = age
@property
def age(self):
if 0 <= self._age <= 4:
return '儿童'
if 5 <= self._age <= 12:
return '少年'
if 13 <= self._age <= 28:
return '青年'
if 29 <= self._age <= 40:
return '壮年'
if 41 <= self._age <= 55:
return '中年'
if 55 < self._age < 100:
return '老年'
else:
return '滚呀!'
@age.setter
def age(self, value):
if type(value) != int:
raise ValueError
if value < 0 or value > 150:
raise ValueError
self._age = value
p1 = Person(34) # 如果使用这个给对象赋值,不会进入setter函数
print(p1.age) # 壮年
p1.age = 170 # ValueError
5.私有化
1.访问权限
-
三种访问权限
公开的:公开的属性和方法在类的内部和外部都可以用,并且可以被继承
保护的:保护的属性和方法在类的内部可以用,外部不能用,但是可以被继承
私有的:私有的属性和方法在类的内部可以用,外部不能用,而且不能被继承
python中的属性和方法只有一种访问权限:公开的,所谓的私有化其实是假的 -
私有化的方法
在属性名和方法前加__(只能是两个下划线开头,不能用两个下划线结尾)
class Person:
num1 = 50
__info = '动物'
@staticmethod
def func1():
print(Person.__info)
Person.func1()
# print(Person.__info) # 报错
print(Person._Person__info)
6.运算符的重载
1.运算符
python在使用运算符的时候本质是在调用这个运算符对应的方法,
每个运算符都对应的方法的的方法名是固定的
不同类型的数据在参与相同的运算符的时候,会调用不同类中对应的方法
某个类型的数据是否支持某种运算,就看这个数据对应的类型中有没有实现这个运算符对应的方法
class Person:
def __init__(self, name='小明', age=18, gender='男'):
self.name = name
self.age = age
self.gender = gender
def __lt__(self, other):
return self.age < other.age
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}>'
# 练习:将ps中的元素按照年龄的大小从小到大排序
p1 = Person()
p2 = Person('小花', 28, '女')
p3 = Person('张三', 20, '男')
p4 = Person('老王', 25, '男')
ps = [p1, p2, p3, p4]
ps.sort()
print(ps)