转:Python中的类

 转贴自:http://www.xwy2.com/article.asp?id=119

原作者:Loong Tsui

 

定义


Python 的 Class 比较特别,和我们习惯的静态语言类型定义有很大区别。
1. 使用一个名为 __init__ 的方法来完成初始化。
2. 使用一个名为 __del__ 的方法来完成类似析购操作。
3. 所有的实例方法都拥有一个 self 参数来传递当前实例,类似于 this。
4. 可以使用 __class__ 来访问类型成员。

   1 >>>   class  MyClass:  
   
2 .    def   __init__ (self):  
   
3 .      print   " initialize.... "   
   
4 .    def  Foo(self):  
   
5 .      print  id(self)  
   
6 .   
   
7 .       
   
8 >>>  a  =  MyClass()  
   
9 . initialize....  
  
10 >>>  a.Foo()  
  
11 14412576   
  
12 >>>  id(a)  
  
13 14412576   

Class 有一些特殊的属性,便于我们获得一些额外的信息。

    1 .                              
   
2 >>>   class  MyClass(object):  
   
3 .    """ This is MyClass's Docoment """   
   
4 .    def   __init__ (self):  
   
5 .     self.i  =   1234   
   
6 .   
   
7 .       
   
8 >>>  MyClass. __doc__   #  类型帮助信息  
    9 " This is MyClass's Docoment "" This is MyClass's Docoment "   
  
10 >>>  MyClass. __name__   #  类型名称  
   11 ' MyClass '   
  
12 >>>  MyClass. __module__   #  类型所在模块  
   13 ' __main__ '   
  
14 >>>  MyClass. __bases__   #  类型所继承的基类(Python 支持多继承)  
   15 . ( < type  ' object ' > ,)  
  
16 >>>  MyClass. __dict__   #  类型字典,存储所有类型成员信息  
   17 < dictproxy object at  0x00DC1AD0 >   
  
18 >>>   # 以下是实例拥有的属性  
   19 >>>  MyClass(). __class__   #  实例的类型  
   20 < class   ' __main__.MyClass ' >   
  
21 >>>  MyClass(). __module__   #  实例类型所在模块  
   22 ' __main__ '   
  
23 >>>  MyClass(). __dict__   #  对象字典,存储所有实例成员信息  
   24 . { ' i ' 1234 }  
  
25 >>>    

继承


Python 支持多继承,但有几点需要注意:

1. 基类 __init__ / __del__ 需显示调用。
2. 继承方法的调用和基类声明顺序有关。


   
1 >>>   class  Base1:  
   
2 .    def   __init__ (self):  
   
3 .      print   " Base1 "   
   
4 .    def  test(self):  
   
5 .      print   " Base1 test... "   
   
6 .   
   
7 .       
   
8 >>>   class  Base2:  
   
9 .    def   __init__ (self):  
  
10 .      print   " Base2 "   
  
11 .    def  test(self):  
  
12 .      print   " Base2 test... "   
  
13 .   
  
14 .       
  
15 >>>   class  MyClass(Base2,Base1):  
  
16 .    def   __init__ (self):  
  
17 .     Base1. __init__ (self)  
  
18 .     Base2. __init__ (self)  
  
19 .      print   " MyClass "   
  
20 .   
  
21 .       
  
22 >>>  a  =  MyClass()  
  
23 . Base1  
  
24 . Base2  
  
25 . MyClass  
  
26 >>>  a.test()  
  
27 . Base2 test...  
  
28 >>>   #  下面把 Base1 放在前面  
   29 >>>   class  MyClass(Base1,Base2):  
  
30 .    def   __init__ (self):  
  
31 .     Base1. __init__ (self)  
  
32 .     Base2. __init__ (self)  
  
33 .      print   " MyClass "   
  
34 .   
  
35 .       
  
36 >>>  a  =  MyClass()  
  
37 . Base1  
  
38 . Base2  
  
39 . MyClass  
  
40 >>>  a.test()  
  
41 . Base1 test...  
  
42 >>>    

成员


Python Class 同样包含类型和实例两种成员。


   
1 >>>   class  Class1:  
   
2 .   i  =   123   #  类成员  
    3 .    def   __init__ (self):  
   
4 .     self.i  =   100   #  实例成员  
    5 .   
   
6 .       
   
7 >>>   print  Class1.i  
   
8 123   
   
9 >>>   print  Class1().i  
  
10 100   
  
11 >>>    

有几个很 "特殊" 的 "规则" 需要注意。

(1) 我们可以通过实例引用访问类型成员。因此下面的例子中 self.i 实际指向 Class1.i,直到我们为实例新增了一个成员 i。


   
1 >>>   class  Class1:  
   
2 .   i  =   123   
   
3 .    def   __init__ (self):  
   
4 .      print  self.i  
   
5 .      print  hex(id(self.i))  
   
6 .   
   
7 .       
   
8 >>>  hex(id(Class1.i))  #  显示 Class1.i 的地址  
    9 ' 0xab5860 '   
  
10 >>>  a  =  Class1()  #  创建 Class1 实例,我们会发现 self.i 实际指向 Class1.i  
   11 123   
  
12 0xab5860   
  
13 >>>  Class1. __dict__   #  显示 Class1 成员  
   14 . { ' i ' 123 ' __module__ ' ' __main__ ' ' __doc__ ' : None,  ' __init__ ' < function  __init__  at  0x012911B0 > }  
  
15 >>>  a. __dict__   #  显示实例成员  
   16 . {}  
  
17 >>>  a.i  =   100   #  为实例新增加一个成员i  
   18 >>>  hex(id(a.i))  #  显示新成员i的地址  
   19 ' 0xab5974 '   
  
20 >>>  a. __dict__   #  显示实例成员  
   21 . { ' i ' 100 }  
  
22 >>>    

(2) 调用类型内部方法,需要省略 self 参数。



   
1 >>>   class  Class1:  
   
2 .    __i   =   123   
   
3 .    def   __init__ (self):  
   
4 .     self. __x   =  0  
   
5 .    def   __test (self):  
   
6 .      print  id(self)  
   
7 .   
   
8 .       
   
9 >>>  Class1.i  
  
10 .   
  
11 . Traceback (most recent call last): 
  
12 .   File  " <pyshell#203> " , line  1 in   < module >  
  
13 .     Class1.i 
  
14 . AttributeError:  class  Class1 has no attribute  ' i '   
  
15 >>>  Class1(). __x   
  
16 .   
  
17 . Traceback (most recent call last): 
  
18 .   File  " <pyshell#204> " , line  1 in   < module >  
  
19 .     Class1(). __x  
  
20 . AttributeError: Class1 instance has no attribute  ' __x '   
  
21 >>>  Class1(). __test ()  
  
22 .   
  
23 . Traceback (most recent call last): 
  
24 .   File  " <pyshell#205> " , line  1 in   < module >  
  
25 .     Class1(). __test () 
  
26 . AttributeError: Class1 instance has no attribute  ' __test '   
  
27 >>>    

事实上这只是一种规则,并不是编译器上的限制。我们依然可以用特殊的语法来访问私有成员。

    1 >>>  Class1._Class1__i  
   
2 123   
   
3 >>>  a  =  Class1()  
   
4 >>>  a._Class1__x  
   
5 . 0  
   
6 >>>  a._Class1__test()  
   
7 14432256   
   
8 >>>    

除了静态(类型)字段,我们还可以定义静态方法。


   
1 >>>   class  Class1:  
   
2 .   @staticmethod  
   
3 .    def  test():  
   
4 .      print   " In Static method... "   
   
5 .   
   
6 .       
   
7 >>>  Class1.test()  
   
8 . In Static method...  
   
9 >>>    

从设计的角度,或许更希望用属性(property)来代替字段(field)。


   
1 >>>   class  Class1:  
   
2 .    def   __init__ (self):  
   
3 .     self. __i   =   1234   
   
4 .    def  getI(self):  return  self. __i   
   
5 .    def  setI(self, value): self. __i   =  value  
   
6 .    def  delI(self):  del  self. __i   
   
7 .   I  =  property(getI, setI, delI,  " Property I " )  
   
8 .   
   
9 .     
  
10 >>>  a  =  Class1()  
  
11 >>>  a.I  
  
12 1234   
  
13 >>>  a.I  =   1000   
  
14 >>>  a.I  
  
15 1000   
  
16 >>>  

如果只是 readonly property,还可以用另外一种方式。


   
1 >>>   class  Class1:  
   
2 .    def   __init__ (self):  
   
3 .     self. __i   =   1234   
   
4 .   @property  
   
5 .    def  I(self):  
   
6 .      return  self. __i   
   
7 .   
   
8 .     
   
9 >>>  a  =  Class1()  
  
10 >>>  a.I  
  
11 1234   
  
12 >>>    

用 __getitem__ 和 __setitem__ 可以实现 C# 索引器的功能。


   
1 >>>   class  Class1:  
   
2 .    def   __init__ (self):  
   
3 .     self. __x   =  [ " a " " b " " c " ]  
   
4 .    def   __getitem__ (self, key):  
   
5 .      return  self. __x [key]  
   
6 .    def   __setitem__ (self, key, value):  
   
7 .     self. __x [key]  =  value  
   
8 .   
   
9 .       
  
10 >>>  a  =  Class1()  
  
11 >>>  a[ 1 ]  
  
12 ' b '   
  
13 >>>  a[ 1 =   " xxx "   
  
14 >>>  a[ 1 ]  
  
15 ' xxx '   
  
16 >>>   

重载


Python 支持一些特殊方法和运算符重载。


   
1 >>>   class  Class1:  
   
2 .    def   __init__ (self):  
   
3 .     self.i  =  0  
   
4 .    def   __str__ (self):  
   
5 .      return   " id=%i " % (id(self))  
   
6 .    def   __add__ (self, other):  
   
7 .      return  self.i  +  other.i  
   
8 .   
   
9 .     
  
10 >>>  a  =  Class1()  
  
11 >>>  a.i  =   10   
  
12 >>>  str(a)  
  
13 ' id=19481664 '   
  
14 >>>  b  =  Class1()  
  
15 >>>  b.i  =   20   
  
16 >>>  a  +  b  
  
17 30   
  
18 >>>    

 通过重载 "__eq__",我们可以改变 "==" 运算符的行为。


   
1 >>>   class  Class1:  
   
2 .    pass   
   
3 .   
   
4 >>>  a  =  Class1()  
   
5 >>>  b  =  Class1()  
   
6 >>>  a  == b  
   
7 . False  
   
8 >>>   #  实现操作符__eq__重载  
    9 >>>   class  Class1:  
  
10 .    def   __eq__ (self, other):  
  
11 .      return  True  
  
12 .   
  
13 .     
  
14 >>>  a  =  Class1()  
  
15 >>>  b  =  Class1()  
  
16 >>>  a  ==  b  
  
17 . True  
  
18 >>>   

Open Class



这是个有争议的话题。在 Python 中,我们随时可以给类型或对象添加新的成员。

1. 添加字段

    1 >>>   class  Class1:  
   
2 .    pass   
   
3 .   
   
4 >>>  a  =  Class1()  
   
5 >>>  a.x  =   10   
   
6 >>>  a.x  
   
7 10   
   
8 >>>  dir(a)  
   
9 . [ ' __doc__ ' ' __module__ ' ' x ' ]  
  
10 >>>  b  =  Class1()  
  
11 >>>  dir(b)  
  
12 . [ ' __doc__ ' ' __module__ ' ]  
  
13 >>>   del  a.x  
  
14 >>>  dir(a)  
  
15 . [ ' __doc__ ' ' __module__ ' ]  
  
16 >>>  dir(Class1)  
  
17 . [ ' __doc__ ' ' __module__ ' ]  
  
18 >>>  Class1.x  =   100   
  
19 >>>  Class1.x  
  
20 100   
  
21 >>>  dir(Class1)  
  
22 . [ ' __doc__ ' ' __module__ ' ' x ' ]  
  
23 >>>    

2. 添加方法


   
1 >>>   class  Class1:  
   
2 .    pass   
   
3 .   
   
4 >>>   def  test():  
   
5 .    print   " test... "   
   
6 .   
   
7 .     
   
8 >>>   def  hello(self):  
   
9 .    print   " hello  " ,id(self)  
  
10 .   
  
11 .     
  
12 >>>  Class1.test  =  test  
  
13 >>>  a  =  Class1()  
  
14 >>>  dir(a)  
  
15 . [ ' __doc__ ' ' __module__ ' ' test ' ]  
  
16 >>>  b  =  Class1()  
  
17 >>>  a.hello  =  hello  
  
18 >>>  dir(a)  
  
19 . [ ' __doc__ ' ' __module__ ' ' hello ' ' test ' ]  
  
20 >>>  a.hello()  
  
21 .   
  
22 . Traceback (most recent call last): 
  
23 .   File  " <pyshell#340> " , line  1 in   < module >  
  
24 .     a.hello() 
  
25 . TypeError: hello() takes exactly  1  argument (0 given)  
  
26 >>>  a.hello(a)  
  
27 . hello   19474632   
  
28 >>>  a.hello(b)  
  
29 . hello   19481584   
  
30 >>>  dir(b)  
  
31 . [ ' __doc__ ' ' __module__ ' ' test ' ]  
  
32 >>>  b.test()  
  
33 .   
  
34 . Traceback (most recent call last): 
  
35 .   File  " <pyshell#344> " , line  1 in   < module >  
  
36 .     b.test() 
  
37 . TypeError: test() takes no arguments ( 1  given)  
  
38 >>>    

3. 改变现有方法


   
1 >>>   class  Class1:  
   
2 .    def  test(self):  
   
3 .      print   " a "   
   
4 .   
   
5 .       
   
6 >>>   def  test(self):  
   
7 .    print   " b "   
   
8 .   
   
9 .     
  
10 >>>  Class1.test  =  test  
  
11 >>>  Class1().test()  
  
12 . b  
  
13 >>>    

另外,有几个内建函数方便我们在运行期进行操作。


   
1 >>>  hasattr(a,  " x " )  
   
2 . False  
   
3 >>>  a.x  =   10   
   
4 >>>  getattr(a,  " x " )  
   
5 10   
   
6 >>>  setattr(a,  " b " 1234 )  
   
7 >>>  a.b  
   
8 1234   
   
9 >>>   

Python Open Class 是如何实现的呢?我们看一下下面的代码。


   
1 >>>   class  Class1:  
   
2 .    pass   
   
3 .   
   
4 >>>  a  =  Class1()  
   
5 >>>  a. __dict__   
   
6 . {}  
   
7 >>>  a.x  =   123   
   
8 >>>  a. __dict__   
   
9 . { ' x ' 123 }  
  
10 >>>  a.test  =   lambda  i: i * 10   
  
11 >>>  a.test( 1 )  
  
12 10   
  
13 >>>  a. __dict__   
  
14 . { ' test ' < function  < lambda >  at  0x012912F0 > ' x ' 123 }  
  
15 >>>    

原来,Python Class 对象或类型通过内置成员 __dict__ 来存储成员信息。

我们还可以通过重载 __getattr__ 和 __setattr__ 来拦截对成员的访问,需要注意的是 __getattr__ 只有在访问不存在的成员时才会被调用。


   
1 >>>   class  Class1:  
   
2 .    def   __getattr__ (self, name):  
   
3 .      print   " __getattr__ " , name  
   
4 .      return  None  
   
5 .    def   __setattr__ (self, name, value):  
   
6 .      print   " __setattr__ " , name, value  
   
7 .     self. __dict__ [name]  =  value  
   
8 .   
   
9 .       
  
10 >>>  a  =  Class1()  
  
11 >>>  a.x  
  
12 __getattr__  x  
  
13 >>>  a.x  =   123   
  
14 __setattr__  x  123   
  
15 >>>  a.x  
  
16 123   
  
17 >>>    

如果类型继承自 object,我们可以使用 __getattribute__ 来拦截所有(包括不存在的成员)的获取操作。
注意在 __getattribute__ 中不要使用 "return self.__dict__[name]" 来返回结果,因为在访问 "self.__dict__" 时同样会被 __getattribute__ 拦截,从而造成无限递归形成死循环。


   
1 >>>   class  Class1(object):  
   
2 .    def   __getattribute__ (self, name):  
   
3 .      print   " __getattribute " , name  
   
4 .      return  object. __getattribute__ (self, name)  
   
5 .   
   
6 .     
   
7 >>>  a  =  Class1()  
   
8 >>>  a.x  
   
9 __getattribute  x  
  
10 .   
  
11 . Traceback (most recent call last): 
  
12 .   File  " <pyshell#396> " , line  1 in   < module >  
  
13 .     a.x 
  
14 .   File  " <pyshell#394> " , line  4 in   __getattribute__  
  
15 .      return  object. __getattribute__ (self, name) 
  
16 . AttributeError:  ' Class1 '  object has no attribute  ' x '   
  
17 >>>  a.x  =   123   
  
18 >>>  a.x  
  
19 __getattribute  x  
  
20 123   
  
21 >>>    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值