面向对象进阶
对象属性的增删改查
class Student:
def __init__(self, name, gender='男', age=18, tel=''):
self.name = name
self.gender = gender
self.age = age
self.tel = tel
def __repr__(self):
return str(self.__dict__)
stu1 = Student('小明', '男', 18, '110')
1.查 - 获取属性的值
对象.属性 - 获取执行属性对应的值,如果属性不存在报错
getattr(对象, 属性名) - 获取执行属性对应的值,如果属性不存在报错
getattr(对象, 属性名, 默认值) - 获取执行属性对应的值,如果属性不存在不报错,直接返回指定的默认值
print(stu1.name)
print(getattr(stu1, 'name'))
方法二可以动态确定需要获取的内容
# value = input('学生的哪个信息: name? age? tel? gender?:')
# # print(stu1.value)
# print(getattr(stu1, value))
# print(stu1.score) # AttributeError: 'Student' object has no attribute 'score'
print(getattr(stu1, 'score', 0))
2.增、改
对象.属性 = 值 - 如果属性存在就是修改,属性不存在就是添加
setattr(对象, 属性名, 值) - 如果属性存在就是修改,属性不存在就是添加
stu1.name = '小花'
print(stu1)
stu1.score = 100
print(stu1, stu1.score)
setattr(stu1, 'height', 170)
print(stu1)
setattr(stu1, 'age', 30)
print(stu1)
- 删
del 对象.属性
delattr(对象, 属性名)
del stu1.gender
print(stu1)
# print(stu1.gender) # AttributeError: 'Student' object has no attribute 'gender'
delattr(stu1, 'tel')
print(stu1)
内置属性
class A:
x = 10
def __init__(self, m=10, n='hello', p=True):
self.m = m
self.n = n
self.p = p
self.name = '小花'
def f1(self):
print(f'对象方法: {self.m}')
@classmethod
def f2(cls):
print(f'类方法:{cls.x}')
@staticmethod
def f3():
print('静态方法')
a = A()
1.内置属性 - 创建类的时候系统自动添加的属性就是内置属性
1)_dict_
类._dict_ - 将类转换成字典,将所有的类属性名作为键,类属性对应的值作为值
对象._dict_ - 将对象转换成字典,对象属性名是键,对象属性对应的值是值
print(A.__dict__)
print(a.__dict__) # {'m': 10, 'n': 'hello', 'p': True}
2._class_
对象._class_ - 获取对象对应的类,功能和type一样
print(a.__class__, type(a))
3._name_
类._name_ - 获取类名
print(A.__name__) # 'A'
4._doc_
类._doc_ - 获取类的说明文档
print(int.__doc__)
5._module_
类._module_ - 获取定义指定类的模块名
print(A.__module__, int.__module__)
类._base_ - 获取当前类的父类
类._bases_ - 获取当前类所有的父类
print(A.__base__) # <class 'object'>
print(A.__bases__) # (<class 'object'>,)
私有化
1.访问权限(面向对语言通用)
公开的:属性和方法在类的内部、类的外部都可以使用,也可以被继承 (python中所有的属性和方法都是公开的)
保护的:属性和方法在类的内部可以使用,也可以被继承
私有的:属性和方法只能在类的内部使用
2.python私有化是假的: 在名字前加__
class A:
num = 18
__x = 20
def __init__(self):
self.__name = '小明'
def f1(self):
print(A.num)
@classmethod
def f2(cls):
print('内部:', A.__x)
A.__f3()
@staticmethod
def __f3():
pass
# print(A.num)
A.f2()
# print('外部:', A.__x)
# print(A.__dict__)
print('外部:', A._A__x)
a = A()
# print(a.__name)
# A.__f3()
类的继承
1.什么继承
继承就是让子类直接拥有父类所有的属性和方法。
子类 - 继承者
父类 - 被继承者,又叫超类
2.继承的语法
class 类名(父类1, 父类2, 父类3,…):
类的内容
注意:如果在定义类的时候没有添加继承关系,那么这个类默认继承Python的基类object
class Person:
num = 61
def __init__(self):
self.name = '小明'
self.age = 18
self.gender = '男'
def eat(self, food):
print(f'{self.name}在吃{food}')
class Student(Person):
pass
print(Student.num)
stu = Student()
print(stu.name, stu.age, stu.gender)
stu.eat('面条')
- 在子类中添加属性和方法
1)添加类属性和方法
在子类中直接定义新的类属性和新的方法
2)添加对象属性
类中的方法的调用过程:先看当前类中是否有对应的方法,如果有就直接调用自己类中的这个方法;如果没有就去看父类中有没有,如果有直接调用,没有看父类的父类…以此类推,如到找object都没有找到相应的方法,才会报错。
继承的时候,子类之所以可以继承父类的对象属性,是因为继承了父类的_init__方法。如果子类中有_init,那么父类的__init__就不会被继承,那么对象属性就不会被继承。
总结:在子类添加__init__的同时用super()去调用父类的__init__方法
class Teacher(Person):
profession = '老师'
def __init__(self):
# super().__init__() # 调用当前类的父类的__init__()
super(Teacher, self).__init__()
self.school = '千锋教育'
def teach(self):
print('教学')
@staticmethod
def message():
print('教书育人')
print(Teacher.num, Teacher.profession)
t1 = Teacher()
# t1.eat('火锅')
t1.teach()
Teacher.message()
print(t1.school)
print(t1.name, t1.age, t1.gender)
4.super的使用
super(类, 对象).方法 - 调用指定类的父类的方法 (注意:后面的对象必须是前面的类或子类的对象)
super().方法 - 调用当前类的父类的方法
class A:
def funcA(self):
print('A')
def func1(self):
print('A1')
class B(A):
def funcB(self):
print('B')
def func1(self):
print('B1')
class C(B):
def funcC(self):
print('C')
def func1(self):
print('C1')
# super().func1()
# super(C, self).func1()
# super(B, self).func1()
super(Student, Student()).eat('苹果')
print('==============================================')
c = C()
c.func1()
class Animal:
def __init__(self, age, gender='雄'):
self.gender = gender
self.age = age
class Dog(Animal):
def __init__(self, name, color, gender='雄'):
super().__init__(0, gender)
self.name = name
self.color = color
a = Animal(2)
d = Dog('大黄', '黄色')
1.魔法方法
类中自带的以__开头并且以__结尾的方法就是魔法方法,所有的魔法方法都不需要程序去调用,会在特定情况下自动调用。
这些魔法方法中有一部分方法是在对象使用运算符的时候会被自动调用。
每一个运算符都有一个固定的魔法方法,某种数据是否支持某种,就看这个数据对应的类中有没有实现对应的魔法方法。
10 + 20 # 10.__add__(20)
'abc' + '234' # 'abc'.__add__('234')
10.2 > 20py
# {'a': 10} + {'b': 20} # TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
# class A:
# def func1(self):
# print('A')
#
#
# class B:
# def func1(self):
# print('B')
#
# x = B()
# x.func1()
- 重载运算符 - 在自己的类中通过现实运算的魔法方法来让自己的类的对象支持指定的运算符
自己定义的类默认支持比较是否相等
from copy import copy
class Student:
def __init__(self, name='小明', age=18, score=60):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}>'
# self + other, 返回值就是加法运算的结果
def __add__(self, other):
# self = stu1, other=stu2
# return self.age + other.age
return [self, other]
def __mul__(self, other: int):
result = []
for _ in range(other):
result.append(copy(self))
return result
# self > other
def __gt__(self, other):
return self.score > other.score
stu1 = Student()
stu2 = Student('小花', 22, 45)
print(stu1 != stu2)
print(stu1 + stu2) # stu1.__add__(stu2)
s = stu1 * 3
print(s)
stu1.name = '张三'
print(s)
students = [
Student('stu1', 23, 98),
Student('stu2', 18, 87),
Student('stu3', 25, 99),
Student('stu4', 22, 80)
]
print(students)
print('======')
print(max(students))
students.sort()
print(students)
def max1(seq):
m = seq[0]
for x in seq[1:]:
if x > m:
m = x
return m
"""
seq = students
m = Student('stu1', 23, 98)
x = Student('stu2', 18, 87): if Student('stu2', 18, 87) > Student('stu1', 23, 98):
"""
拷贝
from copy import copy, deepcopy
1.浅拷贝和深拷贝
不管是浅拷贝还是深拷贝都是将被拷贝的数据复制产生一个新的数据,然后将新的数据的地址返回。
如果被拷贝的对象中有子对象(可变数据),浅拷贝不会对子对象进行拷贝(人变成不一样的人,但是狗还是同一条狗),
深拷贝会对子对象进行拷贝(人变成不一样的人,狗也会变成不一样的狗)
class Dog:
def __init__(self, name, color):
self.name = name
self.color = color
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>'
class Person:
def __init__(self, name, age, dog=None):
self.name = name
self.age = age
self.dog = dog
def __repr__(self):
return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>'
p1 = Person('小明', 18, Dog('大黄', '黄色'))
print('p1:', p1)
# 直接赋值 - 两个变量保存同一个数据的地址
p2 = p1
print('p2:', p2)
# 浅拷贝
p3 = copy(p1)
print('p3:', p3)
# 深拷贝
p4 = deepcopy(p1)
print('p4:', p4)
print('======================修改年龄后==================')
p1.age = 20
p1.dog.name = '旺财'
print('p1:', p1)
print('p2:', p2)
print('p3:', p3)
print('p4:', p4)
内存管理
- 内存的申请
当使用变量保存数据的时候系统会自动在堆中申请空间保存数据,同时让变量保存数据在内存中地址(python中的变量全是指针变量)。
如果需要保存的数据是不可变的数据,系统会先检查当前内存中是否已经存在这个数据,如果有直接返回已经保存的数据的地址,
如果没有才会重新申请新的内存保存数据。
a = 100
b = 100
print(id(a), id(b)) # 4428060448 4428060448
x = 'abc'
y = 'abc'
print(id(x), id(y)) # 4445987760 4445987760
m = (10, 20)
n = (10, 20)
print(id(m), id(n)) # 4468933696 4468933696
l1 = [10, 20]
l2 = [10, 20]
print(id(l1), id(l2)) # 4511662208 4511664384
2.内存释放
原则:如果数据有引用数据就不会被销毁(不会释放),如果数据没有引用(引用计数为0)就会被自动销毁(释放)。
list1 = [10, 20, 30]
list2 = list1
list3 = [1, list1]