面向对象
Posted wgbo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象相关的知识,希望对你有一定的参考价值。
对象的相关定义:
对象:对象指的是类的实例。一个对象有自己的状态(属性)、行为(方法)和唯一的标识(内存地址);所有相同类型的对象所具有的结构和行为在它们共同的类中被定义。
状态:包括这个对象已有的属性(通常是类里面已经定义好的),再加上对象具有的当前属性值(往往是动态的)。
行为:指一个对象如何影响外界和被外界影响,表现为对象自身状态的改变和信息的传递。
标识:值一个对象所具有的区别于所有其他对象的属性(本质上指内存中所创建的对象的地址)。
简言之,对象应具有属性(即状态)、方法(即行为)和标识。标识是在内存中自动完成的,不用去管它,平时主要用到属性和方法。
类:类描述了所创建的对象共同的属性和方法(数据属性和方法属性)。
实例:类是对象的定义,实例才是真实的物件,是具体的个体。实例只有数据属性,没有方法属性。实例调用的方法是类中的方法,由作用域决定。
属性:
类属性:在类中定义的变量,即类的属性。
>>> class A: ... x = 7 # 类中定义变量x ... >>> A.x # 通过类名调用类中变量x 7
类的属性本质上就是类中的变量,它的值不依赖于任何实例,只是由类中所写的变量赋值语句确定。所以这个类属性又叫静态变量或静态数据。类属性只会在创建类的时候定义一次,不会因为对象的创建而重新创建。
类属性可以增加、删除或者修改。
>>> A.y = 9 # 直接向类A中增加新的属性 >>> A.y 9 >>> del A.x # 删除类中的已有属性 >>> A.x Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object ‘A‘ has no attribute ‘x‘ >>> A.y = 99 # 修改类中的属性值 >>> A.y 99
查看类中的内容:
>>> dir(A) [‘__class__‘, ‘__delattr__‘, ‘__dict__‘, ‘__dir__‘, ‘__doc__‘, ‘__eq__‘, ‘__format__‘, ‘__ge__‘, ‘__getattribute__‘, ‘__gt__‘, ‘__hash__‘, ‘__init__‘, ‘__le__‘, ‘__lt__‘, ‘__module__‘, ‘__ne__‘, ‘__new__‘, ‘__reduce__‘, ‘__reduce_ex__‘, ‘__repr__‘, ‘__setattr__‘, ‘__sizeof__‘, ‘__str__‘, ‘__subclasshook__‘, ‘__weakref__‘, ‘y‘] >>> A.__doc__ # 显示类的文档 >>> A.__name__ # 以字符串的形式返回类的名字 ‘A‘ >>> A.__base__ # 类的父类 <class ‘object‘> >>> A.__dict__ # 以字典的形式显示类的所有属性 mappingproxy({‘__doc__‘: None, ‘__module__‘: ‘__main__‘, ‘__dict__‘: <attribute ‘__dict__‘ of ‘A‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘A‘ objects>, ‘y‘: 99}) >>> A.__module__ # 类所在的模块 ‘__main__‘
类属性的总结:
类属性跟类绑定,可以自定义、删除、修改值,也可以随时增加类属性;
每个类都有一些特殊属性。
创建实例:创建实例,就是调用类。
当类被调用之后:
创建实例对象;
检查是否实现__init__()方法。如果没有实现,返回实例对象;如果实现了__init__(),则调用该方法,并且将实例对象作为第一个参数self传递进去。
__init__()是一个特殊方法,它一般规定一些属性或者初始化,让类具有一些基本的特征。__init__()方法没有return语句。
实例属性:与类属性类似,实例所具有的属性叫做实例属性。每个实例的属性定义在该实例的命名空间(内存地址)中,通过实例可以在不同的方法里直接共享实例属性。不同于函数中的局部变量,只能在函数自己内部使用,不能在其他函数中直接调用。
>>> class A: ... x = 7 ... >>> a = A() >>> A.x # 类属性 7 >>> a.x # 实例属性 7 >>> a.x += 1 # 修改实例属性 >>> a.x 8 >>> A.x # 类属性不变 7
类属性和实例属性的区别在于,类属性是直接定义在类中的属性,而实例属性是通过实例化的对象去操作与类中同名的引用。相当于实例新建了一个新的属性,这个属性与类中的属性同名。所以修改实例属性不会影响类属性。
类属性能够影响实例属性,这是因为实例就是通过调用类来建立的。即实例属性跟着类属性的改变而改变。以上都是类中变量引用不可变对象的结果,比如字符串和数。
类中变量引用可变数据时,则情形会不同,因为可变数据能够进行原地修改。
>>> class B: ... lst = [1, 2, 3] # 类中属性是可变类型 ... >>> b = B() # 类的实例 >>> B.lst [1, 2, 3] >>> b.lst [1, 2, 3] >>> b.lst.append(9) # 修改实例的属性 >>> b.lst [1, 2, 3, 9] >>> B.lst # 类属性也变化了 [1, 2, 3, 9] >>> B.lst.append(‘python‘) # 修改类属性 >>> B.lst [1, 2, 3, 9, ‘python‘] >>> b.lst # 实例属性也变化了 [1, 2, 3, 9, ‘python‘]
当类中变量引用的是可变对象时,类属性和实例属性都能直接修改这个对象,从而影响另一方的值。
如果增加一个类属性,相应的也增加了一个实例属性。增加实例属性,类属性不会跟着增加。
>>> B.y = ‘java‘ # 直接增加了一个类属性 >>> b.y # 实例属性相应的增加 ‘java‘ >>> b.z = 99 # 增加一个实例属性 >>> b.z 99 >>> B.z # 类中没有此属性 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: type object ‘B‘ has no attribute ‘z‘
以上的实例属性或类属性,都是源自类中的变量所引用的值,是静态数据。还有一种实例属性的生存方法,是在实例创建的时候,通过__init__()初始化方法建立,是动态数据。
self的作用:类中的任何方法,第一个参数都是self。
看下面的例子:
>>> class Stu: ... def __init__(self): ... self.name = ‘Jack‘ ... self.age = 18 ... print(self) # 打印self的内存地址 ... print(type(self)) # 打印self的类型 ... >>> stu = Stu() # 实例化时自动执行类中__init__()方法 <__main__.Stu object at 0x7fc4dd792780> # self的地址 <class ‘__main__.Stu‘> # self的类型 >>> print(stu) # 与self对应的实例的地址 <__main__.Stu object at 0x7fc4dd792780> >>> type(stu) # 实例的类型 <class ‘__main__.Stu‘>
上面可以看到,self的内存地址和类型与实例stu完全一致。这说明self就是Stu类的实例,即self和stu引用了同一个实例对象。当创建实例的时候,实例变量作为第一个参数,被python解释器传给了self,所以初始化函数中的self.name就是初始化实例的属性。self和实例可以理解为一个主内、一个主外,实例对象的引用会被传给self,self就是实例在类的内部的形式。
这样,在类的内部,通过self实例,类中所有方法都能承接self实例对象,它的属性也被带到类中的每个方法之中,实现了数据在类内部的流转。
以上是关于面向对象的主要内容,如果未能解决你的问题,请参考以下文章