面向对象
继承
-
什么是继承
- 子类直接拥有父类的属性和方法的过程就是继承
- 子类:继承者
- 父类:被继承着,父类又叫超类
-
怎么继承
class 子类(父类):
pass注意:
-
如果定义类的时候没有添加父类,默认继承Python的基类object
- 同一个子类可以同时继承多个父类: class 子类(父类1, 父类2, 父类3,...)
Python子类可以继承父类所有的属性和方法
class Person(object): num = 61 def __init__(self): self.name = '小红' self.age = 18 self.gender = '女' def eat(self, food): print(f'{self.name}正在吃{food}') @classmethod def show_num(cls): print('人数:', cls.num) @staticmethod def info(): print('人类保护环境!') class Student(Person): pass stu1 = Student() print(stu1.name, stu1.age, stu1.gender) print(stu1.num) stu1.eat('面') stu1.info()
-
重写
-
在子类中添加属性和方法
- 添加类属性:直接在子类中定义新的类属性
- 添加方法:直接在子类中定义新的方法
在子类中添加方法的时候可以对父类方法进行重写
在子类中可以通过super().方法
的形式来调用父类中的方法。(注意:不能在静态方法中使用super()调用父类的方法)
总结:super的用法
可以通过super在子类中调用父类的方法
super().方法() - 直接调用当前类的父类的指定方法
super(类, 对象).方法() - 调用指定类的父类的指定方法(要求对象必须是前面的类的对象)- 添加对象属性方法
在子类的_ _ init _ _方法中通过super()去调用父类的 _ _ init _ _
class A:
x = 100
@staticmethod
def fun1():
print('A')
@classmethod
def funa(cls):
print('A1')
class B(A):
y = 20
@classmethod
def fun2(cls):
print('B')
@staticmethod
def fun1():
print('BB')
@classmethod
def funa(cls):
super().funa()
# cls.__base__.funa()
print('B2')
@staticmethod
def fun3():
# super().fun1() # 报错
# super(B, B()).fun1()
print('B的静态方法')
class C(B):
pass
print(A.x) # 100
print(B.x) # 100
print(C.x) # 100
# print(A.y) # 报错
print(B.y) # 20
print(C.y) # 20
B.fun1() # BB
A.fun1() # A
B.funa() # A1 B2
class Animal:
def __init__(self, age=18, sex='雌'):
self.age = age
self.sex = sex
class Cat(Animal):
def __init__(self, color='白', price=2000):
super().__init__(20, '雄')
self.color = color
self.price = price
c1 = Cat()
print(c1.color, c1.age, c1.sex) # 白 20 雄
对象属性的添加
class A:
def __init__(self, a, b=10):
self.a = a
self.b = b
self.c = 0
class B(A):
def __init__(self, d, a):
# d = 100, a = 10
# super().__init__(100)
super().__init__(a) # A:__init__(200)
self.d = d
bb = B(100, 200) # B:__init__(100,200)
print(bb.a, bb.b, bb.c, bb.d) # 200 10 0 100
练习:
创建一个人类有属性:姓名、年龄、性别,要求创建人的对象的时候姓名和年龄必须赋值,性别可以赋值也可以不赋(默认是男)
创建学生类有属性:姓名、年龄、性别、学号、学分和电话,要求创建学生对象的时候,姓名和电话必须赋值。
年龄和性别可以赋值也可以不赋(默认是18和年),学分和学号创建的时候不能赋值,默认值分别是’000’和0
class Person:
def __init__(self, name, age, sex='男'):
self.name = name
self.age = age
self.sex = sex
class Student(Person):
def __init__(self, name, tel, age=18, sex='男'):
super().__init__(name, age, sex)
self.credit = '000'
self.num = 0
self.tel = tel
stu1 = Student('小明', '110')
print(f'<{str(stu1.__dict__)[1:-1]}>')
多继承
多继承的时候子类可以继承所有父类的类属性和方法,但是只能继承第一个父亲的对象属性。
class Animal:
num = 25
def __init__(self):
self.age = 0
self.sex = '雌'
@classmethod
def show(cls):
print('数量:', cls.num)
class Fly:
name = '飞行器'
def __init__(self):
self.height = 100
self.time = 3
@staticmethod
def message():
print('飞行器')
class Bird(Animal, Fly):
pass
print(Bird.num, Bird.name) # 25 飞行器
Bird.show() # 数量: 25
Bird.message() # 飞行器
b = Bird()
print(b.age, b.sex) # 0 雌
# print(b.height, b.time) # 报错
私有化
访问权限(编程常识):
-
公开的(public):在类的内部可以使用、类的外部也可以使用还可以被继承(Python中所有的属性和方法都是公开)
-
保护的(protect):在类的内部可以使用、可以被继承
-
私有的(private):在类的内部可以使用
Python的私有化
方法:在属性名或者方法名前加_ _ 就可以让属性或者方法变成私有的
原理:假的私有化;在_ _ 开头的名字前加’_类名’class A: num = 100 __x = 200 # __x是私有的 def __init__(self): self.name = '小明' self.__age = 18 # __age是私有的 def info(self): print(self.__age) @classmethod def show(cls): print(cls.num, cls.__x) print(A.num) # 100 A.show() # 100 200 # print(A.__x) # 无法使用 a = A() print(a.name) # 小明 # print(a.__age) # 无法使用 a.info() # 18
拷贝
-
浅拷贝和深拷贝的区别:
1)不管是浅拷贝还是深拷贝都是赋值被拷贝的对象产生一个新的对象,然后用新对象来赋值
2)如果被拷贝的对象中有子对象,浅拷贝直接赋值被拷贝对象的子对象,深拷贝会拷贝被拷贝对象的子对象class Dog: def __init__(self): self.name = '旺财' self.sex = '公' def __repr__(self): return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>' class Person: def __init__(self, name, age=18, sex='男'): self.name = name self.age = age self.sex = sex self.dog = Dog() def __repr__(self): return f'<{str(self.__dict__)[1:-1]}, id:{id(self)}>' p1 = Person('小明', 20, '男') p2 = p1 # 直接赋值,将p1中的地址赋值给p2 p3 = copy(p1) # 浅拷贝,复制p1产生一个新的对象,用新对象给p3赋值 p4 = deepcopy(p1) # 深拷贝,复制p1产生一个新的对象,用新对象给p4赋值 print('原数据:', p1) print('直接赋值:', p2) print('浅拷贝:', p3) print('深拷贝:', p4) print('===============') p1.name = '小花' p1.dog.sex = '母' print('原数据:', p1) print('直接赋值:', p2) print('浅拷贝:', p3) print('深拷贝:', p4) # 练习: A = [10, 20, 30, ['abc', '123']] B = A C = copy(A) D = deepcopy(A) A.append(100) A[3].pop() print(B) # [10, 20, 30, ['abc'], 100] print(C) # [10, 20, 30, ['abc']] print(D) # [10, 20, 30, ['abc', '123']]
内存管理
内存管理分为内存的开辟和释放
-
内存的开辟
Python中所有的类型都是类,所有的数据都是对象,对象都保存在堆里面。
在保存数据的时候相同的不可变数据内存中只保存一份,相同的可变数据在内存中一定会保存多份list1 = [100, 200] list2 = [100, 200] tuple1 = (100, 200) tuple2 = (100, 200) print(id(list1), id(list2)) # 2177081172552 2177081172616 print(id(tuple1), id(tuple2)) # 2177081784584 2177081784584
-
内存的释放 - 垃圾回收机制
Python中内存的某个数据是否销毁(对应的内存是否释放),看这个数据在程序中的引用个数,当引用个数大于0的时候数据不会被销毁
当数据的引用个数为0的时候数据会被自动销毁。