1.多继承
python中的类支持多继承(让一个类继承多个类)
多继承的时候:子类只能继承第一个父类所有属性和方法,后面的父类中只有字段和方法能继承
(如果不同的父类中有相同名字的方法,调用时执行第一个方法)
class Animal(object):
num = 100
def __init__(self):
self.age = 0
self.gender = '雌'
@classmethod
def f1(cls):
print('动物类的类方法')
class Fly(object):
name = '飞鸡'
def __init__(self):
self.height = 100
self.time = 5
self.speed = 100
def f2(self):
print('飞行的对象方法')
class Bird(Animal, Fly):
pass
bird1 = Bird()
print(Bird.num, Bird.name) # 字段能继承
Bird.f1() # 类方法可以继承
bird1.f2() # 对象方法可以继承
print(bird1.age, bird1.gender) # 继承前面一个类的属性,第二个类以后只能继承方法
2.运输符重载是在不同的类中实现同样的运算符函数
类的对象默认情况只支持:== ,!=
python中所有的类型都是类,所以所有的数据都是对象;
python中使用任意的运算符都是在调用相应的类中的方法,每一个运算符对应的方法是固定的,
某种数据是否支持某个运算符操作就看这个数据类型是否上线了对应的方法
import copy
class Student:
def __init__(self, name, age, score=0):
self.name = name
self.age = age
self.score = score
def __repr__(self):
return '%s' % (str(self.__dict__)[:])
# a + b = c -> a : self , b : other(a.__add__(b))
# self -> 当前类的对象,也是 + 前面的那个数据
# other -> + 后面的数据,类型根据运算规则的设计,可以是任何数据的数据
def __add__(self, other):
# return self.age + other.age
# return self.score + other.score
pass
def __mul__(self, other):
list = []
for _ in range(other):
list.append(copy.copy(self))
return list
pass
# a < b >>> a.__lt__(b)
# 注意:大于和小于只需要重载一个就可以了
def __lt__(self, other):
return self.score < other.score
stu1 = Student('小明', 19, 90)
stu2 = Student('小娿', 19, 80)
# print(stu1 + stu2) # TypeError: unsupported operand type(s) for +: 'Student' and 'Student'
print(stu1 == stu2)
# False
print(stu1 + stu2)
print(stu1 * 3)
students = [stu1, stu2, Student('x', 12, 100)]
students.sort()
print(students)
3.浅拷贝和深拷贝
from copy import copy, deepcopy
class Dog:
def __init__(self, name, color):
self.name = name
self.color = color
def __repr__(self):
return '<%s,id:%s>' % (str(self.__dict__)[:], hex(id(self)))
class Person:
def __init__(self, name, age, dog=None):
self.name = name
self.age = age
self.dog = dog
p1 = Person('x', 18, Dog('大黄', '白'))
1).直接赋值
将变量中的地址直接赋给新的变量;赋值后两个变量的地址相同(并且修改任意一个对象的值另外一个对象对应的内容也会改变)
p2 = p1
print(id(p1), id(p2))
2).拷贝
不管是浅拷贝还是深拷贝都会对原数据进行赋值产生新地址
list1 = [1, 2, 3]
list2 = copy(list1)
list3 = deepcopy(list1)
print(id(list1), id(list2), id(list3))
# 2127748710792 2127748205576 2127748205192
p3 = copy(p1)
p4 = deepcopy(p1)
print(id(p3), id(p4))
# 1989001996872 1989001997064
3).浅拷贝
字符串、列表、元祖的切片;对象.copy();copy模块中的copy方法都是浅拷贝
浅拷贝只会拷贝当前对象不会改变子对象(复制里面的所有内容到一个新地址,但是子对象地址不会变)
print(id(p1), id(p3))
print(id(p1.dog), id(p3.dog))
# 3005243843208 3005243845640
# 3005243843144 3005243843144
p1.name = 'tom'
print(p1.name, p3.name)
# tom x
p1.dog.color = 'hong'
print(p1.dog.color, p3.dog.color)
# hong hong
4).深拷贝
会将对象中的子对象也重新拷贝到一个地址
print(id(p1), id(p4))
print(id(p1.dog), id(p4.dog))
p1.name = 'tom'
print(p1.name, p4.name)
p1.dog.color = 'hong'
print(p1.dog.color, p4.dog.color)
# 2102245188296 2102245190920
# 2102245188232 2102245190984
# tom x
# hong 白
练习:
a = ['color', 'height', 'background']
b = [a, 'aaa', 'bbb']
c1 = b
c2 = copy(b)
c3 = deepcopy(b)
a[-1] = ['BG']
b.append('ccc')
# 问题:print(c1)>>>>[['color', 'height', 'BG'], 'aaa', 'bbb', 'ccc' ],
# print(c2)>>>[['color', 'height', 'BG'], 'aaa', 'bbb'],
# print(c3)>>>[['color', 'height', 'background'], 'aaa', 'bbb']
4.枚举
枚举值的特点:
1.可以通过有意义的属性名直接显示数据
2.每个数据值不能修改
3.可以做到不同数据的值唯一
from enum import Enum, unique
@unique # 装饰器,让数据的值唯一
class Poker(Enum):
J = 11
Q = 12
K = 13
A = 1
print(Poker.J)
# Poker.J
print(Poker.K.value)
# 13
5.内存
1.内存的开辟
内存区间分为:栈区间和对区间栈区间内存自动开辟,堆区间的内存需要程序员手动开辟和释放
但是python将堆区间内存的开辟和释放自动化
自动开辟:
当每次给变量赋值的时候,系统会先在堆区间中开辟空间将数据存起来,然后再将数据在堆中的地址存到变量中,
而变量存在栈区间;
数字数据和字符串数据在开辟的时候会检查内存中是否有这个数据,如果有则会直接将以前的
数据的地址赋给变量,如果没有才会重新开辟新空间存数据
from sys import getrefcount
a = [1, 2, 3, [1, 2]]
b = [1, 2, 3, [1, 2]]
print(id(a), id(b))
# 2590049784392 2590049784904
print(id(a[3]), id(b[3]))
# 2012519486024 2012520771848
print(id(a[0]), id(b[0]), id(a[3][0]), id(b[3][0]))
# 140733860114688 140733860114688 140733860114688 140733860114688
a1 = 100
b1 = 100
print(id(a1), id(b1))
# 140733962157408 140733962157408
a2 = 'a'
b2 = 'a'
print(id(a2), id(b2))
# 2590079334192 2590079334192
2.内存的释放
栈区间:全局栈区间在程序结束时销毁,函数栈区间在函数调用结束时销毁(自动)
(垃圾回收机制)堆区间:看一个对象是否销毁就看这个对象的应用计数是否为0,
如果这个对象的引用计数为0,这个对象会被销毁
注意:python中针对对象的循环引用已经做了处理,程序员不需要写额外的代码来解决循环引用问题
a6 = {'name': 'x', 'age': 18}
print(getrefcount(a6))