Python 3 中只有新式类,没有旧式类,不需要显示的指定,你定义的类都是新式类
所以,你不可能完全限制其他人无法访问到你的类中方法和特性,所以,Python 并不能实现完全的封装
继承:
将其他类名写在class语句后的圆括号内就表示继承于某类
class 类名(基类名)
语句块
多继承:
多继承的方法很容易,把几个类名写在一起就行了
再说说Python的类属性和实例属性
类属性是属于一个类的变量,就像是C++中类的静态成员变量,你只需将该属性定义在所有方法的作用域外,即为类属性,但一般是紧跟在类名后面,类属性为所有实例所共有,你可以通过 类名.属性 来调用类属性
通过上面的例子我们可以看到,类属性为所有实例和类所共有,通过 类名.类属性 可以更改类属性,并且所有实例的类属性也随之改变,但通过 实例名.类属性 来改变类属性,该实例的该类属性会变为实例属性,而不影响其他实例的类属性,以后通过 类名.类属性 来更改类属性,也不会影响到该实例的这个属性了,因为它变为实例属性啦。(好吧,我承认有点晕o(╯□╰)o)
如果你不知道新式类和旧式类的区别,那么,也不用知道了
定义:
>>> class Nothing:
#定义方法和属性
pass
>>>
类里面用 def 定义方法,它不叫函数,因为每一个方法的第一个参数都是 self,但在调用时我们不必提供,程序会自动将第一个参数绑定到所属的实例上
>>> class Hello:
def greet(self,name):
print ("Hello,"+name)
>>> me = Hello() #要加()不然,不是实例
>>> me.greet('Cheng') #只需第一个参数
Hello,Cheng
>>> class Some:
name = "Jane"
>>> she = Some()
>>> she.name #这里可以访问
'Jane'
>>> class Some:
__name = "Jane"
>>> she = Some()
>>> she.name #这里不可以
Traceback (most recent call last):
File "<pyshell#48>", line 1, in <module>
she.name
AttributeError: 'Some' object has no attribute 'name'
>>> she._Some__name #通过 _类名__方法或特性名,我们又可以访问它
'Jane'
>>> class C:
def __test(self):
print('in C...')
def call(self):
self.__test() #类内访问私有方法和特性
>>> c = C()
>>> c.call()
in C...
所以,你不可能完全限制其他人无法访问到你的类中方法和特性,所以,Python 并不能实现完全的封装
继承:
将其他类名写在class语句后的圆括号内就表示继承于某类
class 类名(基类名)
语句块
>>> class A:
def printA(self):
print("in A...")
>>> class B(A):
def printB(self):
print('in B...')
>>> issubclass(A,B) #A不是B的子类
False
>>> issubclass(B,A) #B是A的子类
True
>>> B.__bases__ #B的基类
(<class '__main__.A'>,)
>>> b = B()
>>> isinstance(b,B) #询问b是否是B的实例
True
>>> b.printA() #访问A中的方法
in A...
多继承:
多继承的方法很容易,把几个类名写在一起就行了
class 类名(基类名1,基类名2,基类名3)
语句块
子类中同名的方法会覆盖基类的方法,方法的调用跟继承的顺序有关,即方法在子类中未找到时,从左到右查找父类中是否包含方法
看下面的例子:
>>> class A:
def test(self):
print("in A...")
>>> class B(A):
def test(self):
print('in B...')
>>> class C(A):
def test(self):
print('in C...')
>>> class D(B,C):
def test(self):
print('in D...')
>>> d = D()
>>> d.test() #如果子类拥有该方法,那直接调用该方法
in D...
>>> class D(B,C): #重定义类D
pass
>>> d = D()
>>> d.test() #B先继承,在B中首先找到该方法,调用B的方法
in B...
>>> class D(C,B): #再次重定义,改变了继承顺序
pass
>>> d = D()
>>> d.test() #这次调用了C的方法
in C...
>>>
当然,如果D、B、C都没有该方法,而A有,那么自然是调用A的方法
>>> hasattr(d,'test') #对象d是否有test方法
True
>>> hasattr(d,'next') #对象d是否有next方法
False
>>> hasattr(d.test,'__call__') #询问d的test方法是否可调用
True
将类实例化时,会创建一个空的类实例,一般的 Python 类的定义中会有一个特殊的方法来初始化,这个方法就是__init__(),当调用了类的实例化方法后,__init__()方法会立刻被这个类的实例调用。所以,__init__()不是构造函数,而是一个普通的方法.
>>> class A:
count = 0;
def __init__(self):
A.count += 1 #每次调用该方法 count 自增 1
def output(self):
print(self.count)
>>> a1 = A()
>>> a1.output()
1
>>> a2 = A()
>>> a2.output()
2
>>> class A:
def __init__(self,name):
self.name = name
>>> a = A('Jane')
再说说Python的类属性和实例属性
类属性是属于一个类的变量,就像是C++中类的静态成员变量,你只需将该属性定义在所有方法的作用域外,即为类属性,但一般是紧跟在类名后面,类属性为所有实例所共有,你可以通过 类名.属性 来调用类属性
>>> class A:
count = 0; #这就是类属性
def __init__(self):
A.count += 1 #每次调用该方法 count 自增 1
def output(self):
print(self.count)
>>> a1 = A()
>>> a1.output()
1
>>> A.count = 0
>>> A.count
0
>>> a1.output()
0
>>> class A:
def __init__(self):
self.num = 1 #添加实例属性num
def again(self,name):
self.name = name #添加实例属性name
>>> a1 = A()
>>> a1.num
1
>>> a1.name #这时实例 a1 中还没有实例属性 name
Traceback (most recent call last):
File "<pyshell#38>", line 1, in <module>
a1.name #这时实例 a1 中还没有实例属性 name
AttributeError: 'A' object has no attribute 'name'
>>> a1.again('Jane')
>>> a1.name #现在有了...
'Jane'
>>> a1.call = '123456' #添加a1的实例属性 call
>>> a1.call
'123456'
>>> class A:
count = 0
def __init__(self):
A.count += 1
def output(self):
print(self.count)
>>> a1 = A()
>>> a2 = A()
>>> a3 = A()
>>> A.count # A的类属性count这时为3
3
>>> A.count = 2 #更改A的类属性为2
>>> a1.count,a2.count, a3.count, A.count #A的所有实例的count也同样改变
(2, 2, 2, 2)
>>> a1.count = 5 #通过A的一个实例a1更改count
>>> a1.count, a2.count, a3.count, A.count #只有a1的count发生改变
(5, 2, 2, 2)
>>> A.count = 4 #再次更改A的类属性为4
>>> a1.count, a2.count, a3.count, A.count #这时a1的count还是保持为5
(5, 4, 4, 4)
通过上面的例子我们可以看到,类属性为所有实例和类所共有,通过 类名.类属性 可以更改类属性,并且所有实例的类属性也随之改变,但通过 实例名.类属性 来改变类属性,该实例的该类属性会变为实例属性,而不影响其他实例的类属性,以后通过 类名.类属性 来更改类属性,也不会影响到该实例的这个属性了,因为它变为实例属性啦。(好吧,我承认有点晕o(╯□╰)o)