学习《Python程序设计》董付国著
面向对象程序设计
面向对象程序设计的一条基本原则是:
程序由多个能够起到子程序作用的单元或对象组合而成,这大大降低了软件开发难度,是编程就像搭积木一样简单。
类的定义与使用
class Student: #类默认继承于object,等价于class Car(object):
def show(self):
print("I am a student...")
>>> student = Student()
>>> student.show()
I am a student...
方法说明
类的所有实例方法的第一个形参必须是所谓的self(可变),self参数代表将来要创建的对象本身;
在类的实例方法中访问实例属性时需要以self为前缀;
调用实例方法时不需要传递这个参数。
属性说明
一是实例属性;二是类属性。
实例属性,一般是指在构造函数init()中定义的,定义时以self作为前缀;
类属性,是在类中所有方法之外定义的数据成员。
Python的动态性是,可以动态地为类和对象增加成员。
>>> stu = Student()
>>> stu.show()
I am a student...
>>> stu.name = "周周" #为本对象动态增加属性,但对其他对象不起作用
>>> print(stu.name)
周周
>>> stu2 = Student()
>>> stu2.name
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
stu2.name
AttributeError: 'Student' object has no attribute 'name'
小话下划线
如果属性名以两个下划线“__”开头,则是私有属性,否则为公有属性。
Python中,在类和模块中,以下划线开头的变量名有特殊的含义。
用下划线作为变量前缀和后缀来表示类的特殊成员。
_attr:表示保护变量,不能用"from module import *"导入,只有类对象和子类对象能访问这些变量;
__attr__:系统定义的特殊成员;
__attr:类中的私有成员,只有类对象自己能访问,子类对象也不能直接访问但可以通过父类的公有方法间接访问。
但在对象外部可以通过特殊方式访问,如"对象名._类名__attr",所以Python中不存在真正意义上的私有成员。
Python支持一种特殊的方式从外部直接访问类的私有成员,但不推荐。
另外,在IDLE交互模式下,一个下划线”_”表示解释器中最后一次显示的内容或最后一次语句正确执行的输出结果。
>>> "test" + "下划线的作用"
'test下划线的作用'
>>> _
'test下划线的作用'
类的方法
- 公有方法
- 私有方法
- 静态方法
- 类方法
静态方法和类方法都可以通过类名和对象调用,但是不能访问属于对象的成员,只能访问属于类的成员。
class Person:
count = 0
"""构造方法"""
def __init__(self,name='周周',age=22,gender='male'):
Person.count += 1
self.__ID = Person.count
self.__name = name
self.__age = age
self.__gender = gender
"""展示个人信息"""
def tostring(self):
info = 'ID是' + str(self.__ID) + '\n' + \
'name是' + self.__name + '\n' + \
'age是' + str(self.__age) + '\n' + \
'gender是' + self.__gender
return info
>>> p1 = Person()
>>> p1.tostring()
'ID是1\nname是周周\nage是22\ngender是male'
>>> print(p1.tostring())
ID是1
name是周周
age是22
gender是male
>>> p2 = Person('小周',12,'male')
>>> print(p2.tostring())
ID是2
name是小周
age是12
gender是male
类的属性
如下面代码所示,如果设置属性为只读,则无法修改它的值,也无法为对象增加与属性同名的的新成员属性,同时也无法删除对象属性。
设置类的只读属性,不可以更改和删除
class TestAttr:
def __init__(self,ID):
self.__ID = ID
@property
def ID(self): #只读,无法修改__ID属性值
return self.__ID
>>> testAttr = TestAttr('1001')
>>> testAttr.ID
'1001'
>>> testAttr._TestAttr__ID
'1001'
>>> testAttr.ID = '1002'
Traceback (most recent call last):
File "<pyshell#78>", line 1, in <module>
testAttr.ID = '1002'
AttributeError: can't set attribute
>>> testAttr.name = '小周' #为本对象动态增加属性,但对其他对象不起作用
>>> testAttr.name
'小周'
>>> del testAttr.name #把该对象的某一属性删除
>>> del testAttr.ID #无法删除只读属性
Traceback (most recent call last):
File "<pyshell#83>", line 1, in <module>
del testAttr.ID
AttributeError: can't delete attribute
设置类的只读属性,可以更改但不可删除
class TestAttr:
def __init__(self,ID):
self.__ID = ID
@property
def ID(self): #只读,无法修改__ID属性值
return self.__ID
def __get(self): #是私有的getter方法
return self.__ID
def __set(self,id):
self.__ID = id
ID = property(__get,__set) #该“只读属性”既可以读取也可以修改,但不可以删除
>>> testAttr = TestAttr('1003')
>>> testAttr.ID #读取属性值
'1003'
>>> testAttr.ID = '1004' #修改"只读属性"的属性值
>>> testAttr.ID
'1004'
>>> del testAttr.ID
Traceback (most recent call last):
File "<pyshell#89>", line 1, in <module>
del testAttr.ID
AttributeError: can't delete attribute
设置类的只读属性,可以更改和删除
class TestAttr:
def __init__(self,ID):
self.__ID = ID
@property
def ID(self): #只读,无法修改__ID属性值
return self.__ID
def __get(self): #是私有的getter方法
return self.__ID
def __set(self,id):
self.__ID = id
def __del(self):
del self.__ID
ID = property(__get,__set,__del) #该“只读属性”既可以读取也可以修改,但不可以删除
>>> testAttr = TestAttr('1005')
>>> testAttr.ID
'1005'
>>>
>>> testAttr.ID = '1006'
>>> testAttr.ID
'1006'
>>> del testAttr.ID
>>> testAttr.ID
Traceback (most recent call last):
File "<pyshell#96>", line 1, in <module>
testAttr.ID
File "E:/Codes/pythonCodes/classtest.py", line 39, in __get
return self.__ID
AttributeError: 'TestAttr' object has no attribute '_TestAttr__ID'
类的特殊方法
__init__() 构造函数
__del__() 析构函数,一般用来释放对象占用的资源,在Python删除对象和回收对象空间时自动执行。
...
类继承
Python支持多重继承,如果多个父类中有相同的方法名,而在子类中使用时没有指定父类名,则Python解释器将从左向右按顺序进行搜索。
父类Person
class Person(object):
def __init__(self, name = '', age = 22, gender = 'male'):
self.setName(name)
self.setAge(age)
self.setGender(gender)
def setName(self, name):
self.__name = name
def setAge(self, age):
self.__age = age
def setGender(self, gender):
self.__gender = gender
def tostring(self):
info = '姓名是:' + self.__name + '\n' + \
'年龄是:' + str(self.__age) + '\n' + \
'性别是:' + self.__gender
print(info)
>>> p = Person('小周')
>>> p.tostring()
姓名是:小周
年龄是:22
性别是:male
子类Student
class Student(Person): #继承Person类
def __init__(self, name = '', age = 22, gender = 'male', department = 'sesc'):
#使用super()调用父类的构造方法,来初始化成员变量
super(Student, self).__init__(name, age, gender)
#Person.__init__(self,name,age,gender)
self.setDepartment(department)
def setDepartment(self, department):
self.__department = department
def tostring(self): #覆盖父类的tostring方法
super(Student,self).tostring()
print('学院是:'+self.__department)
if __name__ == '__main__':
"""测试父类Person"""
per = Person('小周')
per.tostring()
print('---------------------------')
""""测试子类Student"""
stu = Student("周周同学")
stu.tostring()
姓名是:小周
年龄是:22
性别是:male
---------------------------
姓名是:周周同学
年龄是:22
性别是:male
学院是:sesc
子类调用父类的方法的两种方式
super(SubClassName,self).fooFuncName(parameters...) #前有实参self,后面不需要传递self实参
FooClassName.fooFuncName(self,parameters...) #实参需要self
super(Student, self).__init__(name, age, gender)
Person.__init__(self,name,age,gender)