类
类的组成
class Student:native_place = '吉林' #类属性__type = 'Person' #类的私有属性def __init__(self,name,age): #name ,age为实例属性self.name = nameself.age = age#实例方法def info(self):print("my name is %s,my age is %s" % (self.name,self.age))#类方法 当方法中需要使用类对象 (如访问私有类属性等)时,定义类方法可以获取@classmethoddef get_type(cls):print('类方法')return cls.__type#静态方法 静态方法不会自动传递实例对象和类对象@staticmethoddef sm():print('静态方法')
类的对象
stu = Student('Jack',30) #创建一个实例对象stu.info() #调用实例方法print(stu.name) #实例属性print(stu.age) #实例属性print(stu.native_place) #类属性#动态改变类属性Student.native_place = '天津'print(stu.native_place) #输出为天津
类方法和静态方法
当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
取消不需要的参数传递,有利于 减少不必要的内存占用和性能消耗
Student.get_type()>>PersonStudent.sm()>>静态方法
三大特性
- 封装
将数据的属性和行为包装到类对象中,python中如果要使用私有属性或者类,在前面使用’__’
class Student:def __init__(self,name,age):self.name = nameself.__age = agedef show(self):print('这个学生的名字是%s ,年龄是%d' %(self.name,self.__age))stu1 = Student('张三',20)print(stu1.show())print(stu1.name)
print(stu1.__age)
print(stu1._Student__age) 可以这样输出 私有属性
- 继承
Class Person:def __init__(self,name,age):self.name = nameself.age = agedef info(self):print('姓名:{0} 年龄:{1}'.format(self.name,self.age))Class Student(Person):def __init__(self,name,age,score):super().__init__(name,age)self.score=scoredef info(self):super().info()print('成绩:{0}'.format(self.score))Class Teacher(Person):def __init__(self,name,age,year):super().__init__(name,age) #继承父类的方法和属性self.year = yearstu1 = Student('李四',30,100)stu1.info() #方法重写了,调用子类的方法teacher = Teacher('张梅',40,'初三')teacher.info() #直接使用父类的方法
super()的方法
class Base(object):def __init__(self):print("enter Base")print("leave Base")class A(Base):def __init__(self):print("enter A")super(A,self).__init__()print("leave A")class B(Base):def __init__(self):print("enter B")super(B,self).__init__()print("leave B")class C(A,B):def __init__(self):print("enter C")super(C,self).__init__()print("leave C")c = C()>>>>enter Center Aenter Benter Baseleave Baseleave Bleave Aleave C
MRO列表:
事实上,对于你定义的每一个类,Python 会计算出一个方法解析顺序(Method Resolution Order, MRO)列表,它代表了类继承的顺序,我们可以使用下面的方式获得某个类的 MRO 列表。这个列表真实的列出了类C的继承顺序。C->A->B->Base->object。在方法调用时,是按照这个顺序查找的。
那这个 MRO 列表的顺序是怎么定的呢,它是通过一个 C3 线性化算法来实现的,这里我们就不去深究这个算法了,感兴趣的读者可以自己去了解一下,总的来说,一个类的 MRO 列表就是合并所有父类的 MRO 列表,并遵循以下三条原则:
- 子类永远在父类前面
- 如果有多个父类,会根据它们在列表中的顺序被检查
如果对下一个类存在两个合法的选择,选择第一个父类
def super(cls, inst):mro = inst.__class__.mro()return mro[mro.index(cls) + 1]
其中,cls 代表类,inst 代表实例,上面的代码做了两件事
获取 inst 的 MRO 列表
- 查找 cls 在当前 MRO 列表中的 index, 并返回它的下一个类,即 mro[index + 1]
这里的 self 是当前 C 的实例,self.class.mro() 结果是
C.__class__.mro()>>>>[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]
可以看到,C 的下一个类是 A,于是,跳到了 A 的 init,这时会打印出 enter A,并执行下面一行代码:
super(A,self).__init__()
注意,这里的 self 也是当前 C 的实例,MRO 列表跟上面是一样的,搜索 A 在 MRO 中的下一个类,发现是 B,于是,跳到了 B 的 init,这时会打印出 enter B,而不是 enter Base
Object类
- Object类是所有类的父类,所有的类都包含object类的属性和方法
- 内置函数dir()可以查看所有指定对象的属性
- object类有一个内置的str()方法,用于返回一个对于对象的描述,对应内置函数str()经常 用print()进行重写
| 特殊属性名 | 作用 | 特殊方法 | 作用 | | | —- | —- | —- | —- | —- | | dict | 属性字典类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类dict里的Class Student:def __init__(self,name,age):self.name = nameself.age = agedef __str__(self):return '姓名:{0} 年龄:{1}'.format(self.name,self.age)stu1 = Student('张三',20)print(stu1)print(type(stu1))
对象的dict中存储了一些self.xxx的一些东西
| len() | | | | class | 对象所属的类 | add(self,other) | 相加运算 | s = stu1.add(stu1)
任意2个对象相加 | | bases | 父类的元素 | new() | | 创建一个对象self | | base | 多态继承的第一个元素 | init() | 类的对象初始化 | 给 参数赋值,返回给实例对象 | | mro | 类的层次结构 | subclasses() | 子类的列表 | | | | | repr() | 会返回和调用者有关的 “类名+object at+内存地址”信息 | 方法返回一个实例的代码表示形式,通常用来重新构造这个实例。 | | | | str() | 输出对象变量:
默认输出<__main__.Person object at 0x00000000026F90F0> | str() 方法将实例转换为一个字符串,使用 str() 或 print() 函数会输出这个字符串 |
class A:passclass B:passclass C(A,B):def __init__(self,name,age):self.name = nameself.age = agex = C('jack',20)print(x.__dict__) #实例对象的属性字典print(C.__dict__) #类对象的属性字典print(x.__class__) #实例对象所属的类print(C.__bases__) #父类的元素,返回元组print(C.__base__) #继承的第一个父类元素print(C.__mro__) #类的层次结构print(A.__subclasses__()) #子类的列表>>>{'name':'jack','age':20}>>>{'__module__':'__main__','__init__':<function C.__init__ at 0x00001c53432e>,'__doc__':None}>>><class '__main__.C'>>>>(<class '__main__.A'>,<class '__main__.B'>)>>><class '__main__.A'>>>>(<class '__main__.C'>,<class '__main__.A'>,<class '__main__.B'>,<class 'object'>)>>>[<class '__main__.C'>]
class Student:def __init__(self,name):self.name = namedef __add__(self,other):return self.name+other.namedef __len__(self):return len(self.name)stu1 = Student('张三')stu2 = Student('李四')s = stu1+stu2print(s)print(stu1.__add__(stu2))print(stu2.__len__())>>> 张三李四>>> 张三李四>>> 2list1 = [1,2,3,4,5]print(list1.__len__())>>> 5
class Singleton(object):def __new__(cls,*args,**kwargs):print('__new__被调用了,cls的值为{0}'.format(id(cls)))obj = super().__new__(cls)print('obj被创建的对象id为{0}'.format(id(obj)))return objdef __init__(self,name,age):print('__init__被调用了,self的值为{0}'.format(id(self)))self.name = nameself.age = ageprint('obj这个类对象的id为{}'.format(id(object)))print('Singleton这个类对象的id为{}'.format(id(Singleton)))p1 = Singleton('李四',30)print('p1这个实例对象的id为:{0}'.format(id(p1)))>>obj 对象3232Singleton 对象9360__new__ cls 9360obj 7140self 7140p1 实例 7140
- 详细的说明
```python
import copy
class cpu:
pass
class disk:
pass
class computer:
def init(self,cpu,disk):
cpu1 = cpu() cpu2 = cpu1 print(id(cpu1)) print(id(cpu2))self.cpu = cpuself.disk = disk
8940 8940 disk1 = disk() computer1 = computer(cpu1,disk1)
浅copy不copy类的子类
computer2 = copy.copy(computer1) computer3 = copy.deepcopy(computer1) print(computer1,computer1.cpu,computer1.disk) print(computer2,computer2.cpu,computer2.disk)
>
computer1和computer2的内存地址不一样,但是子对象的内存地址是一样的
computer1和computer3的子对象内存地址也不一样
<__main__.computer object at 0x0000001781F3284C0>,<__main__.cpu object at 0x0000001781F3432CF21><__main__.disk object at 0x0000001781F34323FD2> <__main__.computer object at 0x0000001781F329180>,<__main__.cpu object at 0x0000001781F3432CF21><__main__.disk object at 0x0000001781F34323FD2> <__main__.computer object at 0x0000001781F3223F4>,<__main__.cpu object at 0x0000001781F3432FE32><__main__.disk object at 0x0000001781F343222E5>
```
