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()
函数返回指定对象的类型。
| $ ./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))
|
这是我们的头等舱。 该类的主体暂时留空。 按照惯例,给类起一个以大写字母开头的名称。
在这里,我们定义First
类。 请注意,默认情况下,所有类均从基object
继承。
在这里,我们创建First
类的新实例。 换句话说,我们实例化了First
类。 fr
是对我们新对象的引用。
| $ ./first_object.py
<class '__main__.First'>
<class 'type'>
|
在这里,我们看到fr
是First
类的实例对象。
在类内部,我们可以定义属性和方法。 属性是对象的特征。 例如,这可以是雇员的工资。 方法定义了我们可以对对象执行的操作。 一种方法可以定义取消帐户。 从技术上讲,属性是变量,方法是在类内部定义的函数。
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):
|
类定义中的每个方法都以对实例对象的引用开头。 按照惯例,它的名称为self
。 self
名称没有什么特别的。 例如,我们可以这样命名。 第二个参数name
是自变量。 该值在类初始化期间传递。
在这里,我们将属性传递给实例对象。
| missy = Cat('Missy')
lucky = Cat('Lucky')
|
在这里,我们创建两个对象:猫 Missy 和 Lucky。 参数的数量必须与类定义的__init__()
方法相对应。 “ Missy”和“ Lucky”字符串成为__init__()
方法的name
参数。
| print(missy.name)
print(lucky.name)
|
在这里,我们打印两个猫对象的属性。 一个类的每个实例可以有自己的属性。
| $ ./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)
|
在我们的示例中,我们有两只具有特定name
和age
属性的猫。 两只猫都有一些共同之处。 小姐和幸运者都是哺乳动物。 这反映在类级别属性species
中。 该属性是在类主体中的任何方法名称之外定义的。
| print(Cat.species)
print(missy.__class__.species)
|
有两种方法可以访问类对象属性:通过Cat
类的名称,或借助特殊的__class__
属性。
| $ ./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
对象与类定义的self
参数配对。 数字 5 与radius
参数配对。
在 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))
|
在此示例中,我们演示了两个方法调用。
这是绑定的方法调用。 Python 解释器会自动将m
实例与 self 参数配对。
| print(Methods.getName(m))
|
这是无界的方法调用。 实例对象已显式提供给getName()
方法。
| $ ./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()
|
在此示例中,我们有两个类:Animal
和Dog
。 Animal
是基类,Dog
是派生类。 派生类继承基类的功能。 通过eat()
方法显示。 派生的类修改了基类的现有行为,如whoAmI()
方法所示。 最后,派生类通过定义新的bark()
方法来扩展基类的功能。
| class Dog(Animal):
def __init__(self):
super().__init__()
print("Dog created")
|
我们将祖先类放在子孙类名称之后的圆括号中。 如果派生类提供了自己的__init__()
方法,并且我们想调用父构造函数,则必须借助super
函数显式调用基类__init__()
方法。
| $ ./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 在内置类型中广泛使用了多态。 在这里,我们对三种不同的数据类型使用相同的索引运算符。
| $ ./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()
方法,可以为它们提供不同的输出。
| $ ./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 关键字调用__str__()
方法。 此方法应返回对象的非正式字符串表示形式。
len()
函数调用__len__()
方法。 就我们而言,我们打印书的页数。
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__
方法。
| 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__()
方法。 在这里,我们将各个向量的每个成员相加。
| $ ./vector.py
[4, 2, 5]
[2, -2, -1]
|