python——全面的类学习(2)


在这里插入图片描述

1、特殊属性

(1)dir(object) 查看object的所有属性和方法

print(dir(object))
'''
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', 
'__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', 
'__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', 
'__setattr__', '__sizeof__', '__str__', '__subclasshook__']
'''

初始化C继承A、B类,并初始化实例对象x

class A:
    pass


class B:
    pass


class C(A, B):
    def __init__(self, name, age):
        self.name = name
        self.age = age

x = C('Jack', 20)

(2)x.__dict__ 查看实例对象的属性字典

print(x.__dict__)
'''
{'name': 'Jack', 'age': 20}
'''

(3)C.__dict__ 查看C类的属性和方法
在这个模块中有'__main__', '__init__',在'__init__'中有包含一个方法C<function C.__init__ at 0x000001A23B260160>

print(C.__dict__)
'''
{'__module__': '__main__', '__init__': <function C.__init__ at 0x000001A23B260160>, '__doc__': None}
'''

(4)x.__class__ 查看x的所属类

print(x.__class__)

'''
<class '__main__.C'>
'''

(5)C.__bases__ 查看C的父类元组,C的父类为A和B

print(C.__bases__)
'''
(<class '__main__.A'>, <class '__main__.B'>)
'''

(6)C.__base__ 输出C第一个父类

print(C.__base__)

在这里插入图片描述
(7)C.mro() 查看类的层次结构,C继承A、B、object

print(C.mro())
'''
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
'''

(8)A.__subclasses__() 查看子类列表:A的子类有C

print(A.__subclasses__())

'''
[<class '__main__.C'>]
'''

2、特殊方法

(1) __add__() 提供相加方法

一切皆对象的原则下,a、b为两个整数类型对象,a + b的结果为一个整数,其中实际的操作是调用了a.__add__(b)

a = 100
b = 20

c = a + b
print(c)

d = a.__add__(b)
print(d)

'''
120
120
'''

自定义的类型同样可以进行加法操作:但是直接按照下图的方法进行加法会报错

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


stu1 = Student("张三")
stu2 = Student("李四")

print(stu1 + stu2)
'''
print(stu1 + stu2)
TypeError: unsupported operand type(s) for +: 'Student' and 'Student'
'''

正确做法:利用方法重写__add__(self, other)可以使对象具有相加功能

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

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


stu1 = Student("张三")
stu2 = Student("李四")

print(stu1 + stu2)
'''
张三李四
'''

或者直接调用stu1.__add__(stu2)前提必须是在class中有add方法

print(stu1.__add__(stu2))
'''
张三李四
'''

(2) __len__ 求取长度

同理,以列表为例

lst = [1, 2, 3, 4, 5]
print(len(lst))
print(lst.__len__())
'''
5
5
'''

__add__()方法一样,通过重写__len__()方法让内置函数len()的参数可以是自定义的类型

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

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

    def __len__(self):
        return len(self.name)


stu1 = Student("Jack")
stu2 = Student("李四")

print(len(stu1))
print(stu2.__len__())
'''
4
2
'''

(3) 先__new__() 创建对象
(4) 后__init__() 初始化对象
详见例子

class Person(object):
    def __new__(cls, *args, **kwargs):
        #输出id(cls)等价于id(Person)
        print('__new__方法被调用了,cls的id为{0}'.format(id(cls)))

        obj = super().__new__(cls)
        #id(obj)是新创建的一个对象
        print('创建的对象obj的id为{0}'.format(id(obj)))
        return obj

    def __init__(self, name, age):
        print('__init__方法被调用了,self的id值为:{0}'.format(id(self)))
        self.name = name
        self.age = age


print('object的类对象的id为:{}'.format(id(object)))
print('Person的类对象的id为:{}'.format((id(Person))))

p1 = Person('张三', 20)
print('p1这个类实例对象的id为:{}'.format(id(p1)))

输出:

object的类对象的id为:140736216288080
Person的类对象的id为:1468044653824
__new__方法被调用了,cls的id1468044653824
创建的对象obj的id1468033110752
__init__方法被调用了,self的id值为:1468033110752
p1这个类实例对象的id为:1468033110752

直观的可以得出下图的结论:
在这里插入图片描述
obj = super().__new__(cls)中新创建的obj的地址 = __init__时self的地址 = 实例对象p1的地址

3、类的浅拷贝和深拷贝

  • 变量赋值:只是形成两个变量,实际上还是指向同一个对象
  • 浅拷贝:python拷贝一般都是浅拷贝,拷贝时,对象包含子的对象内容不拷贝,因此源对象与拷贝对象会引用同一个子对象
  • 深拷贝:使用copy模块deepcopy函数,递归拷贝过程中包含的子对象,源对象和拷贝对象所有的子对象也不相同

——————————————————————————————————————————————
(1)变量赋值

  • 类对象的复制操作:实际上是一个对象放到了两个变量中去存储,所以cpu1和cpu2的类指针都指向同一个实例对象(id地址相同)
class CPU:
    pass


class Disk:
    pass


class Computer:
    def __init__(self,CPU,disk):
        self.CPU = CPU
        self.Disk = Disk


cpu1 = CPU()
cpu2 = cpu1
print(id(cpu1))
print(id(cpu2))
'''
1304483658864
1304483658864
'''

(2)浅拷贝

  • python拷贝一般都是浅拷贝,拷贝时,对象包含子的对象内容不拷贝,因此源对象与拷贝对象会引用同一个子对象
print('-----------------------')
disk = Disk()  # 创建一个Disk类的对象
computer = Computer(cpu1, disk)  # 创建一个Computer类的对象

# 浅拷贝
import copy

computer2 = copy.copy(computer)
print(computer, computer.cpu, computer.disk)
print(computer2, computer2.cpu, computer2.disk)
'''
-----------------------
<__main__.Computer object at 0x000001CD3A6F8700> <__main__.CPU object at 0x000001CD3A79FC70> <class '__main__.Disk'>
<__main__.Computer object at 0x000001CD3A809490> <__main__.CPU object at 0x000001CD3A79FC70> <class '__main__.Disk'>
'''

我们发现computer和computer2的地址在内存上是两块,而id( computer.cpu) = id( computer.cpu)、id( computer.disk) = id( computer.disk),(子对象CPU、Disk没有被拷贝),即computer和computer2的实例对象不同,但具有相同的子对象(CPU、Disk实例对象相同)。换句话说就是浅拷贝无需对CPU和Disk的实例对象进行拷贝

更详细的请参考视频的6:50,介绍了类对象的浅拷贝是如何完成的
https://www.bilibili.com/video/BV1wD4y1o7AS?p=120

(下图为笔记,手写的箭头表示指针)在这里插入图片描述
(3)深拷贝

  • 使用copy模块的deepcopy函数,递归拷贝过程中包含的子对象,源对象和拷贝对象所有的子对象也不相同
#深拷贝
print("------------------------------")
computer3 = copy.deepcopy(computer)
print(computer, computer.cpu, computer.disk)
print(computer3,computer3.cpu,computer3.disk)
'''
------------------------------
<__main__.Computer object at 0x00000285C9688700> <__main__.CPU object at 0x00000285C972FC70> <class '__main__.Disk'>
<__main__.Computer object at 0x00000285CA908970> <__main__.CPU object at 0x00000285CA908CA0> <class '__main__.Disk'>
'''

我们可以看到computer和computer3的地址在内存上是两块且id( computer.cpu) ≠ id( computer.cpu)、id( computer.disk) ≠ id( computer.disk),也就是说他把拷贝对象的子对象也进行了拷贝。

结尾附赠快捷键 、截图方法、美化代码的小技巧:

(1)快捷键 :

  1. Ctrl+Alt+L :自动规范代码格式
  2. Shift+Alt+F9:编译+运行
  3. Shift+向左/右:向左、右选中一格
  4. Shift+向上、下:向上、下选中一行
  5. Ctrl+向左/右:回到该行的首位置
  6. Ctrl+F:查找关键字出现位置
    在这里插入图片描述
  7. 选中某未知的模块的函数+Ctrl+B:找到该模块(一般会有英文注释和例子来解释该函数)
    在这里插入图片描述
    在这里插入图片描述

(2)截图方法:
使用QQ的Ctrl+Alt+A或者使用微信的Alt+A,然后在博客中使用Ctrl+v就可以将图片直接粘贴到博客中,无需保存
(3)美化代码环境:

  • 推荐插件
    在这里插入图片描述
  • 设置各种代码的颜色(以设置行注释为例,其他的自行探索哈)
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_46126258/article/details/113709686
今日推荐