面向对象编程 OOP
Object Oriented Programming,一种程序设计思想。OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数
面向过程和面向对象
- 面向过程,把函数继续切分为子函数
- 面向对象,把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递
对象
自定义的对象数据类型就是面向对象中的类(Class)的概念
首先必须创建出这个学生对应的对象,然后,给对象发一个print_score消息,让对象自己把自己的数据打印出来
代码语言:python代码运行次数:0复制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))
类(Class)和实例(Instance)
面向对象最重要的概念就是类(Class)和实例(Instance)
Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student
#class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object)
class Student(object):
pass
#创建建实例是通过类名 ()实现的:
bart = Student()
# bart绑定一个name属性
bart.name = 'Bart Simpson'
#在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去
class Student(object):
def __init__(self, name, score): #self,表示创建的实例本身
self.name = name
self.score = score
访问限制
由于外部代码还是可以自由地修改一个实例的属性,我们可以把属性的名称前加上两个下划线__,变成了一个私有变量(private),只有内部可以访问,外部不能访问
代码语言:python代码运行次数:0复制class Student(object):
def __init__(self, name, score): #self,表示创建的实例本身
self.__name = name
self.__score = score
#利用方法使得外部代码可以访问
def get_name(self):
return self.__name
#利用外部代码修改score
def set_score(self, score):
self.__score = score
继承和多态
我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)
代码语言:python代码运行次数:0复制class Animal(object): #编写Animal类
def run(self):
print("Animal is running...")
class Dog(Animal): #Dog类继承Amimal类,没有run方法
pass
class Cat(Animal): #Cat类继承Animal类,有自己的run方法
def run(self):
print('Cat is running...')
pass
class Car(object): #Car类不继承,有自己的run方法
def run(self):
print('Car is running...')
class Stone(object): #Stone类不继承,也没有run方法
pass
def run_twice(animal):
animal.run()
animal.run()
run_twice(Animal())
run_twice(Dog())
run_twice(Cat())
run_twice(Car())
run_twice(Stone())
输出结果
Animal is running... Animal is running...
Animal is running... Animal is running...
Cat is running... Cat is running...
Car is running... Car is running...
AttributeError: 'Stone' object has no attribute 'run'
由于Animal类型有run()方法,因此,传入的任意类型,只要是Animal类或者子类,就会自动调用实际类型的run()方法,这就是多态的意思
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
获取对象信息
type()函数
它返回对应的Class类型。如果我们要在if语句中判断,就需要比较两个变量的type类型是否相同
- 基本数据类型就是int,str
- 对象是函数的话,用types模块中定义的常量:types.FunctionType,types.BuiltinFunctionType,types.LambdaType,types.GeneratorType
isinstance()函数(优先)
对于class的继承关系来说,使用type()就很不方便。我们要判断class的类型,可以使用isinstance()函数
- isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上
- 还可以判断一个变量是否是某些类型中的一种,比如下面的代码就可以判断是否是list或者tuple
>>> isinstance([1, 2, 3], (list, tuple))
True
>>> isinstance((1, 2, 3), (list, tuple))
True
dir()函数
它返回一个包含字符串的list
仅把属性和方法列出来是不够的,配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态
代码语言:python代码运行次数:0复制>>> class MyObject(object):
... def __init__(self):
... self.x = 9
... def power(self):
... return self.x * self.x
...
>>> obj = MyObject()
>>> 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
>>> getattr(obj, 'z', 404) # 获取属性'z',如果不存在,返回默认值404
404
>>> hasattr(obj, 'power') # 有属性'power'吗?
True
>>> getattr(obj, 'power') # 获取属性'power'
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn = getattr(obj, 'power') # 获取属性'power'并赋值到变量fn
>>> fn # fn指向obj.power
<bound method MyObject.power of <__main__.MyObject object at 0x10077a6a0>>
>>> fn() # 调用fn()与调用obj.power()是一样的
81
实例属性和类属性
为了统计学生人数,可以给Student类增加一个类属性,每创建一个实例,该属性自动增加
代码语言:python代码运行次数:0复制class Student(object):
count = 0
def __init__(self, name):
self.name = name
Student.count = 1
发现没有直接点明init这个方法,在实例化对象的时候,应该是会自动调用一次这个方法