什么是面向对象?和面向对象对应的就是面向过程,过程就是函数,面向过程考虑的是当前正在发生什么事情?主要表现就是定义了一个个的函数,通过函数的调用来组织程序。
而面向对象,考虑的是“谁”当前正在发生什么事情?“谁”就是对象。主要表现就是定义一个个的对象,通过对象之间的关系来组织程序。
说的比较笼统,不懂的还是不懂。python是一门面向对象的语言,面向对象有三个基本要素,继承,封装,多态。
什么是对象?万物皆对象。人,山,空气等都是对象。但对象并不只包含万物,对象可以是抽象的,比如:思想。
现在我们拿鸟来简单的说一下。我们平时说到鸟的时候,其实就是泛指鸟类,是我们把一些飞禽抽象出来的一种概念。是一类动物
并不是单指一个,这就是面向对象中类的概念。而当我们说你看那只鸟好漂亮的时候,那只鸟就是特指某一只鸟,这只鸟就是对象。
我们把鸟的公共的特性和行为综合起来封装到一起就构成了鸟类。老鹰会飞,它生的孩子也会飞。鸵鸟会跑,它生的孩子也会跑。用一句话说“龙生龙,凤生凤,老鼠的孩子会打洞”,这叫做继承。上面我们简单地说了一下,类,对象以及封装和继承的概念,还有一个重要的概念就是多态,这个我们只能从程序中慢慢理解。
定义类的格式如下:
class ClassName:
<特性>
<行为>
下面我们定义一个鸟类,并且让它有一个可以飞的方法(函数),如下:
class Bird:
def fly(self):
print("I fly")
上面我们创建了一个鸟的类,并定义了一个fly方法(成员方法),此方法有一个参数self,表示当前对象的意思。那么我们怎么创建这个类的对象,并且让它飞呢?如下:
bird = Bird()
bird.fly(
输出结果:
I fly
我们通过类名和一对括号来创建一个鸟类的对象,并把这个对象赋值给bird引用,然后使用bird引用调用鸟类的fly方法。
构造方法是用来创建对象使用的,可以让我们使用一些参数来实例化一个对象(创建一个对象),构造方法在创建对象的时候会自动执行。
现在我们要给我们的鸟类添加一个特性(成员变量)颜色,别想希望在创建
对象的时候指定颜色,那么我们就需要用到构造函数,构造函数的结构是固定的,如果父类和子类都重新定义了构造方法_init( )_,
在进行子类实例化的时候,子类的构造方法不会自动调用父类的构造方法,必须在子类中显示调用。如下:
def __init__(self):
self.data = []
下面我们重新编写鸟类,添加构造方法和成员变量,代码如下:
class Bird:
#构造方法
def __init__(self,c):
print("Bird init")
#成员变量
self.color = c
#成员方法
def fly(self):
print("I can fly.")
#成员方法
def getColor(self):
print("I am %s color." % self.color)
#创建对象,为构造函数传递参数red
bird = Bird("red")
#调用方法
bird.fly()
#访问成员变量
print(bird.color)
输出结果如下:
Bird init
I can fly.
red
通过上面的代码,我们看到,我们可以使用对象引用加上“.”的方式访问对象的方法和属性。
继承的结构如下:
class ChildClass(BaseClassName1):
现在我们需要一个鸵鸟的类,并希望它有一个奔跑速度的特性和奔跑的方法,让鸵鸟的类继承鸟类;
class Ostrich(Bird):
#构造函数
def __init__(self,c,s):
#调用父类Bird1的构造方法
#子类的构造方法必须调用父类的构造方法,且必须在构造方法的第一行。
Bird.__init__(self, c)
#成员变量
self.runSpeed = s
#成员方法
def run(self):
print("I can run,speed is %i km/h" % self.runSpeed)
ostrich = Ostrich("gray",100)
ostrich.fly()
ostrich.run()
print(ostrich.color)
print(ostrich.runSpeed)
输出结果如下:
Bird init
I can fly.
I can run,speed is 100 km/h
gray
100
我们可以看到鸵鸟类的对象可以访问fly方法以及color属性,但是鸵鸟类中并没有color和fly方法,这是是从Bird类中继承来的。这里我们就看到了继承的强大之处。但是有个问题,我们都知道鸵鸟是不会飞的。那么我们需要重新实现一个Bird1的fly方法,这个过程我们称作重写。
代码如下:
class Ostrich(Bird):
#构造函数
def __init__(self,c,s):
#调用父类Bird1的构造方法
#子类的构造方法必须调用父类的构造方法,且必须在构造方法的第一行。
Bird.__init__(self, c)
#成员变量
self.runSpeed = s
#成员方法
def run(self):
print("I can run,speed is %i km/h" % self.runSpeed)
#重写父类fly方法
def fly(self):
print("I can not fly")
输出结果如下:
Bird init
I can not fly
I can run,speed is 100 km/h
gray
100
另外python中支持多继承,多重继承需要用逗号把父类分开。看下面代码:
class Animal:
def howl(self):
print("I can howl")
def run(self):
print("I can not run")
#多重继承
class Chicken(Animal,Ostrich):
def __init__(self,c,s):
Ostrich.__init__(self, c,s)
chiken = Chicken("green",10);
chiken.fly()
chiken.run()
chiken.howl()
输出结果如下:
Bird init
I can not fly
I can not run
I can howl
需要注意的是,如果多个类中有相同的方法,那么写在前面的父类会覆盖后面父类的方法。
上面的类中的属性和方法,在类外都可以通过点的方式来调用。为了保证封装性以及安全,某些属性和方法要禁止外部访问。python中双下划线开始的属性和方法是私有的,外部不能直接访问,如下例:
class Duck(Bird):
def __init__(self,c,swi):
Bird.__init__(self, c)
self.__swim = swi
def swimm(self):
if self.__swim:
print("I can swim")
else:
print("I can not swim")
def __setSwim(self,swim):
self.__swim = swim
duck = Duck("write",True)
duck.swimm()
duck.__setSwim(False)
print(duck.__swim)
输出结果:
Bird init
I can swim
Traceback (most recent call last):
File "E:\workspace-python\firstpython\src\first.py", line 36, in <module>
duck.__setSwim(False)
AttributeError: 'Duck' object has no attribute '__setSwim'
报错,说明爽下划线开始的成员变量和成员方法,不能在外部访问。
类属性是直接写在类中的属性,此类的多个成员共享一份类属性,成员方法和类型发可以访问类属性,类方法和静态方法可以直接通过类名来访问,代码如下:
class Static:
#类属性,多个实例对象共享此属性值
static_property = "static_property"
def __init__(self,s):
self.member_property = s #成员属性,对象独享此属性值
#静态方法,通过类型直接访问
@staticmethod
def staticMethod():
print("staticMethod")
#类方法,通过类型直接访问,可访问类属性
@classmethod
def classMethod(cls):
print(cls.static_property)
#成员方法,通过对象访问
def memberMethod(self):
print("memberMethod")
static1 = Static("aaaaaa")
static2 = Static("bbbbb")
print(static1.member_property)
print(static2.member_property)
print(Static.static_property)
Static.staticMethod()
Static.classMethod()
输出结果如下:
aaaaaa
bbbbb
static_property
staticMethod
static_property
python是弱类型的语言,多态的表现不是那么明显。多态的实现叫做动态绑定,也叫后期绑定,也就是说
直到运行的时候,才确定要执行的是哪个对象的方法。python也是支持多态的,
多态的表现就是一个引用,在赋予不同的对象时表现出不同的行为。看下面的代码:
class Animal:
def eat(self):
print("I eat everything")
class Fish(Animal):
def eat(self):
print("I eat water")
class Sheep(Animal):
def eat(self):
print("I eat grasses")
#定义函数,接收一个animal的参数
def eatWhat(animal):
animal.eat()
animal = Animal()
fish = Fish()
sheep = Sheep()
eatWhat(animal)
eatWhat(fish)
eatWhat(sheep)
输出结果为:
I eat everything
I eat water
I eat grasses