1.面向对象基础
1.1.类
在Python 2及以前的版本中,由任意内置类型派生出的类(只要一个内置类型位于类树的某个位置),都属于“新式类”,都会获得所有“新式类”的特性;反之,即不由任意内置类型派生出的类,则称之为“经典类”。
“新式类”和“经典类”的区分在Python 3之后就已经不存在,在Python 3.x之后的版本,因为所有的类都派生自内置类型object(即使没有显示的继承object类型),即所有的类都是“新式类”。
创建类的语法如下:
class className:
suite
或
class className(base_classes):
suite
如果不写(base_classes)则默认是继承object。
class A:
pass
class B(A):
pass
print(issubclass(A,object))
print(issubclass(B,A))
True
True
1.2.函数和方法
函数定义在类中的话,叫做方法,方法的第一个参数需要绑定到所属的实例上。
class TestA:
def method(self):
print('TestA.method')
def function():
print('function...')
instance = TestA()
instance.method()
TestA.method
self参数并不依赖调用方法的方式,下面这种方式self也是有的。
testmethod=instance.method
testmethod()
TestA.method
实例的特性可以绑定到一个普通函数上,这样就没有self参数了。
instance.method=function
instance.method()
function...
1.3.私有化
如果想要实例中的方法和属性为私有,则可以在方法名前加双下划线__,这样在外部就不可以访问了。
class TestB:
def ___method(self):
print('TestB.method')
__field='a'
instance = TestB()
instance.__method()
instance.__field
运行结果:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
in
4 __field='a'
5 instance = TestB()
----> 6 instance.__method()
7 instance.__field
AttributeError: 'TestB' object has no attribute '__method'
实际在Python内部这类方法和属性,被编译为单下划线和类型名的形式。
print(dir(TestB)[0:2])
['_TestB___method', '_TestB__field']
私有化方法和属性,建议只使用前双划线的情况,不能前后一起使用,一般只有特殊变量才使用前后双下划线。此时的属性和方法并没有被编译成“单下划线和类型名的形式”
class TestC:
__fieldA__='a'
__fieldB__='b'
instance = TestC()
print(instance.__fieldA__)
print(instance.__fieldB__)
a
b
1.4.继承和多态
Python支持多继承,如果继承多个类,那么其寻找方法的方式有:深度优先和广度优先。当类是经典类时,多继承情况下,会按照深度优先方法查找;当类时新式类时,多继承情况下,并非是广度优先,而是C3算法,只是在部分情况下,C3算法的结果恰巧与广度优先的结果相同。
class A(object):
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B):
def test(self):
print('from D')
class E(C):
def test(self):
print('from E')
class F(D,E):
# def test(self):
# print('from F')
pass
f1=F()
f1.test()
from D
只有新式才有这个属性可以查看线性列表,经典类没有这个属性
print(F.__mro__)
运行结果:
(, , , , , , )
新式类继承顺序:F->D->B->E->C->A
经典类继承顺序:F->D->B->A->E->C
Python3中统一都是新式类;Pyhon2中才分新式类与经典类
所有的父类的MRO列表遵循如下原则:子类会先于父类被检查;多个父类会根据它们在列表中的顺序被检查;如果对下一个类存在两个合法的选择,则选择第一个类。
1.5.类与实例
由于Python是动态语言,根据类创建的实例可以任意绑定属性。给实例绑定属性的方法是通过实例变量,或者通过self变量:
class TestD:
def __init__(self):
self.name='A'
d = TestD()
print(d.name)
d.passwd='asw'
print(d.passwd)
A
asw
print(dir(d)[-1:-3:-1])
['passwd', 'name']
定义在方法外部的一般为类属性,而类方法一般第一个参数为cls,并使用@classmethod修饰器。
实例的属性和方法,只有由实例调用
类的属性和方法,则实例和类都能调用
@staticmethod修饰的为静态方法,与类方法区别就是没有参数cls
class TestE:
clasname='B'
def __init__(self):
self.instname='A'
def instmethod(self):
print('instmethod')
@classmethod
def clasmethod(cls):
print('clasmethod')
@staticmethod
def statmetthod():
print('statmetthod')
e = TestE()
print(e.instname)
print(e.instmethod)
print(e.clasname)
print(e.clasmethod)
print('-----------------')
print(TestE.clasmethod)
print(TestE.statmetthod)
运行结果:
A
>
B
>
-----------------
>
类的属性和实例属性类型也可以动态新增
TestE.passwd=1234
print(dir(TestE)[-1:-8:-1])
运行结果:
['statmetthod', 'passwd', 'instmethod', 'clasname', 'clasmethod', '__weakref__', '__subclasshook__']
1.6.初始化
Python新式类中有两个特殊的方法__new__()和__init__(),经典类中无__new__()。
__new__的作用在构造方法__init__建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法__init__负责将类的实例化,而在__init__调用之前,__new__决定是否要使用该__init__方法,因为__new__可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。
__new__方法是在类准备将自身实例化时调用。
__new__方法始终都是类的静态方法,即使没有被加上静态方法装饰器。
__new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由Python解释器自动提供
__new__必须要有返回值,返回实例化出来的实例,这点在自己实现__new__时要特别注意,可以return父类__new__出来的实例,或者直接是object的__new__出来的实例
__init__有一个参数self,就是这个__new__返回的实例,__init__在__new__的基础上可以完成一些其它初始化的动作,__init__不需要返回值
若__new__没有正确返回当前类cls的实例,那__init__是不会被调用的,即使是父类的实例也不行
1.7.子类调用父类的方法
有以下几种方法:
直接写类名调用:parent_class.parent_attribute(self)
用super(type, obj).method(arg)方法调用:super(child_class, child_object).parent_attribute(arg)【不需要写self】
在类定义中调用本类的父类方法,可以直接 super().parent_method(arg) 【个人推崇这种写法】
class A:
def method(self,name):
print('AAAA',name)
class B(A):
def method(self,name):
A.method(self,name)
b = B()
b.method('Me')
AAAA Me
class A:
def method(self,name):
print('AAAA',name)
class B(A):
def method(self,name):
super(B,self).method(name)
b = B()
b.method('Me')
AAAA Me
class A:
def method(self,name):
print('AAAA',name)
class B(A):
def method(self,name):
super().method(name)
b = B()
b.method('Me')
AAAA Me
类方法在子类继承时,参数cls传入的是子类的类,而非父类。
静态方法则没有变化。
class A:
@classmethod
def cm(cls):
print('类方法cm(cls)调用者:', cls.__name__)
@staticmethod
def sm():
print('静态方法sm()被调用')
class B(A):
pass
A.cm()
B.cm()
A.sm()
B.sm()
类方法cm(cls)调用者: A
类方法cm(cls)调用者: B
静态方法sm()被调用
静态方法sm()被调用
更多文章,请关注: