
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的id为1468044653824
创建的对象obj的id为1468033110752
__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)快捷键 :
- Ctrl+Alt+L :自动规范代码格式
- Shift+Alt+F9:编译+运行
- Shift+向左/右:向左、右选中一格
- Shift+向上、下:向上、下选中一行
- Ctrl+向左/右:回到该行的首位置
- Ctrl+F:查找关键字出现位置
- 选中某未知的模块的函数+Ctrl+B:找到该模块(一般会有英文注释和例子来解释该函数)
(2)截图方法:
使用QQ的Ctrl+Alt+A或者使用微信的Alt+A,然后在博客中使用Ctrl+v就可以将图片直接粘贴到博客中,无需保存
(3)美化代码环境:
- 推荐插件
- 设置各种代码的颜色(以设置行注释为例,其他的自行探索哈)