python是面向对象的语言,那么究竟什么是面向对象?html
类:在中文中的定义,许多相同或类似事物的综合。根据这个定义,类是许多相同或类似的实物聚在一块儿的。譬如,人类,鸟类,花类等。python
类的单个具体实例能够称之为对象,把类具体化单个实体的过程,这个过程称为类的实例化!数据库
面向对象程序设计中的术语对象基本上能够看作数据(特性)以及由一系列能够存取,操做这些数据的方法所组成的集合。swift
面向对象的三个基本特征:封装,继承,多态。函数
建立对象的过程称之为实例化,当一个对象被建立以后,包含三个方面的特性:对象的句柄,属性和方法。对象的句柄用于区分不一样的对象,当对象被建立后,该对象会获取一块存储空间,存储空间的地址即为对象的标识。测试
class People(object): def __init__(self,country, name,age=23): #构造方法 self.country = country #实例属性 self.name = name self.__age = age #私有属性 def __del__(self): #析构函数 print("%s has died" % self.name) def get_info(self): #实例方法 print("The %s info".center(50,"-") % self.name) print("The %s comes from %s, is %d old" % (self.name, self.country, self.__age))
实例化上面的类,spa
>>> a = People("China","hitler",20) #实例化一个类时,这时候构造函数会自动执行 >>> a.get_info() #经过实例访问类中的实例方法 -------------------The hitler info-------------------- The hitler comes from China, is 20 old
在类中定义属性时,若属性是以双下划线开始的则为私有属性,例如self.__age属性,而像self.country和self.name属性则是公有属性,不管是私有属性仍是公有属性,每一个经过实例化获得的类都有这些属性。设计
在实例化时,咱们能够像给函数传入参数那样,给类传入参数,而这些参数的最终被赋值的操做就是在构造函数中执行的。构造函数在类实例化的时候会自动执行。code
注意私有属性和实例属性的访问方法的不一样:htm
>>> a.name #访问实例属性 'hitler' >>> a.country #访问实例属性 'China' >>> a.__age #方位私有属性 Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: 'People' object has no attribute '__age' >>> a._People__age #私有属性的访问方法,实例化名._类名__私有属性名 20 >>> del a #删除一个实例,这时候,析构函数会自动执行 hitler has died #析构函数:在实例销毁的时候自动执行的,一般用于作一些收尾的工做,关闭一些数据库链接或者关闭打开的临时文件。
析构函数:在实例销毁的时候自动执行的,一般用于作一些收尾的工做,关闭一些数据库链接或者关闭打开的临时文件。
在上面的例子中,使用del删除了实例a,而后会自动返回析构函数执行的结果。
能够对实例进行增长,删除,修改操做:
对象属性的增删改 >>> A = People("USA", "jobs", "53") >>> A.country #能够经过实例修改对应的属性值 'USA' >>> A.country = "UKA" >>> A._People__age = 55 >>> A.get_info() ##能够看到实例的属性值已经修改 -------------------The jobs info-------------------- The jobs comes from UKA, is 55 old #能够经过del删除某个属性 >>> del A.country >>> A.get_info() #报错,没有对应的country属性 Traceback (most recent call last): File "<input>", line 1, in <module> File "E:\pycharm\class_method.py", line 14, in get_info print("The %s comes from %s, is %d old" % (self.name, self.country, self.__age)) AttributeError: 'People' object has no attribute 'country' -------------------The jobs info-------------------- >>> A.country = "China" #添加属性 >>> A.get_info() #能够看到属性添加成功 -------------------The jobs info-------------------- The jobs comes from China, is 55 old
注意上面的经过实例对属性的增长,删除,修改操做仅对当前的实例有效;而对于类的其他实例则没有效果。能够作以下测试以证实:
>>> a = People("USA","swift",29) #实例化一个对象 >>> a.pos = "singer" #给对象添加一个pos属性 >>> a.pos #对象a具备pos属性 'singer' >>> B = People("UKA","king",80) #再实例化一个对象B >>> B.pos Traceback (most recent call last): #对象B没有pos属性 File "<input>", line 1, in <module> AttributeError: 'People' object has no attribute 'pos'
>>> a.get_info()
-------------------The swift info--------------------
The swift comes from USA, is 29 old
>>> b.get_info()
-------------------The king info--------------------
The king comes from UKA, is 80 old
解释:
建立类的时候python会在内存中为类开辟一段内存空间,实例化的时候,python会为每个实例开辟一段内存空间,每一个实例的内存空间都是相互独立的,所以更改了a的内存空间,并不会影响B的内存空间。
若想使更改的效果,对类的每个实例都生效,可使用类变量。
在类变量以前,先说一下self参数。在类中定义的方法,每一个方法都有一个self参数,那么self参数该如何理解?
类变量:
首先知足上面提到的,让更改对每个实例都生效。
class People(object): addr = "Earth" # 类变量 def __init__(self, country, name, age=23): self.country = country self.name = name self.__age = age
而后对上面的类进行实例化操做,以下:
>>> a = People("USA","swift", 29) #实例化两个类 >>> b = People("China","wxz", 24) >>> a.addr #这两个类都有一个addr属性,注意addr类变量在类中定义的方法 'Earth' >>> b.addr 'Earth' >>> a.addr = "Moon" #注意这样作只是在实例a中添加了实例属性addr,而不是修改类变量addr。 >>> a.addr #实例a访问的是实例属性中的addr。 'Moon' >>> b.addr #而实例b访问的是类变量addr。所以结果不一样 'Earth' >>> People.addr = "Moon" #修改类变量,这时候实例a仍然访问的是实例属性addr,而实例b访问的是类变量addr。 >>> a.addr 'Moon' >>> b.addr 'Moon' #再实例化一个实例对象c,能够发现c的addr属性已是修改以后的属性。 >>> c = People("UKA", "King",88) >>> c.addr #实例对象c访问的是类变量addr。 'Moon'
在上面的实例中,咱们给实例a添加一个实例属性addr,而这时候类变量也有一个属性addr,那么在访问的时候实例会怎么去调用对应的值呢?
经过以上的例子能够得出以下结论:属性查找,首先查找实例自己是否有对应的属性,若找到则返回结果,中止查找;不然就继续查找类中的属性变量。
在这里实例a由于添加了add实例r属性,所以实例a只会返回实例自己的addr结果;而实例b和实例c,由于自己的没有addr实例属性(构造函数中没有定义),所以会返回类变量addr的值。
类变量是类的各个实例共有的属性。固然这个属性也能够放在构造函数中,在每一个实例初始化的时候,就会自动生成这个属性。
可是上面提到过python会为每一个实例开辟一个内存空间,所以当实例很是巨大的时候,这样作会占用存储空间。采用类变量的形式更节省空间。
封装:
在这个实例中有一个简单的方法就是get_info()。对于一个对象也就是实例来讲,要想获得这个对象的具体信息,只须要调用get_info()这个方法便可,而后就会返回对象的具体信息。可是具体是怎么样获得这些信息的,这个实例是不知道的。这种形式就是封装。把一些功能实现的细节不对外暴露,隐藏起来就是封装。
继承:
class People(object): def __init__(self,name,pos=None): self.name = name self.pos = pos def get_info(self): print("My name is %s, I have not a work" % self.name) class Teacher(People): def __init__(self,name, pos, school): super(Teacher,self).__init__(name, pos) #重写构造方法的两种形式,推荐使用super的形式,构造方法重写时注意参数传递。 # People.__init__(self, name, pos) self.school = school def get_info(self): print("My name is %s, I am a %s" % (self.name, self.pos)) print("The colleage is %s" % self.school) class Student(People): def __init__(self,name,pos, score, course): super(Student, self).__init__(name, pos) self.score = score self.course = course def get_info(self): print("My name is %s, I am a %s" % (self.name, self.pos)) print("My score is %d" % self.score) print("I have learned the %s %s %s" % self.course)
上面定义了一个父类People,两个子类teacher和student,都继承了people。
实例化操做:
a = People("wxz") b = Teacher(name="steve", pos="teacher", school="Peking university") d = Student(name="job", pos="Stuent", score=88, course=("数学","语文","物理")) In [6]: a.get_info() My name is wxz, I have not a work In [7]: b.get_info() My name is steve, I am a teacher The colleage is Peking university In [8]: d.get_info() My name is job, I am a Stuent My score is 88 I have learned the 数学 语文 物理
实例化的每个对象均可以调用get_info()方法,获得其对应的信息。这三个对象是不同的,分别为people, teacher,student对象。
如有一个函数,只要传入对应的对象,而后就能够调用函数获得对应的信息。以下这种形式:
In [9]: def print_info(obj): ##在只要传入对象信息,咱们不知道这个对象是什么类型,可是他依然能够获得对象的信息 ...: obj.get_info() ...: In [10]: print_info(a) My name is wxz, I have not a work In [11]: print_info(b) My name is steve, I am a teacher The colleage is Peking university In [12]: print_info(d) My name is job, I am a Stuent My score is 88 I have learned the 数学 语文 物理
在这个例子中,并不知道a,b,d是什么样的对象,要作的只是把这三个对象传入了print_intfo函数,而后函数会自动返回对应的对象信息。
这里只有一个print_info的接口,可是不一样的对象均可以调用这个接口,这种行为就叫作多态。
多态就是一种接口的多种使用。
下面一个简单的多态实例
list1 Out[22]: ['a', 'f', 'd', 's', 'f', 'a', 's', 'd', 'f'] #列表 tuple1 Out[23]: ('f', 'g', 'a', 'g', 'f', 'd', 'g', 'd', 'f') #元组 len(list1) Out[24]: 9 len(tuple1) Out[25]: 9
对于len()函数来讲并不知道list1是列表,tuple1是元组,len()函数只是接受一个参数对象,而后返回这个参数对象的长度。也能够理解为多态的一种使用。
面向对象的三个基本特征:封装,继承,多态。
面向的对象的属性: