7.3 KiB
Python 类介绍(第 2 部分,共 2 部分)
原文:https://www.pythoncentral.io/introduction-to-python-classes-part-2-of-2/
在本系列的第一部分中,我们看了在 Python 中使用类的基础知识。现在我们来看看一些更高级的主题。
Python 类继承
Python 类支持继承,这让我们获得一个类定义并扩展它。让我们创建一个继承(或从第一部分中的例子派生出)的新类:
class Foo:
def __init__(self, val):
self.val = val
def printVal(self):
print(self.val)
类 derived Foo(Foo):
def negate val(self):
self . val =-self . val
这定义了一个名为DerivedFoo的类,它拥有Foo类所拥有的一切,还添加了一个名为negateVal的新方法。这就是它的作用:
>>> obj = DerivedFoo(42)
>>> obj.printVal()
42
>>> obj.negateVal()
>>> obj.printVal()
-42
当我们重新定义(或覆盖)一个已经在基类中定义的方法时,继承变得非常有用:
class DerivedFoo2(Foo):
def printVal(self):
print('My value is %s' % self.val)
我们可以按如下方式测试该类:
>>> obj2 = DerivedFoo2(42)
>>> obj2.printVal()
My value is 42
派生类重新定义了printVal方法来做一些不同的事情,每当调用printVal时都会使用这个新版本。这让我们可以改变类的行为,这通常是我们想要的(因为如果我们想要原始的行为,我们只需要使用原始的类)。注意,该方法的新版本调用旧版本,并且调用以基类的名称为前缀(否则 Python 会认为您调用的是新版本)。
Python 提供了几个函数来帮助您确定一个对象是什么类:
- 检查一个对象是否是指定类的一个实例,或者是一个派生类。
例如以下内容:
>>> print(isinstance(obj, Foo))
True
>>> print(isinstance(obj, DerivedFoo))
True
>>> print(isinstance(obj, DerivedFoo2))
False
- 检查一个类是否派生自另一个类
例如以下内容:
>>> print(issubclass(DerivedFoo, Foo))
True
>>> print(issubclass(int, Foo))
False
Python 类迭代器和生成器
Python 的for语句将循环遍历任何可迭代的,包括内置的数据类型,如数组和字典。例如:
>>> arr = [1,2,3]
>>> for x in arr:
... print(x)
1
2
3
当我们定义自己的类时,我们可以使它们可迭代,这将允许它们在 for 循环中工作。我们通过定义一个返回一个迭代器(一个跟踪我们在循环中的位置的对象)的__iter__方法和一个返回下一个可用值的__next__方法来实现这一点。请注意,Python 3.x 和 Python 2.x 的next方法的语法是不同的。对于 Python 3.x,您必须使用__next__方法,而对于 Python 2.x,您必须使用next方法。
这里有一个简单的例子,可以让你在一个数据结构上向后迭代。下面是类的定义:
[python] class Backwards: def init(self, val): self.val = val self.pos = len(val)
def iter(self): 回归自我
def next(self): #如果 self.pos < = 0: 提升 StopIteration,我们就完成了
self.pos = self.pos - 1 return self.val[self.pos] [/python]
[python] class Backwards: def init(self, val): self.val = val self.pos = len(val)
def iter(self): 回归自我
def next(self): #我们完成了 如果 self.pos < = 0: 提高 StopIteration
self.pos = self.pos - 1 return self.val[self.pos] [/python]
这是一个迭代类的例子:
>>> for x in Backwards([1,2,3]):
... print(x)
3
2
1
该类跟踪两件事,被迭代的数据结构和下一个要返回的值。__iter__方法只是返回对对象本身的引用,因为这是用来管理循环的。当 Python 遍历对象时,它会重复调用next方法来获取下一个值,直到没有剩余值时抛出StopIteration异常。
这是一个非常简单的例子,但是它的大部分是锅炉板代码(获取每一项并跟踪我们在循环中的进度),每次我们想要创建一个 iterable 类时都是一样的。然而,Python 又一次拯救了我们,它给我们提供了一种方法,使用生成器来消除所有这些重复的管理代码。
一个生成器是一种特殊的函数,它返回一个 iterable 对象,这个对象自动地记住它在一个循环中的位置。这是同一个例子,这次使用了一个发生器。
该功能可定义如下(注意:使用yield关键字):
def backwards(val):
for n in range(len(val), 0, -1):
yield val[n-1]
我们可以这样使用发电机:
>>> for x in backwards([1,2,3]):
... print(x)
3
2
1
如果你以前从未见过这种事情,你可能真的很难理解它,但是最简单的方法就是像这样阅读backwards函数:
- 在传入的值上向后循环。
- 在每一遍中,
yield下一个值,即暂时停止执行循环,并将下一个值返回给调用者。它做它想做的任何事情,然后当它再次调用我们时,我们从我们停止的地方继续循环。
作为对象的 Python 类
一个类描述了该类的实例看起来像什么,也就是说,它们将有什么方法和成员变量。在内部,Python 在自己的对象中跟踪每个类的定义,我们可以修改这个对象。这意味着我们可以动态地改变类的定义,甚至在运行时创建一个全新的类!
让我们从一个简单的类定义开始:
class Foo:
def __init__(self, val):
self.val = val
让我们来看看用法:
>>> obj = Foo(42)
>>> obj.printVal()
AttributeError: Foo instance has no attribute 'printVal'
哎呀!我们得到一个错误,因为这个类没有一个printVal方法。
好了,再加一个:-)。我们可以这样定义它:
def printVal(self):
print(self.val)
我们可以将函数添加到类中,如下所示:
>>> Foo.printVal = printVal
>>> obj.printVal()
42
我们定义了一个名为 printVal 的方法,它是独立的(也就是说,它是在类之外定义的),但是它看起来像一个类方法(也就是说,它有一个 self 参数)。然后,我们将它添加到类定义(Foo.printVal = printVal)中,这使得它变得可用,就好像它是原始类定义的一部分一样。
如果我们想删除它,我们可以使用普通的del语句:
>>> del Foo.printVal
>>> obj.printVal()
AttributeError: Foo instance has no attribute 'printVal'
为了在运行时创建一个全新的类,我们使用了type方法:
>>> obj = MyNewClass()
NameError: name 'MyNewClass' is not defined
>>> MyNewClass = type('MyNewClass', (object,), dict())
>>> obj = MyNewClass()
>>> print(obj)
<__main__.MyNewClass object at 0x01D79DCC>
type调用的第二个参数是我们想要从中派生的类的列表,而第三个参数是组成类定义的方法和成员变量的字典(您可以在这里定义它们,或者如上所述动态添加它们)。
要理解 Python 中的生成器和 yield 关键字,请查看文章 Python 生成器和 yield 关键字。