Python 从入门到进阶之路(五)

以前的文章咱们简单介绍了一下 Python 的函数,本篇文章咱们来看一下 Python 中的面向对象。编程

 Python从设计之初就已是一门面向对象的语言,正由于如此,在Python中建立一个类和对象是很容易的。数据结构

面向对象技术简介

  • 类(Class): 用来描述具备相同的属性和方法的对象的集合。它定义了该集合中每一个对象所共有的属性和方法。对象是类的实例。
  • 方法:类中定义的函数。
  • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体以外。类变量一般不做为实例变量使用。
  • 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • 方法重写:若是从父类继承的方法不能知足子类的需求,能够对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • 局部变量:定义在方法中的变量,只做用于当前实例的类。
  • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部可是在类的其余成员方法以外声明的。
  • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也容许把一个派生类的对象做为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 实例化:建立一个类的实例,类的具体对象。
  • 对象:经过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

和其它编程语言相比,Python 在尽量不增长新的语法和语义的状况下加入了类机制。编程语言

Python中的类提供了面向对象编程的全部基本功能:类的继承机制容许多个基类,派生类能够覆盖基类中的任何方法,方法中能够调用基类中的同名方法。ide

对象能够包含任意数量和类型的数据。函数

Python 中定义类的方法是以 class k开头,咱们先定义一个类:ui

1 class Cat:
2     def eat(self):
3         print("猫吃鱼")
4         
5 cat = Cat()
6 cat.eat()  # 猫吃鱼

如上 ,咱们定义了一个 Cat 类,里面定义了一个方法,咱们能够经过 变量=类名() 的方式来实例化一个类,这样咱们就能够调用类里面的属性和方法,因此当咱们调用 cat.eat() 时输出打印 Cat 类里面的 eat() 方法。spa

在上面的 eat() 方法中,咱们默认穿了一个 self 的参数,它表明该类的实例,不必定非叫 self ,能够叫 xxx,只是咱们约定俗成叫 self,跟 *args 和 **kwargs 一个道理,那该如何理解这个 self 呢,以下:设计

 1 class Cat:
 2     def eat(self):
 3         print(self.name+"吃鱼")
 4 
 5 
 6 tom = Cat()
 7 tom.name = "Tom"
 8 tom.eat()  # Tom吃鱼
 9 
10 jerry = Cat()
11 jerry.name = "Jerry"
12 jerry.eat()  # Jerry吃鱼

在上面的代码中,咱们定义了两个 Cat 的实例,而且在每一个实例中都添加了一个 name 属性,若是咱们想要在 eat() 方法中输出各自定义的 name 值,咱们能够经过 self 属性来定义,由于 self 就表示该类的实例,因此就会去拿各自实例里面的 name 值。code

上面的代码中咱们能够实现输出不一样的 name 值,可是须要咱们在实例化后本身定义 name,咱们也能够在定义类的时候就将 name 值传入来作:对象

 1 class Cat:
 2     def __init__(self,name):
 3         self.name = name
 4     def eat(self):
 5         print(self.name+"吃鱼")
 6 
 7 tom = Cat("Tom")
 8 tom.eat()  # Tom吃鱼
 9 
10 jerry = Cat("Jerry")
11 jerry.eat()  # Jerry吃鱼

上面的代码中,咱们在 Cat 类中定义了一个 __init__() 的方法,该方法是类自带的方法,第一个参数必须为 self,咱们能够在里面定义本身所需的变量。如上,咱们在实例化 Cat 类的时候就将 Tom ,Jeery 传入,而后在 self 形参后面添加形参,该形参与传入参数的顺序意义对应,这样咱们就可使用传入的参数了,定义和使用时须要在前面加 self. 

在上面的代码演示中,咱们能够看出当咱们实例化一个类以后,就能调用该类的方法,这种方法叫公有方法,还有一种方法叫私有方法,就是实例化后不能被调用,只有本身内部能够调用,以下:

 1 class Cat:
 2     def __init__(self,name):
 3         self.name= name
 4     def eat(self):
 5         print(self.name+"吃鱼")
 6         self.__run()
 7     def __run(self):
 8         print("私有方法")
 9 
10 tom = Cat("Tom")
11 tom.eat()  # Tom吃鱼  私有方法
12 tom.__run()  # AttributeError: 'Cat' object has no attribute '__run'

上面的代码中当咱们实例化 tom 后,能够经过 eat() 方法调用到 __run() 方法,可是直接调用 __run() 会报错。

不只私有方法不能被调用,私有属性也不能,以下:

 1 class Cat:
 2     age = 11
 3     __height = 120
 4     def add(self):
 5         self.age += 1
 6         self.__height += 1
 7 
 8 tom = Cat()
 9 tom.add()
10 print(tom.age)  # 12
11 print(tom.__height)  # AttributeError: 'Cat' object has no attribute '__height'

接下来咱们看一下类中的继承,在上面的代码中咱们定义了一个 Cat 的类,里面有一个 eat() 方法,当咱们定义一个 Dog 类时,它也有一个 eat() 方法,并且 eat() 方法是同样的,如今 Cat 类有一个 bark() 方法,Dog 类里也有一个 bark() 方法,可是这两个方法执行的结果不同,并且 Dog 类里有一个 swim() 方法,而 Cat 里没有,若是咱们都分别定义这两个类的话,代码会很长,并且若是两个相同的 eat() 方法须要修改时须要修改两个地方,这时咱们能够用继承的方式解决,以下:

 1 class Animal:
 2     def eat(self):
 3         print("吃吃吃")
 4 
 5 class Cat(Animal):
 6     def bark(self):
 7         print("喵喵喵")
 8 
 9 class Dog(Animal):
10     def bark(self):
11         print("汪汪汪")
12 
13     def swim(self):
14         print("狗刨式")
15 
16 cat = Cat()
17 cat.eat()  # 吃吃吃
18 cat.bark()  # 喵喵喵
19 cat.swim()  # AttributeError: 'Cat' object has no attribute 'swim'
20 
21 dog = Dog()
22 dog.eat()  # 吃吃吃
23 dog.bark()  # 汪汪汪
24 dog.swim()  # 狗刨式

咱们将 Cat 类和 Dog 类相同的 eat() 方法定义在了 Animal 类里,而后在建立 Cat 和 Dog 类时添加了 (Animal),意思是继承 Animal 类,这样咱们在实例化 Cat 和 Dog 类后就能调用 Animal 类里的方法 eat(),并且还能调用各自实例里的 bark() 方法,可是若是没有另外一个类,则不能使用该类的方法,如 cat 调用 dog 的 swim() 方法就会报错。

固然咱们可让 Cat 类也继承 Dog 类,以下:

 1 class Animal:
 2     def eat(self):
 3         print("吃吃吃")
 4 # Cat 类要想继承 Dog 类必须写在 Dog 类后面
 5 # class Cat(Dog,Animal):
 6 #     def bark(self):
 7 #         print("喵喵喵")
 8 
 9 class Dog(Animal):
10     def bark(self):
11         print("汪汪汪")
12     def swim(self):
13         print("狗刨式")
14 
15 class Cat(Dog,Animal):
16     def bark(self):
17         print("喵喵喵")
18 
19 cat = Cat()
20 cat.eat()  # 吃吃吃
21 cat.bark()  # 喵喵喵
22 cat.swim()  # 狗刨式
23 
24 dog = Dog()
25 dog.eat()  # 吃吃吃
26 dog.bark()  # 汪汪汪
27 dog.swim()  # 狗刨式

如上,咱们可让 Cat 同时继承 Dog 和 Animal 两个类,可是如若想要继承某类,必须先建立该类。

咱们也能够多重继承,即让 Animal 类也继承某类,这样 Cat 和 Dog 若是继承了 Animal 类,那么也可使用 Animal 类继承的父类的属性和方法。

只得注意的是私有属性和方法不能被继承,由于私有属性和方法只能在本身的类中使用。

 

接下来咱们看一下类中方法的重写:

 1 class Animal:
 2     def eat(self):
 3         print("吃吃吃")
 4 
 5 class Cat(Animal):
 6     pass
 7 
 8 class Dog(Animal):
 9     def eat(self):
10         print("大口大口吃")
11 
12 cat = Cat()
13 cat.eat()  # 吃吃吃
14 
15 dog = Dog()
16 dog.eat()  # 大口大口吃

在上面的代码中,咱们让 Cat 和 Dog 类都继承了 Animal 类,可是在 Dog 类中,咱们定义了一个和 Animal 类中同样的方法名,可是执行的结果不同,当咱们分别调用实例化的 cat 和 dog 的 eat() 方法时,Cat 类因为没有本身的 eat() 方法,因此向上寻找,发现继承的 Animal 类中有 eat() 方法,因此就调用了 Animal 类中的 eat() 方法,可是 Dog 类中有 eat() 方法,因此就调用本身的 eat() 方法,不在向上寻找,这就是类中方法的重写。

 

在上面咱们说过了类属性和实例方法,接下来咱们来看一下类方法:

 1 class Cat:
 2     # 类属性
 3     age = 10
 4 
 5     # 实例方法
 6     def __init__(self):
 7         self.name = "Tom"
 8 
 9     def info(self):
10         print(self.name, self.age)
11 
12     # 类方法
13     @classmethod
14     def addAge(cls):
15         cls.age = 22
16 
17 tom = Cat()
18 tom.info()  # Tom 10
19 Cat.info()  # TypeError: info() missing 1 required positional argument: 'self'
20 
21 tom.addAge()
22 print(tom.age)  # 22
23 print(Cat.age)  # 22
24 
25 Cat.addAge()
26 print(tom.age)  # 22
27 print(Cat.age)  # 22

若是咱们在类里面的方法前面加 @classmethod,就代表该方法为类方法,在说类方法前咱们再来看一下实例方法。

当咱们实例化一个 tom 后,咱们就能够调用 tom 里面的实例方法,咱们以前说过 self 指的是该类的实例化,因此当咱们调用 tom.info() 时能正常调用,可是 Cat.info() 时则会报错,由于里面的 self 指向的是实例化的 tom,而不是 Cat 类,因此会报错。

在类方法中,咱们一样谣传一个默认的形参,默认叫 cls,它指向的是类自己,而不是该类的实例化,因此咱们能够经过 cls.age=22 来更改类里面的类属性,并且类方法 addAge() 可使用实例化的 tom 来调用,也可使用 Cat 类自己来调用。

相关文章
相关标签/搜索