day16-深拷贝和浅拷贝

2019-06-24  本文已影响0人  冯书简

多继承

1.多继承

python中的类支持多继承

class 子类(父类1, 父类2,...):
pass

class Fly(object):
    """飞行类"""
    f_num = 10

def __init__(self):
    self.height = 0
    self.speed = 0
    self.time = 0

def start(self, speed):
    self.speed = speed

# print(self.speed)

​    print('开始飞行')

class Animal(object):
    num = 100

def __init__(self):
    self.age = 0
    self.gender = '公'

@staticmethod
def eat(food: str):
    print('吃'+food)

class Bird(Animal, Fly):
    pass

b1 = Bird()

# 字段都可以继承

print(Bird.f_num, Bird.num)   # 10, 100

# 方法都可以继承

b1.start(10)
Bird.eat('肉')

# 只能继承第一个父类的对象属性

# print(b1.age, b1.gender)

# print(b1.height, b1.time, b1.speed)

运算符的重载

1. 运算符

python中所有的数据类型本质都是类, 所有的数据本质就是对象。

在使用运算符对数据进行操作的时候,实质是调用运算符对应的魔法方法;
运算符前面的数据类型,决定了函数哪个类中对应的魔法方法

每个运算符都有自己固定的魔法方法, 看某种类型的数据是否支持某种运算符就看这个类型中有没有实现对应的魔法方法
例如: + - add
> - gt

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__)[1:-1]

# +号对应的魔法方法:实现两个对象求和

# self + other  ->  self.__add__(other)

# 函数的返回值就是运算结果

def __add__(self, other):
    print('self:', self.name)
    print('other:', other.name)
    return self.age + other.age

# *号对应的魔法方法:实现对象乘以整数

def __mul__(self, other):
    return self.age * other

# 注意: >和<只需要重载一个,另外一个自动支持

# self < other

def __lt__(self, other):
    return self.score < other.score

stu1 = Student('小明', 19, 90)
stu2 = Student('小胡', 20, 89)

print(stu1 == stu2)   # False

print(stu1 + stu2)     # stu1.__add__(stu2)

# print(stu1 > stu2)

print('abc'*4)

print(stu1 * 2)    # stu1.__mul__(2)

all_student = [
    Student('stu1', 17, 90),
    Student('stu2', 20, 89),
    Student('stu3', 12, 70),
    Student('stu4', 40, 81)
]
print(all_student)

# 问题

# all_student.sort()   # TypeError: '<' not supported between instances of 'Student' and 'Student'

# 解决方案一:给key赋值

# all_student.sort(key=lambda item: item.score)

# print(all_student)

# 解决方案二: 重载<运算符

# all_student.sort()

# print(all_student)

print(stu1 < stu2)
print(stu1 > stu2)

print(max(all_student))

内存管理

手动内存管理

内存分为栈区间和堆区间,栈区间中的内存是自动开辟自动释放; 堆上的内存需要程序员写代码申请和释放

1.内存的开辟

python中所有的类型就是类,所以所有的数据都是对象。对象都是保存在堆区间;变量是保存在栈区间,
变量中实际存储的是堆中存储的数据的地址。(变量的本质就是指针)

注意: 除了数字和字符串对象,其他的数据都是每次需要数据的时候直接在堆中开辟空间。
数字和字符串会先检查这个数据之前是否保存过,如果保存过就直接用之前的数据,否则才开辟新的内存空间

from sys import getrefcount
list1 = [1, 2, 3]
list2 = [1, 2, 3]
print(id(list1), id(list2))

list3 = list2

num1 = '100'
num2 = '100'
print(id(num1), id(num2))

num1 = 2**1999
num2 = 2**1999
print(id(num1), id(num2))

# def change(x, y):

# temp = x

# x = y

# y = temp

#
#

# a = 10

# b = 20

# change(a, b)

# print(a, b)

2.内存的释放

python中内存的释放采用的是'垃圾回收机制'自动释放

a.垃圾回收机制: 1)看一个数据是否需要销毁(是否需要回收),就看这个对象的引用计数是否为0(引用:保存对象地址的数据)。
2)如果这个对象的引用计数不为零就假设当前对象消失,然后看会不会有其他对象因为它的消失引用计数变成0,
如果有,就将另外一个对象回收(循环引用解环)

注意: 用一个变量给另外一个变量赋值,实质赋的是地址

list1 = [10, 20, 30]
print(getrefcount(list1))

list2 = list1
print(getrefcount(list1))

# def yt_getrefcount(obj):

# # obj = list1

# print('获取obj的引用次数')

#

# print(yt_getrefcount(list1))

num = 100
print(getrefcount(num))

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.dog = None

class Dog:
    def __init__(self, name, age, color):
        self.name = name
        self.age = age
        self.color = color
        self.owner = None

p1 = Person('小明', 18)
dog1 = Dog('财财', 3, '黄色')
p1.dog = dog1
dog1.owner = p1

del p1
del dog1
# 面试题:== 和 is的区别?

# 补充: is的使用 - 判断两个数据的地址是否一样

list1 = [1, 2, 3]
list2 = [1, 2, 3]
list3 = list1
print(list1 == list2, list1 == list3)   # True, True
print(list1 is list2, list1 is list3)   # False, True

深拷贝和浅拷贝

import copy

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        self.dog = None

def __repr__(self):
    return '<%s>' % str(self.__dict__)[1:-1]

class Dog:
    def __init__(self, name, color):
        self.name = name
        self.color = color

def __repr__(self):
    return '<%s>' % str(self.__dict__)[1:-1]

使用变量的三种情况:

1.直接赋值 - 赋的是地址,赋完值两个变量一模一样

变量1 = 变量2

list1 = [1, 2, 3]
list2 = list1

list1.append(10)
print(list1)   # [1, 2, 3, 10]
print(list2)   # [1, 2, 3, 10]

2.浅拷贝

列表[:]、列表.copy()、copy.copy(数据)

浅拷贝: 直接复制被拷贝的数据产生一个新的地址,将新的地址赋给变量; 如果被拷贝的对象中有子对象,子对象不会被复制

p1 = Person('小明', 18, '男')
p1.dog = Dog('大黄', '黄色')

# p2 = p1

print('============浅拷贝==============')
p2 = copy.copy(p1)
p2.name = 'Tom'
p2.dog.color = '褐色'
print(p1)    # <'name': '小明', 'age': 18, 'gender': '男'>
print(p2)    # <'name': 'Tom', 'age': 18, 'gender': '男'>

3.深拷贝

copy.deepcopy(数据)
深拷贝: 直接复制被拷贝的数据产生一个新的地址,将新的地址赋给变量; 如果被拷贝的对象中有子对象,子对象也会被复制

print('============深拷贝==============')
p1 = Person('小明', 18, '男')
p1.dog = Dog('大黄', '黄色')
p3 = copy.deepcopy(p1)

p3.name = '小花'
p3.gender = '女'
p3.dog.color = '红色'

print(p1)
print(p3)

a = 10
b = 257
c1 = 257

def te():
    c = 10
    d = 257
    print(a is c)
    print(b is d)
    print(id(a),id(b),id(c),id(d))

te()
print(id(c1), id(b))
上一篇下一篇

猜你喜欢

热点阅读