day 18面向对象2
1.对象属性的增删改查
class Student:
def __init__(self, name, tel, study_id='0001', score=0):
self.name = name
self.tel = tel
self.study_id = study_id
self.score = score
# 在打印一个对象的时候,系统会自动用这个对象去调用__repr__方法,并且获取这个方法的返回值。返回值是什么就打印什么(返回值必须是字符串)
def __repr__(self):
# 打印那个对象,self就是谁
# return f'姓名:{self.name} 电话:{self.tel}'
return f'<{str(self.__dict__)[1:-1]}>'
stu1 = Student('小明', '110', score=90)
stu2 = Student('隔壁老王', '120', '0022', 78)
print(stu1)
print(stu2)
1.1查 - 获取对象属性的值
对象.属性
getattr(对象, 属性名)
print(stu1.name)
print(getattr(stu1, 'name'))
# getattr可以做到动态获取属性的值
# value = input('请输入要获取的属性的属性名')
# print(getattr(stu1, value))
# print(stu1.height) # 报错
# print(getattr(stu1, 'height')) # 报错
print(getattr(stu1, 'height', 180)) # 180
1.2增/改
对象.属性 = 值
setattr(对象, 属性名, 值)
# 属性存在就是改
stu1.name = '小红'
setattr(stu1, 'tel', '109')
print(stu1)
# 属性不存在就是增加
stu1.height = 170
setattr(stu1, 'weight', 130)
print(stu1)
1.3删 - 删除对象属性
del 对象.属性
delattr(对象, 属性名)
del stu1.study_id
print(stu1)
delattr(stu1, 'score')
print(stu1)
2.类方法和静态方法
1)对象方法
怎么定义:直接定义
怎么调用:对象.方法名()
特点:self
什么时候用:如果实现函数的功能需要用到对象属性,那么这个函数就定义成对象方法
2)类方法
怎么定义:在定义函数前加装饰器@classmethod
怎么调用:类.方法名()
特点:有个默认参数cls,这个参数在调用的时候不用传参,系统会自动将当前类传给cls
什么时候用:实现函数功能在不需要对象属性的前提下取药类就使用类方法
3)静态方法
怎么定义:在定义函数前加装饰器@staticmethod
怎么调用:类.方法名()
特点:没有默认参数(相当于类中的普通函数)
什么时候用:实现函数的功能在不需要对象属性的前提下不需要类就使用静态方法
class Student:
num = 100
def __init__(self, name='zx'):
self.name = name
def func1(self):
print(self.name, Student.num)
print('对象方法')
@classmethod
def func2(cls):
stu1 = Student()
stu2 = cls()
# 当前类能做的cls都能做
print(stu1.num, stu2.num)
print('类方法')
@staticmethod
def func3():
print('静态方法')
print(Student)
Student.func2()
Student.func3()
3.内置类属性
class Person:
"""人类"""
num = 61
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'人类目前的数量是{cls.num}')
@staticmethod
def destroy():
print('人类破坏环境!')
p1 = Person()
1.类.doc - 获取类的说明文档
print(Person.__doc__) # 人类
2.类.module - 获取指定类所在模块
print(Person.__module__) # __main__
print(list.__module__) # builtins
3.对象.class - 获取指定对象类型,和type(对象)功能一样
print(p1.__class__) # <class '__main__.Person'>
print(Person) # <class '__main__.Person'>
print(type(p1)) # <class '__main__.Person'>
4.类.name - 获取类名
print(Person.__name__) # 'Person'
print(int.__name__) # 'int'
datas = ['abc', -0.212, '你好', 23, 32, 12.6, type]
for data in datas:
with open(f'files/{data.__class__.__name__}.txt', 'a', encoding='utf-8') as f:
f.write(str(data)+'\n')
类.dict - 将类转换成字典,key是字段名,值是字段对应的值
对象.dict - 将对象转换成字典,对象属性名作为key,属性值作为value
print(Person.__dict__) # 函数也是变量,所以{'__module__': '__main__', '__doc__': '人类', 'num': 61, '__init__': <function Person.__init__ at 0x000002856A319B80>, 'eat': <function Person.eat at 0x000002856A319C10>, 'message': <classmethod object at 0x000002856A1E89D0>, 'destroy': <staticmethod object at 0x000002856A1E8A00>, '__dict__': <attribute '__dict__' of 'Person' objects>, '__weakref__': <attribute '__weakref__' of 'Person' objects>}
print(p1.__dict__) # {'name': '张三', 'age': 18, 'gender': '男'}
类.base - 获取指定类的父类
类.bases - 获取指定类所有的父类
object是python中所有类的基类
print(Person.__base__) # <class 'object'>
print(Person.__bases__) # (<class 'object'>,)
4.getter和setter
1)getter:
a.什么时候用:在获取对象属性前,如果要别的什么事情,就可以给这个属性添加getter
b.怎么用:
第一步:在需要添加getter的属性的属性名前加_
第二步:在装饰器@property后面定义一个函数:
函数名就是属性名去掉_
函数没有参数,需要一个返回值(返回值就是获取这个属性真正得到的结果)
第三步:通过对象获取属性的时候,属性不需要带_
2)setter - 添加setter之前必须先添加getter
a.什么时候用:如果要在给某个对象属性赋值之前做别的什么事情,就给这个属性添加setter
b.怎么用:
第一步:在需要添加setter之前添加getter
第二部:在装饰器@getter名.setter后面定义一个函数:
函数名就是属性名去掉_
函数有一个函数(这个参数指向的是赋值的时候的值),没有返回值
第三步:通过对象获取属性的时候,属性不需要带_
class Person:
def __init__(self, age=18, birth=1000):
self.age = age # 相当于self.age(age)
self.bir = birth
@property
def age(self):
if 0 <= self._age <= 4:
return '儿童'
elif 5 <= self._age <= 12:
return '少年'
elif 13 <= self._age <= 28:
return '青年'
elif 29 <= self._age <= 40:
return '壮年'
elif 41 <= self._age <= 55:
return '中年'
elif 55 < self._age:
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(30)
print(p1.age)
print(Person(20).age)
p1.age = 6
p3 = Person(190)
print(p3.age)
5.私有化
访问权限
公开的:公开的属性和方法在类的内部、外部都可以用,并且可以被继承
保护的:保护的属性和方法在类的内部可以用,外部不能用,但是可以继承
私有的:私有的属性和方法在类的内部可以用,外部不能用,不能被继承
python中的属性和方法只有一种访问权限:公开的,所谓的私有化其实是假的
私有化的方法:在属性名和方法名前加__(注意:只能是两个__开头,不能再用__结尾)
class Person:
_Person__info = None
num = 100
__info = '动物'
@staticmethod
def __fun1():
print(Person.num)
return Person.__info
print(Person.num)
# print(Person.info) # 报错
print(Person._Person__info) # 动物
print(Person._Person__fun1())
6.运算符的重载
运算符
python在使用运算符的时候本质是在调用运算符对应的方法,每个运算符对应的方法的方法名是固定的;
不同类型的数据在参与相同的运算符的时候,会调用不同类中对应方法
某个类型的数据是否支持某种运算,就看这个数据对应的类型中有没有实现这个运算符对应的方法
练习:
class Person:
def __init__(self, name='小明', age=18, gender='男'):
self.name = name
self.age = age
self.gender = gender
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}>'
# def __lt__(self, other):
# return self.age < other.age
# 练习:将ps中的元素按照年龄的大小从小到大排序
p1 = Person()
p2 = Person('小花', 28, '女')
p3 = Person('张三', 20, '男')
p4 = Person('老王', 25, '男')
ps = [p1, p2, p3, p4]
print(ps)
ps = sorted(ps)
# ps.sort(key=lambda item: item.age)
# print(ps)