收藏 分销(赏)

python开发之‘类’.docx

上传人:二*** 文档编号:4765916 上传时间:2024-10-12 格式:DOCX 页数:13 大小:44.17KB 下载积分:5 金币
下载 相关 举报
python开发之‘类’.docx_第1页
第1页 / 共13页
本文档共13页,全文阅读请下载到手机保存,查看更方便
资源描述
Classes 类工Python在尽可能不增加新的语法和语义的情况下加入了类机制。这种机制是C++和Modula-3 的混合。Pyihon中的类没有在用户和定义之间建立一个绝对的屏障,而是依赖于用户自觉的不 去“破坏定义然而,类机制最重要的功能都完整的保存下来:类继承机制允许多继承,派生 类可以覆盖(override)基类中的任何方法,方法中可以调用基类中的同名方法。对象可以包 含任意数量的私有成员。 用C++术语来讲,所有的类成员(包括数据成员)都是*公有* (参见PriMe Variables私有 变量)的,所有的成员函数都是*虚*( virtual )的。没有特定的构造和析构函数。像Modula-3 一样,在成员方法中没有什么简便的方式可以引用对象的成员:方法函数在定义时需要以引用 的对象做为第一个参数,调用时那么会隐式引用对象。像Smalltalk 一样,类本身就是对象,在 更为广义的范围上理解:Python中一切数据类型都是对象。这样就形成了语义上的引入和重 命名。但是,像C++而非Modula-3中那样,大多数带有特殊语法的内置操作符(算法运算 符、下标等)都可以针对类的需要重新定义。 A Word About Terminology 术语漫谈义由于没有什么关于类的通用术语,我从Smalltalk和C++中借用一些(我更希望用Modula-3 的,因 为它的面向对象机制比C++更接近Python,不过我想没多少读者听说过它)。 对象是被特化的,多个名字(在多个作用域中)可以绑定同一个对象。这相当于其它语言中的 别名。通常对Python的第一印象中会忽略这一点,使用那些不可变的基本类型(数值、字符 串、元组)时也可以很放心的忽视它。然而,在Python代码调用字典、链表之类可变对象, 以及大多数涉及程序外部实体(文件、窗体等等)的类型时,这一语义就会有影响。这通用有 助于优化程序,因为别名的行为在某些方面类似于指针。例如,很容易传递一个对象,因为在 行为上只是传递了一个指针。如果函数修改了一个通过参数传递的对■象,调用者可以接收到变 化一一在Pascal中这需要两个不同的参数传递机制。 Python Scopes and Name Spaces作用域和命名空间工在介绍类之前,我首先介绍一些有关Python作用域的规那么:类的定义非常巧妙的运用了命名 空间,要完全理解接下来的知识,需要先理解作用域和命名空间的工作原理。另外,这一切的 知识对于任何高级Python程序员都非常有用。 Let's begin with some definitions. 我们从一些定义开始。 工命名空间*是从命名到对象的映射,当前命名空间主要是通过Python字典实现的,不过通常 示关心具体的实现方式(除非出于性能考虑),以后也有可能会改变其实现方式。以下有一些 命名空间的例子:内置命名(像abs()这样的函数,以及内置异常名)集,模块中的全局命名, 函数调用中的局部命名。某种意义上讲对象的属性集也是一个命名空间。关于命名空间需要了 解的一件很重要的事就是不同命名空间中的命名没有任何联系,例如两个不同的模块可能都会 定义一个名为“maximize”的函数而不会发生混淆一一用户必须以模块名为前缀来引用它们。 顺便提一句,我习惯称Python中任何一个之后的命名为*属性*例如,表达式z.real中的real是对象z的一个属性。严格来讲,从模块中引用命名是引用属性:表达式 modname.funcname中,modname是一个模块对象,''「uncname、'是它的一个属性。因此,模 块的属性和模块中的全局命名有直接的映射关系:它们共享同一命名空间! [#]_ 属性可以是只读或可写的。后一种情况下,可以对属性赋值。你可以这样作: ''modname.the_answer = 42'',,可写的属性也可以用del语句删除。例如:''del mod name. thc_answcr'' 会从 modname 对象中删除 thc_answcr 属性。 响它的祖先类的优先级)。合起来看,这些东西使得它可以通过多继承设计可靠和可扩展的类 型。要了解详细内容,参见 /。 Private Variables 私有变量义There is limited support for class-private identifiers. Any identifier of the form _spam (at least two leading underscores, at most one trailing underscore) is textually replaced with _classnainc_spam, where elassname is the current class name with leading undcrscorc(s) stripped. This mangling is done without regard to the syntactic position of the identifier, so it can be used to define class-private instance and class variables, methcxls, variables stored in globals, and even variables stored in instances, private to this class on instances of other classes. Truncation may occur when the mangled name would be longer than 255 characters. Outside classes, or when the class name consists of only underscores, no mangling occurs. Python对类的私有成员提供了有限的支持。任何形如_spam (以至少双下划线开头,至多单 下划线结尾)随即都被替代为_classname_spam ,去掉前导下划线的classname即当前的类 名。这种混淆不关心标识符的语法位置,所以可用来定义私有类实例和类变量、方法,以及全 局变量,甚至于将*其它*类的实例保存为私有变量。混淆名长度超过255个字符的时候可能会发 生截断。在类的外部,或类名只包含下划线时,不会发生截断。 Name mangling is intended to give classes an easy way to define “private“ instance variables and methods, without having to worry about instance variables defined by derived classes, or mucking with instance variables by code outside the class. Note that the mangling rules are designed mostly to avoid accidents; it still is possible for a determined soul to access or modify a variable that is considered private. This can even be useful in special circumstances, such as in the debugger, and that's one reason why this loophole is not closed. (Buglet: derivation of a class with the same name as the base class makes use of private variables of the base class possible.)命名混淆意在给出一个在类中定义“私有”实例变量和方法的简单途径,防止派生类的实例变量 定义产生问题,或者与外界代码中的变量搞混。要注意的是混淆规那么主要目的在于防止意外错 误,被认作为私有的变量仍然有可能被访问或修改。在特定的场合它也是有用的,比方调试的 时候,这也是一直没有堵上这个漏洞的原因之一(小漏洞:派生类和基类取相同的名字就可以 使用基类的私有变量。) Notice that code passed to cxcc() or cval() docs not consider the elassname of the invoking class to be the current class; this is similar to the effect of the global statement, the effect of which is likewise restricted to code that is byte-compiled together. The same restriction applies to getattr(), setattr() and delattr(), as well as when referencing _diet_ directly. 要注意的是传入exec()'', ''eval()的代码不会将调用它们的类视作当前类,这与global语句 的情况类似,''global''的作用局限于“同一批”进行字节编译的代码。同样的限制也适用于 getattr()'\ ''setattr()和 delattr(),以及直接引用 _diet_ 的时候。 Odds and Ends 补充1Sometimes it is useful to have a data type similar to the Pascal “record” or C “struct",bundling together a few named data items. An empty class definition will do nicely: 有时类似于Pascal中“记录(record) ”金C中“结构(struct)”的数据类型很有用,它将一组已 命名的数据项绑定在一起。一个空的类定义可以很好的实现这它: class Employee: passjohn = EmployeeO # Create an empty employee record # Fill the fields of the record john.name = John Doc'john.dept = 'computer lab' john.salary = 1000 A piece of Python code that expects a particular abstract data type can often be passed a class that emulates the methods of that data type instead. For instance, if you have a function that formats some data from a file object, you can define a class with methods rcad() and rcadlinc() that get the data from a string buffer instead, and pass it as an argument. 某一段Python代码需要一个特殊的抽象数据结构的话,通常可以传入一个类,事实上这模仿 了该类的方法。例如,如果你有一个用于从文件对象中格式化数据的函数,你可以定义一个带 有read()和readline()方法的类,以此从字符串缓冲读取数据,然后将该类的对象作为参数传 入前述的函数。 Instance method objects have attributes, too: m._self_ is the instance object with the method m(), and m._func_ is the function object corresponding to the method. 方法对象实例也有属性,、、m._self_、、是调用m()方法的实例对象,二m._func_'、是这个方 法对应的函数对象。 Exceptions Are Classes Too 异常也是类义User-defined exceptions are identified by classes as well. Using this mechanism it is possible to create extensible hierarchies of exceptions. 用户自定义异常也可以是类。利用这个机制可以创立可扩展的异常体系。 There are two valid (semantic) forms for the raise statement: 以下是两种新的有效(语义上的)异常抛出形式: raise Classraise Instance In the first form, Class must be an instance of type or of a class derived from it. The first form is a shorthand for: 第一种形式中,''Class''必须是ivne或其派生类的一个实例。第一种形式是以下形式的简写: raise Class()A class in an except clause is compatible with an exception if it is the same class or a base class thereof (but not the other way around — an except clause listing a derived class is not compatible with a base class). For example, the following code will print B, C. D in that order: 发生的异常其类型如果是except子句中列出的类,或者是其派生类,那么它们就是相符的(但 是不能反过来说一一 except子句列出的类型如果是其子类,不能作为判别依据)。例如,以下 代码会按顺序打印B, C. D: class B: passclass C(B): passclass D(C): passforcin[B,C, D]: try: raise c() except D: print(“D”) except C: print("C”) except B: print("B”)Note that if the except clauses were reversed (with except B first), it would have printed B, B, B 一 the first matching except clause is triggered. 要注意的是如果异常子句的顺序颠倒过来(“except B”在最前),它就会打印B, B, B 一 — 第•个匹配的异常被触发。 When an error message is printed fbr an unhandled exception, the exception's class name is printed, then a colon and a space, and finally the instance converted to a string using the built-in function str(). 打印一个异常类的错误信息时,先打印类名,然后是一个空格、一个冒号,然后是用内置函数str() 将类转换得到的完整字符串。 Iterators迭代器必By now you have probably noticed that most container objects can be looped over using a for statement: 现在你可能注意到大多数容器对象都可以用lor遍历: for element in [I, 2, 3]: print(element)for element in (1, 2, 3): print(element) for key in ('one1:1, 'two':2): print(key)for char in "123": print(char) for line in open("myfile.txt"): print(line)This style of access is clear, concise, and convenient. The use of iterators pervades and unifies Python. Behind the scenes, the for statement calls iter() on the container object. The function returns an iterator object that defines the method _next—() which accesses elements in the container one at a time. When there are no more elements, —next—() raises a Stoplteration exception which tells the for loop to terminate. You can call the _next_() method using the next。builtin; this example shows how it all works: 这种形式的访问清晰、简洁、方便。迭代器的用法在Python中普遍而且统一。在后 台,:keyword:自,•语句在容器对象中调用iterO。该函薮返回一个定义了 _next_()方法的迭 代器对象,它在容器中逐一访问元素。没有后续的元素时,:抛出一个SlODheraiion 异常通知for语句循环结束。你可以使用内置函数nextQ调用_next_()方法。以下是其工 作原理的例如: »>s = 'abc' »>it = iter(s) »>it<iterator object at OxOOA 1 DB50> »>ncxt(it) 'a'»>nexl(it) 'b' »>next(it)*c' »>next(it)Traccback (most recent call last): File ”<stdin>”, line l,in? next(it)Stoplteralion Having seen the mechanics behind the iterator protocol, it is easy (o add iterator behavior to your classes. Define a iter 。method which returns an object with a _next_() method. If the class defines _next_(), then iter 。can just return self: r解了迭代器协议的后台机制,就可以很容易的给自己的类添加迭代器行为。定义一个 M ()方法,使其返回一个带有_ncxt()方法的对象。如果这个类已经定义了 _next_、, 那么:meth:'_iter_()只需要返回''self': class Reverse: “Iterator fbr looping over a sequence backwards" def _init_(self, data): self.data = data self.index = len(data) def—iter_(self): return self def_next_(self): if self.index == 0: raise Slopiterationself.index = self.index - I return self.da(a[self.index] »>for char in ReverseCspam'): ... print(char)Generators 生成器” Generators arc a simple and powerful tool for creating iterators. They arc written like regular functions but use the yield statement whenever they want to return data. Each time next。is called on it, the generator resumes where it left-off (it remembers all the data values and which statement was last executed). An example shows that generators can be trivially easy to create: 生成器'是创立迭代器的简单而强大的工具。它们写起来就像是正那么函数,需要返回数据 的时候使用:keyword:'yield'语句。每次:func:'next'被调用时,生成器回复它脱离的位置(它 记忆语句最后一次执行的位置和所有的数据值)。以下例如演示了生成器便捷的创立方式: def reverse(dala): for index in range(len(data)-1, -1, -1): yield data[index]»>for char in reverse('golf): ... print(char)f Io gAnything that can be done with generators can also be done with class based iterators as described in the previous section. What makes generators so compact is that the iter () and —next—() methods are created automatically. 前一节中描述了基于类的迭代器,它能作的每〜件事生成器也能作到。因为自动创立了 iler ()和next。方法,生成器显得如此简洁。 Another key feature is that the local variables and execution slate are automatically saved between calls. This made the function easier to write and much more clear than an approach using instance variables like self.index and self.data. 另外一个关键的功能是两次调用之间的局部变量和执行情况都自动保存了下来。这样函数编写 起来就比手动调用self.index和self.data这样的类变量容易的多。 In addition to automatic method creation and saving program state, when generators terminate, they automatically raise StoDlteration. In combination, these features make it easy to create iterators with no more effort than writing a regular function. 除了创立和保存程序状态的自动方法,当发生器终结时,还会自动抛出Stojlteration异常。综 上所述,这些功能使得编写一个正规函数成为创立迭代器的最简单方法。 Generator Expressions生成器表达式工Some simple generators can be coded succinctly as expressions using a syntax similar to list comprehensions but with parentheses instead of brackets. These expressions are designed for situations where the generator is used right away by an enclosing function. Generator expressions are more compact but less versatile than full generator definitions and tend to be more memory friendly than equivalent list comprehensions. 有时简单的生成器可以用简洁的方式调用,就像不带中括号的链表推导式。这些表达式是为函 数调用生成器而设计的。生成器表达式比完整的生成器定义更简洁,但是没有那么多变,而且 通常比等价的列表推导式更容易记。 Examples: »>sum(i*i for i in range(lO))# sum of squares285 »>xvec = [10, 20, 301»>yvec = [7, 5, 3] >»sum(x*y for x,y in zip(xvec, yvec))# dot product260 »>from math import pi, sin»>sine_lable = dict((x, sin(x*pi/180)) for x in range(0, 91)) »>unique_words = set(word for line in page for word in line.split())»>valedictorian = max((student.gpa, student.name) for student in graduates) »>data = 'golf»>list(data[i] for i in range(len(data)-1, -1,-1)) [T, T, 'o', 'g'] Footnotes[1Except for one thing. Module objects have a secret read-only attribute called _diet_ which ]returns the dictionary used to implement the module's namespace; the name diet is an attribute but not a global name. Obviously, using (his violates the abstraction of namespace implementation, and should be restricted to things like post-mortem debuggers.有个例外。模 块对象有一个隐秘的只读属性,叫_dict_',返回组成模块的命名空间;:attr:'_dict_ 这个名字是一个属性而非全局命名。显然,这违反了命名空间实现概念,应该严格限制 于调试之类的场合。 Table Of ContentsClasses 类 o A Word About Tcrminolosy 术语漫谈Python Scopes and Name Spaces 作 用 域和 命片空 间 , Scopes and Namespaces Example 作用 域和 命名空 间例如 A Firsi Look al Classes 初识类, Class Definition Syntax 类定义语法 ■ Class Objects 类对象, Insiance Objects 实例对象 ■ Method Objects 方法对象o Random Remarks 一些说明 Inhcrilancc 继承Multiple Inheritance 多继承 o Pri vale Variables 私有变量o Odds and Ends 补充 o Exceptions Are Classes Too 异常也是类o Ileralors迭彳弋器 o Generators 生成器o Generator Expressions 生成器表达式 Previous topicErrors and Exceplions 错 误和异 常 Next topicBrief Tour of ihe Standard Library 标准库概览 This Page • Show SourceQuick search Navigation • index • modulesl • nextl • previous] • ft • Python v3.0cl documentation》 • The Pylhon tutorial Python 入门指南》© CcDyrighl 1990-2008, Python Software Foundation. Last updated on Oct 31, 2008. Created using Sphinx 0.5. 在不同的时刻创立的命名空间,有不同的生存期。包含内置命名的命名空间在Python解释器 启动时创立,会一直保存,不被删除。模块的全局命名空间在模块定义被读入时创立,通常, 模块命名空间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚 本文件中读入还是来自交互式输入,都是 5〃—模块的一局部,所以它们也拥有自己的命名空间。(内置命名也同样被包含在一个模 块中,它被称作_builtin_ 。) 当函数被调用时创立一个局部命名空间,函数反正返回过抛出一个未在函数内处理的异常时删 除。(实际上,说是遗忘更为贴切)。当然,每一个递归调用拥有自己的命名空间。 工作用域*是Python程序中一个命名空间可以直接访问的正文区域。“直接访问”在这里的意思是 查找命名时无需引用命名前缀。 尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有三个命名空间可以直 接访问的作用域嵌套在一起:包含局部命名的使用域在最里面,首先被搜索;其次搜索的是中 层的作用域,这里包含了同级的函数;最后搜索最外面的作用域,它包含内置命名。 如果•个命名声明为全局的,那么所有的赋值和引用都直接针对包含模全局命名的中级作用域。 另外,从外部访问到的所有内层作用域的变量都是只读的。(试图写这样的变量只会在内部作 用域创立一个*新*局部变量,外部标示命名的那个变量不会改变)。 从字面意义上讲,局部作用域引用当前函数的命名。在函数之外,局部作用域与全局使用域引 用同一命名空间:模块命名空间。类定义也是局部作用域中的另一个命名空间。 重要的是作用域决定于源程序的文本:一个定义于某模块中的函数的全局作用域是该模块的命 名空间,而不是该函数的别名被定义或调用的位置,了解这一点非常重要。另一方面,命名的 实际搜索过程是动态的,在运行时确定的——然而,Python语言也在不断开展,以后有可能 会成为静态的“编译”时确定,所以不要依赖动态解析!(事实上,局部变量己经是静态确定了。) Python的一个特别之处在于其赋值操作总是在最里层的作用域。赋值不会复制数据——只是将 命名绑定到对象。删除也是如此:“delx”只是从局部作用域的命名空间中删除命名x。事实 上,所有引入新命名的操作都作用于局部作用域。特别是import语句和函数定将模块名或函 数绑定于局部作用域。(可以使用global语句将变量引入到全局作用域。)关键字global可以用于从全局命名域引入个别变量并重绑定它::kcyword:m)〃/ocz/语句检索 外围的作用域并进行重绑定。 Scopes and Namespaces Example作用域和命名空间例如义以下例如演示了如何引用不同的作用域和命名空间,以及如何使用global和nonlocal影响变 量绑定: def scope_test(): def do_local(): spam = "local spam" def do_nonlocal(): nonlocal spam spam = "nonlocal spam" def do_global(): global spam spam = "global spam" spam = "test spam" do_localO print("After local assignment:", spam) do_nonlocal() print("After nonlocal assignment:'1, spam) do_global() print("After global assignment:", spam) scope_test()print("In global scope:", spam) The output of the example code is: 例如代码输出如下: After local assignment: test spamAfter nonlocal assignment: nonlocal spam After global assignment: nonlocal spamIn global scope: global spam 注意 扃制赋值(默认的)不会改变sopejesi在spam上的绑定。nonlocal赋值改变了 scopejest在spam上的绑定,而global赋值改变了模块级绑定。 You can also see that there was no previous binding for spam before the global assignment. 你可以观察到没有进行global赋值之前spam上的绑定没有改变。 A First Look at Classes 初识类必Classes introduce a little bit of new syntax, three new object types, and some new semantics. 类引入了一点新的语法,三种新的对象类型,以及一些新的语义。 Class Definition Syntax 类定义语法必The simplest form of class definition looks like this: 最简单的类定义形式如下: cla
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 通信科技 > 其他

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2025 宁波自信网络信息技术有限公司  版权所有

客服电话:4009-655-100  投诉/维权电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服