面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行, 面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度
面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
在Python中, 所有数据类型都可以视为对象, 同时也可以自定义对象. 自定义的对象类型就是面向对象中的类的概念.
面向过程处理学生信息打印名字和成绩的方法:
std1 = { 'name': 'Michael', 'score': 98 }
std2 = { 'name': 'Bob', 'score': 81 }
def print_score(std):
print('%s: %s' % (std['name'], std['score']))
而面向对象的处理是将学生形成对象, 名字和成绩都是它的成员变量:
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
def print_score(self):
print('%s: %s' % (self.name, self.score))
给对象发消息实际上就是调用对象的关联函数, 也就是方法(Method).
上述的学生对象调用方法是
bart = Student('Bart Simpson', 59)
lisa = Student('Lisa Simpson', 87)
bart.print_score()
lisa.print_score()
类(Class)的个例就是实例(Instance), 面向对象有三个特点: 数据封装, 继承 和多态.
1 类和实例
定义类:
class 类名(object):
类体
类名通常是首字母大写, object表示是从哪个类继承而来的, 所有类都可以继承自object类.
创建实例
实例 = 类名(参数列表)
初始化函数
上述的类名跟上参数列表是默认写入需要的参数, 是基于__init__()方法的
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
其中init的第一个参数永远是self, 这个是表示创建的实例本身, 相当于java的this, 在使用过程中传入参数不要管self, 因为这是解释器会自己添加
但是与java不同的是, 如果有__init__方法了, 生成实例的时候就必须对应的传入需要的参数, 但是不用传入self.
成员方法
类中的方法与别的方法的区别在于, 类中的方法第一个参数始终是self, 表示实例自己, 但是传入参数的时候不用管它.
数据封装
数据封装就是写一些方法来调用对应的成员变量, 对外使用的时候就直接调用该方法了而不是直接调用里面的成员变量.
2 访问限制
根据上述的数据封装的方法, 切实的给予了外界使用成员变量的方法, 但是外界仍然可以继续直接调用成员变量
要设置私有的成员变量是将成员变量定义成以双下划线开头的变量. 这样外界调用的时候就会报错了.
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
>>> bart = Student('Bart Simpson', 98)
>>> bart.__name
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute '__name'
注意前后都是双下划线的是特殊变量, 特殊变量是可以允许访问的
实际上可以通过 实例._类名__变量 来访问该私有变量, 但是强烈要求不要这么做!!
>>> bart._Student__name
'Bart Simpson'
3 继承和多态
OOP中可以由继承的产生. 通过继承得到的类叫做子类(Subclass), 被继承的类叫做基类, 父类, 超类(Base class, Super class)
继承的作用就是继承了父类的方法, 可以直接使用
class Animal(object):
def run(self):
print('Animal is running...')
class Dog(Animal):
pass
class Cat(Animal):
pass
>>> dog = Dog()
>>> dog.run()
>>> Animal is running...
>>> cat = Cat()
>>> cat.run()
>>> Animal is running...
多态是指, 子类可以被看成是父类, 但是父类不可以被看成是子类
def run_twice(animal):
animal.run()
animal.run()
当我们定义这样的方法, 根据传入的动物不同, 会分别打印出自己不同的run方法
Python这样的动态语言与Java这样的静态语言 不同, 不需要检查run_twice方法传入的参数是不是Animal类型, 只需要传入的类型有run方法就可以了.
4 获取对象信息
1 判断对象是什么类型, 使用type()函数就可以了
type()函数的返回值是Class类型
可以通过导入types来获取更多类型, 用于判断函数, 内置函数, 匿名函数, 生成器等
>>> import types
>>> def fn():
... pass
...
>>> type(fn)==types.FunctionType
True
>>> type(abs)==types.BuiltinFunctionType
True
>>> type(lambda x: x)==types.LambdaType
True
>>> type((x for x in range(10)))==types.GeneratorType
True
2 判断class类型, 使用isinstance()函数就可以了
基本上可以使用type()的都可以使用isinstance()函数
isinstance()常用于判断实例的
isinstance()可以用来判断是否是父类的. 如若a是类A定义的, 且继承自B类, 则instance(a, B)返回值也为真
3 获得一个对象的所有属性和方法, 可以使用dir()函数
例如
>>> dir('ABC')
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
其中的__XXX__()一般都是有特殊用途的, 例如__len__()就是获得长度的, 所以
>>> len('ABC')
3
>>> 'ABC'.__len__()
3
#这俩效果是相同的
同时, 如希望手动定义的类也可以使用len()函数, 则就需要在类体中定义__len__()函数
另外还有getattr()、setattr()以及hasattr()函数用于获取更多信息
1) hasattr(对象, 属性) 判断该对象是否有该属性
2) getattr(对象, 属性, 如果属性不存在时的返回值) 获取对象的属性
3) setattr(对象, 属性, 属性值) 给某对象设置属性和值
具体使用如下
>>> hasattr(obj, 'x') # 有属性'x'吗?
True
>>> obj.x
9
>>> hasattr(obj, 'y') # 有属性'y'吗?
False
>>> setattr(obj, 'y', 19) # 设置一个属性'y'
>>> hasattr(obj, 'y') # 有属性'y'吗?
True
>>> getattr(obj, 'y') # 获取属性'y'
19
>>> obj.y # 获取属性'y'
19
5 实例属性和类属性
Python是动态语言, 可以给实例绑定任意属性
可以通过实例或者self绑定
class Student(object):
def __init__(self, name):
self.name = name
s = Student('Bob')
s.score = 90
上述通过self绑定了name值Bob, 通过实例绑定了score为90
还可以定义类的属性
类属性的定义放在类定义当中
class Student(object):
name = 'Student'
def __init__(self):
pass
pass
当通过实例查找某个属性无法找到的时候, 解释器会查找类属性