面向对象进阶、深浅拷贝及内存管理
-
面向对象进阶
-
对象属性的增删改查
-
查 - 获取属性的值 (
getattr
)# 对象.属性 - 获取执行属性对应的值,如果属性不存在报错 # getattr(对象, 属性名) - 获取执行属性对应的值,如果属性不存在报错 # getattr(对象, 属性名, 默认值) - 获取执行属性对应的值,如果属性不存在不报错,直接返回指定的默认值 print(stu1.name) print(getattr(stu1, 'name')) # 方法二可以动态确定需要获取的内容 # value = input('学生的哪个信息: name? age? tel? gender?:') # # print(stu1.value) # print(getattr(stu1, value))
-
增、改 (
setattr
)# 对象.属性 = 值 - 如果属性存在就是修改,属性不存在就是添加 # setattr(对象, 属性名, 值) - 如果属性存在就是修改,属性不存在就是添加 stu1.name = '小花' print(stu1) stu1.score = 100 print(stu1, stu1.score) setattr(stu1, 'height', 170) print(stu1) setattr(stu1, 'age', 30) print(stu1)
-
删 (
delattr
)# del 对象.属性 # delattr(对象, 属性名) del stu1.gender print(stu1) # print(stu1.gender) # AttributeError: 'Student' object has no attribute 'gender' delattr(stu1, 'tel') print(stu1)
-
-
内置属性
-
类/对象.__dict__
- - - 将类/对象转换成字典,类的话以类属性名作为键,类属性对应的值作为值, 对象的话,对象属性名是键,对象属性对应的值是值# 类.__dict__ - 将类转换成字典,将所有的类属性名作为键,类属性对应的值作为值 # 对象.__dict__ - 将对象转换成字典,对象属性名是键,对象属性对应的值是值 print(A.__dict__) print(a.__dict__) # {'m': 10, 'n': 'hello', 'p': True}
-
对象.__class__
- - - 获取对象对应的类,功能和type一样# 对象.__class__ - 获取对象对应的类,功能和type一样 print(a.__class__, type(a))
-
类.__name__
- - - 获取类名# 类.__name__ - 获取类名(返回的是 字符串) print(A.__name__) # 'A'
-
类.__doc__
- - - 获取类的说明文档# 类.__doc__ - 获取类的说明文档 print(int.__doc__)
-
类.__module__
- - - 获取定义指定类的模块名# 类.__module__ - 获取定义指定类的模块名 print(A.__module__, int.__module__)
-
类.__base__
/类.__bases__
- - - 获取类的父类/所有父类# 类.__base__ - 获取当前类的父类 # 类.__bases__ - 获取当前类所有的父类 print(A.__base__) # <class 'object'> print(A.__bases__) # (<class 'object'>,)
-
__slots__
- - - 用来约束当前类的对象最多有哪些对象属性class Student: # 类属性__slots__是用来约束当前类的对象最多有哪些对象属性; # 注意:如果给类的__slots__属性赋值了,那么这个类的对象就不能再使用__dict__属性 __slots__ = ('name', 'age', 'score', 'height') def __init__(self): self.name = '小明' pass stu = Student() print(stu.name) stu.age = 18 print(stu.age)
-
-
访问权限私有化
-
访问权限(面向对语言通用)
""" 公开的:属性和方法在类的内部、类的外部都可以使用,也可以被继承 (python中所有的属性和方法都是公开的) 保护的:属性和方法在类的内部可以使用,也可以被继承 私有的:属性和方法只能在类的内部使用 """
-
python私有化是假的(内部的私有化
__x
,相当于外面的_类名__x
): 再名字前加__
例如:__x
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)
-
-
类的继承
-
什么是继承
""" 继承就是让子类直接拥有父类所有的属性和方法。 子类 - 继承者 父类 - 被继承者,又叫超类 """
-
继承的语法
""" 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): # 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)
-
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('大黄', '黄色')
-
-
运算符重载
-
魔法方法
""" 类中自带的以__开头并且以__结尾的方法就是魔法方法,所有的魔法方法都不需要程序去调用,会在特定情况下自动调用。 这些魔法方法中有一部分方法是在对象使用运算符的时候会被自动调用。 每一个运算符都有一个固定的魔法方法,某种数据是否支持某种,就看这个数据对应的类中有没有实现对应的魔法方法。 """ 10 + 20 # 10.__add__(20) 'abc' + '234' # 'abc'.__add__('234') 10.2 > 20
-
重载运算符 - 在自己的类中通过现实运算的魔法方法来让自己的类的对象支持指定的运算符
# 自己定义的类默认支持比较是否相等 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(max(students)) students.sort() print(students)
-
-
-
深浅拷贝
和直接赋值
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
-
内存的释放
# 原则:如果数据有引用数据就不会被销毁(不会释放),如果数据没有引用(引用计数为0)就会被自动销毁(释放)。 list1 = [10, 20, 30] list2 = list1 list3 = [1, list1]
-