类的定义与使用
Python使用class关键字来定义类,class关键字之后是一个空格,接下来时类的名字,如果派生自其他基类则需要把基类放到一对括号中并使用逗号分隔,然后是一个冒号,最后换行并定义类的内部实现 类的首字母一般要大写
class Car ( object ) :
def infor ( self) :
print ( "这是一个小汽车" )
定义类之后可以用来实例化对象,并可以通过“对象名.成员”的方式来访问其中的数据成员方法。
>> > car= Car( )
>> > car. infor( )
这是一个小汽车
在Python中,可以使用内置函数isinstance()来测试一个对象是否为某个类的实例 或者使用内置type()函数查看对象类型
>> > isinstance ( car, Car)
True
>> > type ( car)
< class '__main__.Car' >
Python提供了一个关键字pass,执行时什么也不会发生,表示空语句,可以使用pass来占位
>> > class Test :
'''这是一个测试'''
pass
>> > Test. __doc__
'这是一个测试'
数据成员与成员方法
私有成员与公有成员
私有成员在类的外部不能直接访问,一般是在类的内部进行访问和操作,或者在类的外部通过调用对象的公有成员方法来访问 而公有成员可以是公开使用的,既可以在类的内部进行访问,也可以在外部程序中使用 在定义类的成员时,如果成员名以两个(或更多)下划线开头但不是以两个(或更多)下划线结束则表示是私有成员,否则就不是私有成员 Python没有对私有成员提供严格的保护机制,通过一种特殊方式“对象名._类名__xxx”也可以在外部程序中访问私有成员,但会破坏类的封装性,不建议这样做
>> > class A :
def __init__ ( self, value1= 0 , value2= 0 ) :
self. _value1= value1
self. __value2= value2
def setValue ( self, value1, value2) :
self. _value1= value1
sele. __value2= value2
def show ( self) :
print ( self. _value1)
print ( self. __value2)
>> > a= A( )
>> > a. _value1
0
>> > a. _A__value2
0
圆点“.”是成员访问运算符,可以用来访问命名空间、模块或对象中的成员 在对象或类名后面加上一个圆点“.”,都会自动列出其所有公开成员 如果在圆点“.”后面再加一个下划线,则会列出该对象或类的所有成员,包括私有成员 也可以使用内置函数dir()来查看指定对象、模块或命名空间的所有成员
成员名定义的特殊性
_xxx:以一个下划线开头,保护成员,只有类对象和子类对象可以访问这些成员,在类的外部一般不建议直接访问,在模块中使用一个或多个下划线开头的成员不能用“from module import*”导入,除非在模块中使用__all__变量明确指明这样的成员可以被导入 _xxx _ :前后两个下划线,系统定义的特殊成员 __xxx:以两个或更多下划线开头但不以两个或更多下划线结束,表示私有成员,一般只有类对象自己能访问,子类对象也不能访问该成员,但在对象外部可以通过“对象名._类名__xxx”这样的特殊方式来访问
数据成员
数据成员可以分为两类:属于对象的数据成员和属于类的数据成员 属于对象的数据成员一般在构造方法__init__()中定义,当然也可以在其他成员方法中定义,在定义和在实例方法中访问数据成员时以self作为前缀,同一个类的不同对象(实例)的数据成员之间互不影响 属于类的数据成员是该类所有对象共享的,不属于任何一个对象 在主程序中或类的外部,对象数据成员属于实例(对象),只能通过对象名访问 而数据成员属于类,可以通过类名或对象名访问
>> > class Demo ( object ) :
total= 0
def __new__ ( cls, * args, ** kwargs) :
if cls. total>= 2 :
raise Exception( '最多只能创建2个对象' )
else :
return object . __new__( cls)
def __init__ ( self) :
Demo. total= Demo. total+ 1
>> > t1= Demo( )
>> > t1
< __main__. Demo object at 0x0000000F646A4748 >
>> > t2= Demo( )
>> > t3= Demo( )
Traceback ( most recent call last) :
File "<pyshell#40>" , line 1 , in < module>
t3= Demo( )
File "<pyshell#36>" , line 5 , in __new__
raise Exception( '最多只能创建2个对象' )
Exception: 最多只能创建2 个对象
_new _():类的静态方法,用于确定是否要创建对象 _init _():构造方法,创建对象时自动调用 _del _():析构方法,释放对象时自动调用
成员方法、类方法、静态方法、抽象方法
在面向对象程序设计中,函数和方法这两个概念是有本质区别的 方法一般指与特定实例绑定的函数,通过对象调用方法是,对象本身将被作为第一个参数自动传递过去 普通函数不具备这个特点 Python类的成员方法大致可以分为公有方法、私有方法、静态方法、类方法和抽象方法 公有方法、私有方法和抽象方法一般是指属于对象的实例方法 私有方法的名字以两个或更多的下划线开始 抽象方法一般定义在抽象类中并且要求派生类必须重新实现 每个对象都有自己的公有方法和私有方法,在这两类方法中都可以访问属于类和对象的成员 公有方法通过对象名直接调用 私有方法不能通过对象名直接调用,只能在其他实例方法中通过前缀self进行调用或在外部通过特殊的形式来调用
实例方法
所有实例方法(包括公有方法、私有方法、抽象方法和某些特殊方法)都必须至少有一个名为self的参数,并且必须是方法的第一个形参(如果有多个形参),self参数代表当前对象 在实例方法 中访问实例成员 时需要以self为前缀 但在外部通过对象名 调用对象方法时并不需要 传递这个参数 如果在外部通过类名 调用属于对象的公有方法 ,需要显示 为该方法的self参数传递一个对象名 ,用来明确指定访问哪个对象的成员
静态方法与类方法
静态方法与类方法都可以通过类名和对象名调用,但不能直接访问属于对象的成员,只能访问属于类的成员 类方法一般以cls作为第一个参数表示该类自身,在调用类方法时不需要为该参数传递值 静态方法可以不接受任何参数
>> > class Root :
__total= 0
def __init__ ( self, v) :
self. __value= v
Root. __total += 1
def show ( self) :
print ( 'self.__value:' , self. __value)
print ( 'Root.__total:' , Root. __total)
@classmethod
def classShowTotal ( cls) :
print ( cls. __total)
@staticmethod
def staticShowTotal ( ) :
print ( Root. __total)
>> > r= Root( 3 )
>> > r. classShowTotal( )
1
>> > r. staticShowTotal( )
1
>> > rr= Root( 5 )
>> > Root. classShowTotal( )
2
>> > Root. staticShowTotal( )
2
>> > Root. show( r)
self. __value: 3
Root. __total: 2
>> >
抽象方法
抽象方法一般在抽象类中定义,并且要求在派生类中必须重新实现,否则不允许派生类创建实例
>> > import abc
>> > class Foo ( metaclass= abc. ABCMeta) :
def f1 ( self) :
print ( 123 )
def f2 ( self) :
print ( 456 )
@ abc. abstractmethod
def f3 ( self) :
raise Exception( '你必须重写这个方法' )
>> > class Bar ( Foo) :
def f3 ( self) :
print ( 3333 )
>> > b= Bar( )
>> > b. f3( )
3333
属性
公开数据成员可以在外部随意访问和修改,数据很容易被破坏,而且不能保证合法性 解决这类问题是定义私有成员,然后设计公开的成员方法来提供对私有数据成员的读取和修改操作 属性是一种特殊形式的成员方法,结合了公开数据成员和成员方法的优点,既可以像成员方法那样对值进行必要的检查,又可以像数据成员一样灵活的访问 可以将属性设置为可读、可修改、可删除
>> > class Text :
def __init__ ( self, value) :
self. __value= value
def __get ( self) :
return self. __value
def __set ( self, v) :
self. __value= v
def __del ( self) :
del self. __value
value= property ( __get, __set, __del)
def show ( self) :
print ( self. __value)
>> > t= Text( 3 )
>> > t. show( )
3
>> > t. value= 5
>> > t. show( )
5
>> > del t. value
>> > t. value
Traceback ( most recent call last) :
File "<pyshell#104>" , line 1 , in < module>
t. value
File "<pyshell#96>" , line 5 , in __get
return self. __value
AttributeError: 'Text' object has no attribute '_Text__value'
>> > t. value= 1
>> > t. show( )
1
>> > t. value
1
类与对象的动态性、混入机制
在Python中可以动态的为自定义类和对象增加数据成员和成员方法的行为成为混入机制
>> > import types
>> > class Car ( object ) :
price= 1000
def __init__ ( self, c) :
self. color= c
>> > car1= Car( "Red" )
>> > print ( car1. color, Car. price)
Red 1000
>> > Car. price= 100000
>> > Car. name= 'QQ'
>> > car1. color= 'Yellow'
>> > print ( car1. color, Car. price, Car. name)
Yellow 100000 QQ
>> > def setSpeed ( self, s) :
self. speed= s
>> > car1. setSpeed= types. MethodType( setSpeed, car1)
>> > car1. setSpeed( 50 )
>> > print ( car1. speed)
50
继承和多态
继承
设计一个新类是,如果可以继承一个已有的类进行二次开发,可以大大减少工作量 在继承关系中,有已经设计好的类称为父类或基类 新设计的类称为子类或派生类 派生类可以继承父类的公有成员,但是不能继承其私有成员 如果需要在派生类中调用基类的方法,可以使用内置函数super()或者通过“基类名.方法名()”的方法实现
>> > class Person ( object ) :
def __init__ ( self, name= '' , age= 20 , sex= 'man' ) :
self. setName( name)
self. setAge( age)
self. setSex( sex)
def setName ( self, name) :
if not isinstance ( name, str ) :
raise Exception( '名字必须是字符串' )
self. __name= name
def setAge ( self, age) :
if type ( age) != int :
raise Exception( '年龄必须是数字' )
self. __age= age
def setSex ( self, sex) :
if sex not in ( 'man' , 'woman' ) :
raise Exception( '性别必须是"man"或"woman"' )
self. __sex= sex
def show ( self) :
print ( self. __name, self. __age, self. __sex, sep= '\n' )
>> > class Teacher ( Person) :
def __init__ ( self, name= ' ' , age= 30 , sex= 'man' , department= 'computer' ) :
super ( Teacher, self) . __init__( name, age, sex)
Person. __init__( self, name, age, sex)
self. setDepartment( department)
def setDepartment ( self, department) :
if type ( department) != str :
raise Exception( 'department必须是字符串' )
self. __department= department
def show ( self) :
super ( Teacher, self) . show( )
print ( self. __department)
>> > if __name__== '__main__' :
zhangsan= Person( 'zhang san' , 19 , 'man' )
zhangsan. show( )
print ( '=' * 30 )
lisi= Teacher( 'li si' , 32 , 'man' , 'Math' )
lisi. show( )
lisi. setAge( 40 )
lisi. show( )
zhang san
19
man
== == == == == == == == == == == == == == ==
li si
32
man
Math
li si
40
man
Math
>> >
多态
多态指基类的同一个方法在不同派生类对象中具有不同的表现和行为 派生类继承了基类的行为和属性之后,还会增加某些特定的行为和属性,同时还可能对继承来的某些行为进行一定的改变
>> > class Animal ( object ) :
def show ( self) :
print ( '我是一只动物' )
>> > class Cat ( Animal) :
def show ( self) :
print ( '我是一只猫' )
>> > class Dog ( Animal) :
def show ( self) :
print ( '我是一只狗' )
>> > class Test2 ( Animal) :
pass
>> > x= [ item( ) for item in ( Animal, Cat, Dog, Test2) ]
>> > for item in x:
item. show( )
我是一只动物
我是一只猫
我是一只狗
我是一只动物
>> >