1.面向对象
把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数。
面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象之间传递。
classStudent(object):def __init__(self, name, score):
self.name=name
self.score=scoredefprint_score(self):print('%s: %s' % (self.name, self.score))
Class是一种抽象概念,比如我们定义的Class——Student,是指学生这个概念,而实例(Instance)则是一个个具体的Student,比如,Bart Simpson和Lisa Simpson是两个具体的Student。
类(Class):用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
方法:类中定义的函数。
类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
局部变量:定义在方法中的变量,只作用于当前实例的类。
实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
实例化:创建一个类的实例,类的具体对象。
对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
2.类和实例
必须牢记类是抽象的模板,比如Student类,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
classStudent(object):def __init__(self, name, score): #构造方法
self.name =name
self.score=scoredefget_grade(self):if self.score >= 90:return 'A'
elif self.score >= 60:return 'B'
else:return 'C'bart= Student('Bart Simpson', 59)print(bart.get_grade())
class后面紧接着是类名,即Student,类名通常是大写开头的单词,紧接着是(object),表示该类是从哪个类继承下来的,如果没有合适的继承类,就使用object类,这是所有类最终都会继承的类。
注意到__init__方法的第一个参数永远是self,表示创建的实例本身,因此,在__init__方法内部,就可以把各种属性绑定到self,因为self就指向创建的实例本身。
创建实例的时候,必须传入与__init__方法匹配的参数。
要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用一个方法,只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入:
classStudent(object):def __init__(self, name, score): #构造方法
self.__name =name
self.__score =score
defget_name(self):return self.__name
defget_score(self):return self.__score
defset_score(self, score):if 0 <= score <= 100:
self.__score =scoreelse:raise ValueError('bad score')
bart= Student('Bart Simpson', 59)
bart.set_score(100)print(bart.get_score(),bart.get_name())
bart._Student__name ###这样可以从外部访问了,但是不建议。
内部属性不被外部访问,实例的变量名如果以__开头,就变成了一个私有变量(private),只有内部可以访问,外部不能访问。
这样代码更健壮,可以对参数做检查,避免传入无效的参数
在Python中,变量名类似__xxx__的,就是以双下划线开头,并且以双下划线结尾,是特殊变量,特殊变量可以直接访问,不是private变量,不能用__name__、__score__这样的变量名。
以一个下划线开头的实例变量名,比如_name,这样的实例变量外部是可以访问的,但是,按照约定俗成的规定,把它当成私有变量。
__private_method:两个下划线开头,声明该方法为私有方法,只能在类的内部调用 ,不能在类的外部调用。self.__private_methods。
类的专有方法:可以对类的专有方法进行重载(用到具体的搜索吧)
__init__ : 构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方
3.继承和多态
OOP程序设计中,我们定义class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类、父类或超类(Base class、Super class)。
子类获得了父类的全部功能,但当子类和父类有相同的方法时,子类覆盖了父类的该方法,先调用子类的相同方法。
super() 函数是用于调用父类(超类)的一个方法super(dog, self).__init()__(name)
基类可以定义在别的模块中,classDerivedClassName(modname.BaseClassName): 但是要导入该模块import。
Python同样有限的支持多继承形式。需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索,方法在子类中未找到时,从左到右查找父类中是否包含方法。
classDerivedClassName(Base1, Base2, Base3):.
.
.
继承示例代码:
classAnimal(object):def __init__(self):
a= "animal"
defrun(self):print('Animal is running...')classDog(Animal):defrun(self):print('Dog is running...')defeat(self):print('Eating meat...')
dog=Dog()print(isinstance(dog, Dog))
Python中多态是指一类事物有多种形态。比如动物有多种形态,人,狗,猫,等等。文件有多种形态:文本文件,可执行文件。
多态性:
为什么要用多态性?
①增加了程序的灵活性
以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)
②增加了程序额可扩展性
通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用
importabcclass Animals(metaclass=abc.ABCMeta):
@abc.abstractmethoddeftalk(self):pass
classPeople(Animals):deftalk(self):print('People is talking')classCat(Animals):deftalk(self):print('Cat is miaomiao')classDog(Animals):deftalk(self):print('Dog is wangwang')
cat1=Cat()
dog1=Dog()
peo1=People()#peo、dog、pig都是动物,只要是动物肯定有talk方法#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo1.talk()
dog1.talk()
peo1.talk()#定义一个统一的接口来访问
deffunc(obj):
obj.talk()
func(cat1)
动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
4.获取对象信息
判断对象类型,使用type()函数。如果要判断一个对象是否是函数等,可以使用types模块中定义的常量。
isinstance()判断的是一个对象是否是该类型本身,或者位于该类型的父继承链上。总是优先使用isinstance()判断类型,可以将指定类型及其子类“一网打尽”。
获得一个对象的所有属性和方法,可以使用dir()函数。
通过内置的一系列函数,我们可以对任意一个Python对象进行剖析,拿到其内部的数据。要注意的是,只有在不知道对象信息的时候,我们才会去获取对象信息。
配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态。参考菜鸟python3 内置函数。
5. 实例属性和类属性
直接在class中定义属性,这种属性是类属性,归类所有。类的所有实例都可以访问到。相同名称的实例属性将屏蔽掉类属性。
访问类的变量是通过“类名.变量名”进行访问,而不是“self.变量名”进行访问。“self.变量名”访问的是实例对象的自身变量。
下面例子中实例的变量被重新绑定,
classff:
a = 5
defaaa(self):
print(ff.a) #如果写成self.a,a1.a变量被重新绑定,a1.aaa()的值就是10. 就取不到类的变量。
a1 =ff()
a1.aaa()
a2 =ff()
a2.aaa()
a1.a = 10
print(a1.a)
print(a2.a)
ff.a = 100
print(a1.a)
print(a2.a)
a1.aaa()
a2.aaa()
result:
5
5
10
5
10
100
100
100
6.使用__slots__
可以给一个实例绑定方法和属性,但对别的实例是不起作用的。
只允许对Student实例添加name和age属性。
classStudent(object):__slots__ = ('name', 'age') #用tuple定义允许绑定的属性名称s=Student()
s.name= "sss"s.score= 99
使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。
在子类中也定义__slots__,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__。
7.使用@property
读,写,删除的例子。三种操作对应了一个名字。
class People(object):
def __init__(self, name, age):
self.name = name
self.age = age
# 私有属性
self.__number = 0
# 获取私有属性值 number = p1.number 会执行这个函数
@property
def number(self):
# 返回私有属性值
return self.__number
# 设置私有属性值 p1.number = 666
@number.setter
def number(self, value):
# 设置__number的值
self.__number = value
# 删除私有属性 del p1.number 会执行这个函数
@number.deleter
def number(self):
# 删除属性
del self.__number
p1 = People('张三', 22)
# 正常的对象属性赋值
# 对象.属性名 = 属性值
p1.name = '李四'
# 获取对象的属性值
name = p1.name
# 删除对象的属性
del p1.name
# 私有属性升级版
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
num = p1.number
print(num)
# 会去执行@number.setter装饰的number函数,在函数中设置__number属性的值
p1.number = 666
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
print(p1.number)
# 会去执行@number.deleter装饰的number函数,在函数中会将__number属性删除
del p1.number
# 会去执行@property装饰number函数,函数执行完成后返回一个结果
print(p1.number)
birth是可读写属性,而age就是一个只读属性,因为age可以根据birth和当前时间计算出来。
classStudent(object):
@propertydefbirth(self):returnself._birth
@birth.setterdefbirth(self, value):
self._birth=value
@propertydefage(self):return 2015 -self._birth
s=Student()
s.birth= 5
print(s.birth)
8.多重继承
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为MixIn。
classDog(Mammal, RunnableMixIn, CarnivorousMixIn):pass
9.检查对象的特性
hasattr() 函数用于判断对象是否包含对应的属性。语法:hasattr(object,name)
getattr() 函数用于返回一个对象属性值。语法:getattr(object,name[,default])default -- 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
c =ff()print(hasattr(c, 'age')) #检查实例属性是否拥有
print(hasattr(c, 'study')) #检查实例方法是否拥有
print(callable(getattr(c, 'study',None))) #检查实例方法study能否被调用
是否拥有