跳转至

Python 面向对象编程

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

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

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

  • 抽象化
  • 多态性
  • 封装形式
  • 继承

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

Python 对象

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

object_types.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()函数返回指定对象的类型。

1
2
3
4
5
6
7
8
9
$ ./object_types.py 
<class 'int'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'tuple'>
<class 'type'>
<class 'function'>
<class 'module'>

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

Python 类关键字

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

first_object.py
#!/usr/bin/env python

# first_object.py

class First:
    pass

fr = First()

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

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

class First:
    pass

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

fr = First()

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

1
2
3
$ ./first_object.py 
<class '__main__.First'>
<class 'type'>

在这里,我们看到frFirst类的实例对象。

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

Python 对象初始化

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

object_initialization.py
#!/usr/bin/env python

# object_initialization.py

class Being:

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

Being()

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

$ ./object_initialization.py 
Being is initialized

Python 对象属性

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

attributes.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__()

def __init__(self, name):

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

self.name = name

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

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

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

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

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

1
2
3
$ ./attributes.py 
Missy
Lucky

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

attributes_dynamic.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类。

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

在这里,我们动态创建两个属性:age 和 name。

$ ./attributes_dynamic.py 
24 is Peter years old

Python 类属性

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

class_attribute.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)

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

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

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

1
2
3
4
5
6
$ ./class_attribute.py 
Missy 3
Lucky 5
mammal
mammal
mammal

Python 方法

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

methods.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类。 我们定义了三种新方法。

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

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

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

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

def getRadius(self):
    return self.radius

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

c.setRadius(5)

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

1
2
3
$ ./methods.py 
5
78.5398

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

bound_unbound_methods.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))

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

print(m.getName())

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

print(Methods.getName(m))

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

1
2
3
$ ./bound_unbound_methods.py 
Methods
Methods

Python 继承

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

inheritance.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()

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

1
2
3
4
5
6
class Dog(Animal):

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

        print("Dog created")

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

1
2
3
4
5
6
$ ./inherit.py 
Animal created
Dog created
Dog
Eating
Woof!

Python 多态性

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

basic_polymorphism.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 在内置类型中广泛使用了多态。 在这里,我们对三种不同的数据类型使用相同的索引运算符。

1
2
3
4
$ ./basic_polymorphism.py 
f
2
g

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

polymorphism.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()方法,可以为它们提供不同的输出。

1
2
3
$ ./polymorphism.py 
Meow!
Woof!

Python 特殊方法

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

special_methods.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__()

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

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

print(book)

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

print(len(book))

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

del book

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

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

vector.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__方法。

1
2
3
4
5
6
7
8
9
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__()方法。 在这里,我们将各个向量的每个成员相加。

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