# Python 中的面向对象编程

> 原文： [http://zetcode.com/lang/python/oop/](http://zetcode.com/lang/python/oop/)

在 Python 教程的这一部分中，我们将讨论 Python 中的面向对象编程。

那里有三种广泛使用的编程示例：过程编程，函数编程和面向对象的编程。 Python 支持所有三种编程示例。

## 面向对象编程

面向对象编程（OOP）是一种使用对象及其相互作用设计应用和计算机程序的编程示例。

OOP 中有一些基本的编程概念：

*   抽象
*   多态
*   封装
*   继承

抽象通过建模适合该问题的类来简化复杂的现实。 多态是将运算符或函数以不同方式用于不同数据输入的过程。 封装对其他对象隐藏了类的实现细节。 继承是一种使用已经定义的类形成新类的方法。

## Python 对象

Python 中的所有内容都是一个对象。 对象是 Python OOP 程序的基本构建块。

`object_types.py`

```py
#!/usr/bin/env python

# object_types.py

import sys

def function():
    pass

print(type(1))
print(type(""))
print(type([]))
print(type({}))
print(type(()))
print(type(object))
print(type(function))
print(type(sys))

```

在此示例中，我们显示所有这些实体实际上都是对象。 `type()`函数返回指定对象的类型。

```py
$ ./object_types.py 
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'type'>
<class 'function'>
<class 'module'>

```

整数，字符串，列表，字典，元组，函数和模块是 Python 对象。

## Python `class`关键字

先前的对象都是 Python 编程语言的内置对象。 用户定义的对象是使用`class`关键字创建的。 该类是定义未来对象性质的蓝图。 从类中，我们构造实例。 实例是从特定类创建的特定对象。 例如，`Huck`可能是`Dog`类的实例。

`first_object.py`

```py
#!/usr/bin/env python

# first_object.py

class First:
    pass

fr = First()

print(type(fr))
print(type(First))

```

这是我们的头等舱。 该类的主体暂时留空。 按照惯例，给类起一个以大写字母开头的名称。

```py
class First:
    pass

```

在这里，我们定义`First`类。 请注意，默认情况下，所有类均从基`object`继承。

```py
fr = First()

```

在这里，我们创建`First`类的新实例。 换句话说，我们实例化了`First`类。 `fr`是对我们新对象的引用。

```py
$ ./first_object.py 
<class '__main__.First'>
<class 'type'>

```

在这里，我们看到`fr`是`First`类的实例对象。

在类内部，我们可以定义属性和方法。 属性是对象的特征。 例如，这可以是雇员的工资。 方法定义了我们可以对对象执行的操作。 一种方法可以定义取消帐户。 从技术上讲，属性是变量，方法是在类内部定义的函数。

## Python 对象初始化

称为`__init__()`的特殊方法用于初始化对象。

`object_initialization.py`

```py
#!/usr/bin/env python

# object_initialization.py

class Being:

    def __init__(self):
        print("Being is initialized")

Being()

```

我们有一个`Being`类。 创建对象后立即自动调用特殊方法`__init__()`。

```py
$ ./object_initialization.py 
Being is initialized

```

这是示例输出。

## Python 对象属性

属性是对象的特征。 在`__init__()`方法中设置属性。

`attributes.py`

```py
#!/usr/bin/env python

# attributes.py

class Cat:

    def __init__(self, name):

        self.name = name

missy = Cat('Missy')
lucky = Cat('Lucky')

print(missy.name)
print(lucky.name)

```

在此代码示例中，我们有一个`Cat`类。 创建对象后立即自动调用特殊方法`__init__()`。

```py
def __init__(self, name):

```

类定义中的每个方法都以对实例对象的引用开头。 按照惯例，它的名称为`self`。 `self`名称没有什么特别的。 例如，我们可以这样命名。 第二个参数`name`是自变量。 该值在类初始化期间传递。

```py
self.name = name

```

在这里，我们将属性传递给实例对象。

```py
missy = Cat('Missy')
lucky = Cat('Lucky')

```

在这里，我们创建两个对象：猫`Missy`和`Lucky`。 参数的数量必须与类定义的`__init__()`方法相对应。 `"Missy"`和`"Lucky"`字符串成为`__init__()`方法的`name`参数。

```py
print(missy.name)
print(lucky.name)

```

在这里，我们打印两个猫对象的属性。 一个类的每个实例可以有自己的属性。

```py
$ ./attributes.py 
Missy
Lucky

```

可以动态分配属性，而不仅仅是在初始化过程中。 下一个示例对此进行了说明。

`attributes_dynamic.py`

```py
#!/usr/bin/env python

# attributes_dynamic.py

class Person:
    pass

p = Person()
p.age = 24
p.name = "Peter"

print("{0} is {1} years old".format(p.name, p.age))

```

我们定义并创建一个空的`Person`类。

```py
p.age = 24
p.name = "Peter"

```

在这里，我们动态创建两个属性：`age`和`name`。

```py
$ ./attributes_dynamic.py 
24 is Peter years old

```

## Python 类属性

到目前为止，我们一直在讨论实例属性。 在 Python 中，还有所谓的类对象属性。 类的所有实例的类对象属性都相同。

`class_attribute.py`

```py
#!/usr/bin/env python

# class_attribute.py

class Cat:
    species = 'mammal'

    def __init__(self, name, age):

        self.name = name
        self.age = age

missy = Cat('Missy', 3)
lucky = Cat('Lucky', 5)

print(missy.name, missy.age)
print(lucky.name, lucky.age)

print(Cat.species)
print(missy.__class__.species)
print(lucky.__class__.species)

```

在我们的示例中，我们有两只具有特定`name`和`age`属性的猫。 两只猫都有一些共同之处。 小姐和幸运者都是哺乳动物。 这反映在类级别属性`species`中。 该属性是在类主体中的任何方法名称之外定义的。

```py
print(Cat.species)
print(missy.__class__.species)

```

有两种方法可以访问类对象属性：通过`Cat`类的名称，或借助特殊的`__class__`属性。

```py
$ ./class_attribute.py 
Missy 3
Lucky 5
mammal
mammal
mammal

```

## Python 方法

方法是在类主体内定义的函数。 它们用于通过对象的属性执行操作。 在 OOP 范式的封装概念中，方法至关重要。 例如，我们的`AccessDatabase`类中可能有一个`connect()`方法。 我们无需知道方法连接如何准确地连接到数据库。 我们只知道它用于连接数据库。 这对于划分编程中的职责至关重要，尤其是在大型应用中。

`methods.py`

```py
#!/usr/bin/env python

# methods.py

class Circle:

    pi = 3.141592

    def __init__(self, radius=1):
        self.radius = radius

    def area(self):
        return self.radius * self.radius * Circle.pi

    def setRadius(self, radius):
        self.radius = radius

    def getRadius(self):
        return self.radius

c = Circle()

c.setRadius(5)
print(c.getRadius())
print(c.area())

```

在代码示例中，我们有一个`Circle`类。 我们定义了三种新方法。

```py
def area(self):
    return self.radius * self.radius * Circle.pi

```

`area()`方法返回圆的面积。

```py
def setRadius(self, radius):
    self.radius = radius

```

`setRadius()`方法为`radius`属性设置新值。

```py
def getRadius(self):
    return self.radius

```

`getRadius()`方法返回当前半径。

```py
c.setRadius(5)

```

在实例对象上调用该方法。 `c`对象与类定义的`self`参数配对。 数字 5 与`radius`参数配对。

```py
$ ./methods.py 
5
78.5398

```

在 Python 中，我们可以通过两种方式调用方法。 有有界的和无界的方法调用。

`bound_unbound_methods.py`

```py
#!/usr/bin/env python

# bound_unbound_methods.py

class Methods:

    def __init__(self):
        self.name = 'Methods'

    def getName(self):
        return self.name

m = Methods()

print(m.getName())
print(Methods.getName(m))

```

在此示例中，我们演示了两个方法调用。

```py
print(m.getName())

```

这是绑定的方法调用。 Python 解释器会自动将`m`实例与`self`参数配对。

```py
print(Methods.getName(m))

```

这是无界的方法调用。 实例对象已显式提供给`getName()`方法。

```py
$ ./bound_unbound_methods.py 
Methods
Methods

```

## Python 继承

继承是一种使用已经定义的类形成新类的方法。 新形成的类称为派生的类，我们从中衍生的类称为基类。 继承的重要好处是代码重用和降低程序的复杂性。 派生类（后代）将覆盖或扩展基类（祖先）的功能。

`inheritance.py`

```py
#!/usr/bin/env python

# inheritance.py

class Animal:

    def __init__(self):
        print("Animal created")

    def whoAmI(self):
        print("Animal")

    def eat(self):
        print("Eating")

class Dog(Animal):

    def __init__(self):
        super().__init__()

        print("Dog created")

    def whoAmI(self):
        print("Dog")

    def bark(self):
        print("Woof!")

d = Dog()
d.whoAmI()
d.eat()
d.bark()

```

在此示例中，我们有两个类：`Animal`和`Dog`。 `Animal`是基类，`Dog`是派生类。 派生类继承基类的功能。 通过`eat()`方法显示。 派生的类修改了基类的现有行为，如`whoAmI()`方法所示。 最后，派生类通过定义新的`bark()`方法来扩展基类的功能。

```py
class Dog(Animal):

    def __init__(self):
        super().__init__()

        print("Dog created")

```

我们将祖先类放在子孙类名称之后的圆括号中。 如果派生类提供了自己的`__init__()`方法，并且我们想调用父构造器，则必须借助`super`函数显式调用基类`__init__()`方法。

```py
$ ./inherit.py 
Animal created
Dog created
Dog
Eating
Woof!

```

## Python 多态

多态是对不同的数据输入以不同方式使用运算符或函数的过程。 实际上，多态意味着如果类 B 从类 A 继承，则不必继承关于类 A 的所有内容； 它可以完成 A 类所做的某些事情。

`basic_polymorphism.py`

```py
#!/usr/bin/env python

# basic_polymorphism.py

a = "alfa"
b = (1, 2, 3, 4)
c = ['o', 'm', 'e', 'g', 'a']

print(a[2])
print(b[1])
print(c[3])

```

Python 在内置类型中广泛使用了多态。 在这里，我们对三种不同的数据类型使用相同的索引运算符。

```py
$ ./basic_polymorphism.py 
f
2
g

```

多态在处理继承时最常用。

`polymorphism.py`

```py
#!/usr/bin/env python

# polymorphism.py

class Animal:

   def __init__(self, name=''):

      self.name = name

   def talk(self):

      pass

class Cat(Animal):

   def talk(self):

      print("Meow!")

class Dog(Animal):

   def talk(self):

      print("Woof!")

a = Animal()
a.talk()

c = Cat("Missy")
c.talk()

d = Dog("Rocky")
d.talk()

```

在这里，我们有两种：狗和猫。 两者都是动物。 `Dog`类和`Cat`类继承了`Animal`类。 它们具有`talk()`方法，可以为它们提供不同的输出。

```py
$ ./polymorphism.py 
Meow!
Woof!

```

## Python 特殊方法

Python 编程语言中的类可以使用特殊的方法名称来实现某些操作。 这些方法不是直接调用，而是通过特定的语言语法调用。 这类似于在 C++ 或 Ruby 中所谓的运算符重载。

`special_methods.py`

```py
#!/usr/bin/env python

# special_methods.py

class Book:

    def __init__(self, title, author, pages):

        print("A book is created")

        self.title = title
        self.author = author
        self.pages = pages

    def __str__(self):

        return "Title:{0} , author:{1}, pages:{2} ".format(
            self.title, self.author, self.pages)

    def __len__(self):

        return self.pages

    def __del__(self):

        print("A book is destroyed")

book = Book("Inside Steve's Brain", "Leander Kahney", 304)

print(book)
print(len(book))
del book

```

在我们的代码示例中，我们有一个`book`类。 在这里，我们介绍四种特殊方法：`__init__()`，`__str__()`，`__len__()`和`__del__()`。

```py
book = Book("Inside Steve's Brain", "Leander Kahney", 304)

```

在这里，我们称为`__init__()`方法。 该方法创建`Book`类的新实例。

```py
print(book)

```

`print`关键字调用`__str__()`方法。 此方法应返回对象的非正式字符串表示形式。

```py
print(len(book))

```

`len()`函数调用`__len__()`方法。 就我们而言，我们打印书的页数。

```py
del book

```

`del`关键字删除一个对象。 它调用其`__del__()`方法。

在下一个示例中，我们实现一个向量类并演示对其的加法和减法运算。

`vector.py`

```py
#!/usr/bin/env python

# vector.py

class Vector:

    def __init__(self, data):

        self.data = data

    def __str__(self):

        return repr(self.data)

    def __add__(self, other):

        data = []

        for j in range(len(self.data)):

            data.append(self.data[j] + other.data[j])

        return Vector(data)

    def __sub__(self, other):

        data = []

        for j in range(len(self.data)):

            data.append(self.data[j] - other.data[j])

        return Vector(data)

x = Vector([1, 2, 3])
y = Vector([3, 0, 2])

print(x + y)
print(y - x)

```

该示例介绍了`__add__`和`__sub__`方法。

```py
def __add__(self, other):

    data = []

    for j in range(len(self.data)):

        data.append(self.data[j] + other.data[j])

    return Vector(data)

```

在这里，我们实现向量的加法运算。 当我们使用`+`运算符添加两个`Vector`对象时，将调用`__add__()`方法。 在这里，我们将各个向量的每个成员相加。

```py
$ ./vector.py 
[4, 2, 5]
[2, -2, -1]

```

这是输出。

在 Python 教程的这一部分中，我们介绍了 Python 中的面向对象编程。