关于Python中面向对象
什么是面向对象
这可能对于很多初学者来说是个问题,关于面向对象和面向过程可以说一直是编程界的两大阵营吧,没有好与坏之分,全在于个人见解吧,但是不得不说,现在面向过程更加主流一些吧!
面向对象的语言很多,最典型应该算Java吧!而面向过程的语言也很多,代表应该就是C语言了,但同时,又有许多的语言为了照顾这两方面的人,既支持面向过程,又支持面向对象,而Python就是这种类型。
简单来说,面向过程就是在写代码的时候,注重的是实现目的的过程是什么方式的,这个过程是怎样的,通过什么样的步骤可以解决掉他。而面向对象是对整体的考虑,将万物看作类,不同的物品通过不同的类封装,一个类里面,有类自己的属性,方法等。python支持面向对象和面向过程,一般对与比较小的项目,可以使用面向过程的方法实现比较简单,而大型项目就需要定义不同的类,在每个类里面再进行具体方法的实现。
关于类与类的实例,我举个例子吧,水果和苹果的例子,水果就是一个类,而苹果就是水果的一个实例,我们在吃苹果时说是吃水果,但是我们不能只吃水果,我们吃的,一定是水果的一个实例。请大家仔细品味这句话。
怎样创建一个类?
创建一个类特别简单,具体如下:
class classs_name(object):
pass
这就创建了一个类,只不过没有加上任何属性,方法等。
关于一些重要的方法
关于__init__方法
__init__方法用于进行类的初始化操作。在类创建一个实例后,__init__方法用于对类里面的属性进行初始化,所以说,只要一个类里面有__init__方法,在创建类的实例时,就一定会调用此方法。
关于__new__方法
__new__方法用相当于Java里面的构造器一样,用于创建一个类的实例,他的返回值就是当前类的实例,如果一个类里面没有此方法,就会默认去调用父类的__new__方法,如果父类没有此方法,最终会去调用object类的__new__方法。因为object类是所有类的父类。由于__new__方法返回当前类的实例,而__init__是对当前类的实例进行初始化,所以对__new__的调用会在__init__方法之前。
__init__ 和 __new__ 最主要的区别在于:
1.__init__ 通常用于初始化一个新实例,控制这个初始化的过程,比如添加一些属性, 做一些额外的操作,发生在类实例被创建完以后。它是实例级别的方法。
2.__new__ 通常用于控制生成一个新实例的过程。它是类级别的方法。
举个例子看看:
class test(object):
def __init__(self):
print "__init__ was called "
def __new__(cls):
print "__new__ was called"
return super(test,cls).__new__(cls)
运行结果:
__new__ was called
__init__ was called
但是如果将return语句去掉呢?就是不返回当前类的实例,那么就表示当前实例没有创建成功,那么就没有必要进行类的初始化操作了,看看例子:
class test(object):
def __init__(self):
print "__init__ was called "
def __new__(cls):
print "__new__ was called"
#return super(test,cls).__new__(cls)
运行结果:
__new__ was called
关于__del__方法
如果把__init__方法或__new__方法看作是一个类的构造器的话,那么__del__就被称为类的解构器,他用于删除一个类的实例,下面举个例子:
class test(object):
def __init__(self):
print "__init__ was called"
def __del__(self):
print "__del__ was called"
t=test()
b=test()
t1=t
t2=t
print(id(t))
print(id(t1))
print(id(t2))
print('del t')
del t
print('del t1')
del t1
print('del t2')
del t2
print('del b')
del b
运行结果:
__init__ was called
139872429641488
139872429641488
139872429641488
del t
del t1
del t2
__del__ was called
del b
__del__ was called
继承,封装,多态——面向对象三大特征
继承
python里面,所有的类都默认继承object 类,如果你想继承其他类,也是可以的,将需要的写入类名后面的括号里面就可以了。继承一个类,就会默认继承他的所有非私有属性,关于继承的好处这里不再赘述,关于私有属性,下面会讲。
封装
封装的意思,就是对类的访问进行控制,python里面,类的私有属性通过特殊的属性名来进行控制,类的私有变量名前面要加上两个下划线,而特殊的方法方法名前后都有俩下划线,所以在定义属性名时,不要在定义属性名时前后加上两个下划线,关于类里的特殊方法,可以使用dir(classname)来查看。
多态
当父类定义了和子类同样的方法(方法名相同)那么,在调用此方法时,总会调用子类的方法,也就是说,子类将父类的方法覆盖了,这就是python的多态。
举个例子:
class Animal(object):
def run(self):
print("Animal is running")
class Dog(Animal):
pass
class Cat(Animal):
pass
d=Dog()
c=Cat()
d.run()
c.run()
运行结果:
Animal is running
Animal is running
再看一个例子:
class Animal(object):
def __init__(self):
self.__name='Animal'
self.age=5
class Dog(Animal):
pass
d=Dog()
print(d.age)
print(d.__name)
运行结果:
5
Traceback (most recent call last):
File "class.py", line 9, in <module>
d.__name
AttributeError: 'Dog' object has no attribute '__name'
报出了AttributeError的异常,显示Dog没有__name这个属性。
class Animal(object):
def run(self):
print("Animal is running")
class Dog(Animal):
def run():
print "Dog is running"
class Cat(Animal):
def run():
print "Cat is running"
d=Dog()
c=Cat()
d.run()
c.run()
运行结果:
Dog is running
Cat is running
从结果来看,并没有显示Animal里面的run方法,而是调用了每个子类各自的run方法。
实例属相和类属性
从字面简单来了解,实例属性就是类的实例所拥有的属性,而类属性就是指类所拥有的属性。
class Soft(object):
version=0.1 #创建一个类属性version
s=Soft()
print(Soft.version) # 因为version为类属性,所以应该通过类名点来访问
print(s.version) # 按上面所讲的,类属性通过实例来访问应该是报错的,但是python实现是先在实例属性中检索,然后再到类属性中去检索,所以最终是可以访问到的,并且不会报错。
Soft.version+=1 # 改变类属性的值
print(Soft.version) # 通过类名点访问
print(s.version) # 通过实例来访问
s.version=1.0 # 注意,类属性只能通过类名点访问,此操作是建立了一个名为version的实例属性
print(Soft.version)
print(s.version)
运行结果:
0.1
0.1
1.1
1.1
1.1
1.0