python面向对象3、内存管理和拷贝

2019-08-12  本文已影响0人  举颗凤梨

1.多继承

class Animal(object):
    num = 100
    name = 'hh'

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

    @classmethod
    def func1(cls):
        print('动物类的类方法')


class Fly(object):
    name = '飞行器'

    def __init__(self):
        self.height = 100
        self.time = 20
        self.spend = 100

    def func1(self):
        print('红红火火')

    def func2(self):
        print('飞行的对象方法')


class Bird(Animal,Fly):
    pass


bird = Bird()
print(Bird.num,Bird.name)
bird.func1()
bird.func2()
print(bird.age)

运算符重载

import copy

python中所有的类型都是类,所以所有的数据都是对象
python中使用任意的运算符都是在调用相应类中的相应方法,每一个运算符对应什么方法是固定
某种数据是否支持某个运算符操作就看这个数据类型中是否实现了对应的方法

2.运算符重载指的是在不同的类中实现同样的运算符对应的函数

类的对象默认情况下只支持:==,!=

class Student:
    def __init__(self, name, age, score=0):
        self.name = name
        self.age = age
        self.score = score

    def __repr__(self):
        return str(self.__dict__)

    # a+b  ->  a.__add__(b)
    # self  ->  当前类的对象,也就是+前面的那个数据
    # other  ->  +后面的那个数据,类型根据运算规则的设计可以是任何类型的数据
    def __add__(self, other):
        # return self.age + other.age
        # return self.score + other.score
        return self.name + other.name, self.age + other.age, self.score + other.score
        # return 'abc'

    def __mul__(self, other):
        list1=[]
        for _ in range(other):
            list1.append(copy.copy(other))
        return list1

    # 大于和小于运算符只需要重载一个,另外一个自动实现
    def __lt__(self, other):
        return self.score < other.score


stu1 = Student('小明', 12, 34)
stu2 = Student('小胡', 15, 67)
stu3 = Student('小胡', 15, 47)

print(stu1 == stu2, stu1 != stu2)   # False True
print(stu1 + stu2)  # return self.age + other.age 27
print(stu1 + stu2)  # return self.score + other.score 101
print(stu1 + stu2)  # return self.name + other.name,self.age + other.age,self.score + other.score   ('小明小胡', 27, 101)
print(stu1 + stu2)  # return 'abc' abc
students = [stu1, stu2, stu3]
students.sort()
print(students)

""" = = = HJR = = = """

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__)[1:-1],hex(id(self)))


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

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


p1 = Person('小米',18,Dog('大黄','黄色'))

1.直接赋值

将变量中的地址直接赋给新的变量,赋值后两个变量的地址相同

p2 = p1
print(id(p1),id(p2))   # 3032819635872 3032819635872
p1.name = '小花'
print(p1.name,p2.name)   # 小花 小花

2.拷贝

不管是浅拷贝还是深拷贝都会对原数据进行赋值产生新的地址
浅拷贝只拷贝当前对象,不会拷贝子对象,还是与原来的子对象相关联
深拷贝拷贝所有,完全与原对象分离

print(id(p1),id(copy(p1)),id(deepcopy(p1)))  # 2045139556000 2045139556168 2045139556728

3.浅拷贝

字符串、列表和元祖的切片;对象.copy();copy模块中的copy方法都是浅拷贝

p3 = copy(p1)
print(p1,p3)   # <'name': '小花', 'age': 18, 'dog': <'name': '大黄', 'color': '黄色',id:0x29a6c9213c8>,id:0x29a6c921668> <'name': '小花', 'age': 18, 'dog': <'name': '大黄', 'color': '黄色',id:0x29a6c9213c8>,id:0x29a6c921668>
p3.dog.name = '哈尼'
p3.name = '小童'
print(p1,p3)   # <'name': '小花', 'age': 18, 'dog': <'name': '哈尼', 'color': '黄色',id:0x285c82e13c8>,id:0x285c82e1668> <'name': '小童', 'age': 18, 'dog': <'name': '哈尼', 'color': '黄色',id:0x285c82e13c8>,id:0x285c82e1940>
# 发现dog中的改变会一同改变


# 4.深拷贝
"""
copy模块中的deepcopy为深拷贝,有且仅有这一个
"""
p4 = deepcopy(p1)
print(p1,p4)   # <'name': '小花', 'age': 18, 'dog': <'name': '哈尼', 'color': '黄色',id:0x15086f915f8>,id:0x15086f916a0> <'name': '小花', 'age': 18, 'dog': <'name': '哈尼', 'color': '黄色',id:0x15086f915f8>,id:0x15086faae10>
p4.dog.name = '大华'
p4.name = '小美'
print(p1,p4)  # <'name': '小花', 'age': 18, 'dog': <'name': '哈尼', 'color': '黄色',id:0x1d71fee15f8>,id:0x1d71fee16a0> <'name': '小美', 'age': 18, 'dog': <'name': '大华', 'color': '黄色',id:0x1d71fefaeb8>,id:0x1d71fefada0>

练习

a = ['color','height','background']
b = [a,'aaa','bbb']
c1 = b
c2 = copy(b)
c3 = deepcopy(b)
a[-1] = ['BG']
b.append('ccc')
# [['color','height',['BG']],'aaa','bbb','ccc']
# [['color','height',['BG']],'aaa','bbb']
# [['color', 'height', 'background'], 'aaa', 'bbb']
# 问题:print(c1),print(c2),print(c3)的打印结果

""" = = = HJR = = = """
from enum import Enum,unique

枚举值的特点:

1.可以通过有意义的属性名直接显示数据
2.每个数据的值不能修改
3.可以做到不同的数据是唯一的

unique确保不同的数据是唯一的
在类中继承Enum可以做到枚举

@unique
class PokerNum(Enum):
    J = 11
    Q = 12
    K = 13


print(PokerNum.J)    # PokerNum.J
print(PokerNum.J.value > PokerNum.Q.value)   # False

""" = = = HJR = = = """

获取引用计数

from sys import getrefcount

1.内存的开辟

内存区间分为栈区间和堆区间;栈区间的内存自动开辟自动释放,堆区间的内存需要程序员手动开辟手动释放;
但是python已经将堆区间内存的开辟和释放自动化

a. 当给变量赋值的时候,系统会先在堆区间中开辟空间将数据存起来,然后再将数据在队中的地址存到变量中,变量存在栈区间;
b. 数字和字符串数据在开辟空间的时候,会先检查内存中之前是否已经有这个数据,
如果有,直接使用之前的数据,不再开辟空间,如果没有,才重新开辟空间

a, b = [1, 2, 3], [1, 2, 3]
print(id(a), id(b), a is b)   # 1567575270024 1567575270088 False
print(id(a[0]),id(b[0]), a[0] is b[0])  # 140726342640464 140726342640464 True
a, b = 10, 10
print(id(a), id(b), a is b)   # 140726342640752 140726342640752 True
a, b = '10', '10'
print(id(a), id(b), a is b)   # 1567575737208 1567575737208 True

2,内存的释放

栈区间:全局栈区间在程序结束后销毁,函数栈区间在函数调用结束后销毁(自动)
堆区间:看一个对象是否销毁,就看这个对象的引用计数是否为0;
如果一个对象的引用计数为0,这个对象就销毁,反之不销毁(垃圾回收机制)
注意:python中针对对象的循环引用,已经做了处理,程序员不需要写额外的代码来解决循环引用的问题

a = [1, 2, 3]
print(getrefcount(a))  # 2 会打印比之前多一个引用,因为函数本身会有一个

def fun(a={}):
    a[1]=3
    return a


print(fun())
print(fun())

上一篇 下一篇

猜你喜欢

热点阅读