[Python3] 类

[Python3] 类

(1)namespace 是从object到name的映射。
(2)namespace用dict实现,通常这种映射不可见。
(3)内建程序的模块被称为buinltins
(4)程序或脚本的顶级模块被称为“__main__”
(5)scope是Python的文本域,它的namespace是directly accessible。“Directly accessible”意味着一个未授权的引用试图在namespace中查找name。
(6)虽然scope是静态的,但它被用于动态。在任何执行期间,至少有三个嵌套域,它们的namespace是直接访问的:
※最里层的scope是最先被搜索的,它包含了本地名。
※任何程序的scope,先从最近的封闭域(enclosing scope)开始搜索,它包含了非本地,而且非全局的名字。
※从第二个到最后一个scope包含了当前模块的全局名。
※最外层scope(最后搜索)是包含了built-in名的namespace。
(7)如果名字声明成global,那么所有引用和赋值直接到中间域(middle scope),它包含了模块的全局名。
(8)在最内层的域之外重新绑定变量,可以使用nonlocal声明。如果声明中没有nonlocal,变量是只读的。
(9)通常本地域引用当前程序的本地名。外部程序的本地域引用相同的namespace作为全局域。类的定义在本地域中放置了另一个namespace。
(10)区域是由文本决定的,这点很重要:一个函数的全局域定义在一个模块中,该全局域就是模块的名字空间,和在哪里(或使用什么别名)调用函数无关。
(11) 如果没有global声明的影响,绑定对象和名只是在最近的区域。assignment并不复制数据——只是把name和object绑定。删除时也是一样:语句 del x,是将被本地域引用的x从namespace中移除。实际上,所有产生新名字的操作使用的都是本地域:import声明和函数定义是在本地域绑定模块或函数名。
(12)global声明了特定的变量存在于全局域,nonlocal声明了特定的变量存在于当前区域的外层,现在在内层重新绑定一次。
Scopes and Namespaces例子

def scope_test():
    def do_local():
        spam = "local spam"//本地声名不改变外层的spam值。
    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"//nonloacl分配改变了外层的spam值。
    def do_global():
        global spam
        spam = "global spam"//global分配改变成模块级别绑定,相当于在全局域中定义了一个变量spam,此时不改变外层的spam值。
    spam = "test spam"//在do_nonlocal()函数中,这里的spam就是nonlocal
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", 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 spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam

(13)__doc__是有效类属性,它返回属于该类的docstring。

(14)__init__()方法,类似于c++中的构造函数。在类中用def __init__(self):来定义,self类似C++中的this指针。
(15)MyClass是一个类,x是该类的一个实例,f()是该类的一个方法。x.f是方法对象(method object);MyClass.f是函数对象(function object);如果一个”名字“是有效的类属性,并且是个函数对象,那么方法对象是当指向(pointers to)实例对象时创建的,并且同时函数对象在该抽象类中被找到。当一个方法对象使用参数列表调用时,一个新的参数列表在实例对象中构建,并且函数对象使用这个新参数列表进行调用。
(16)x.f()完全等同于MyClass.f(x)。
(17)类对象支持两类操作:属性索引和实例化。
(18)实例变量:每个实例中的数据是唯一的;
类   变量:所有的实例共享属性和方法。
(19)在python中无法像C++那样完全地隐藏类的实现细节,并不是技术做不到,而仅仅是因为习惯才设计成这样。
(20)类的继承class 派生名(基类名):
(21)如果被请求的属性没有在类中找到,查找会在其基类中继续。这个规则是递归的,直到没有基类。
(22)派生类的方法可以覆盖其基类的方法。当调用某一对象的方法A()时,方法A()的基类方法又调用同一类中的方法B(),在这一调用过程中,很有可能最后调用的是在该派生类中覆盖B()的方法。(对于C++程序员来说在PYTHON中所有的方法实际上都是virtual的)
(23)在派生类中调用基类方法:BaseClassName.methodname(self, arguments)。
(24)Python有两个内建函数用于继承:
  • isinstance():用于检查实例类型:isinstance(obj,int)如果obj.__class__是int或int的派生类,那么返回True。
  • issubclass():用于检查类继承:issubclass(bool,int)返回True,因为bool是int的子类。但是issubclass(float,int)返回false,因为float不是int的子类。

(25)多继承 class 派生类名(base1, base2,base3):
如果在派生类中没有找到要查找的属性,那么之后会在base1的继承结构中递归查找,如果没找到会在base2中进行同样的操作。

(26)当类成员的名字以一个下划线开头时(包括方法和数据成员),习惯上被看成是非公有的API(也就是_spam)。

(27)当一个标示符的形式是“__spam”(至少两个下划线前缀,至多一个下划线后缀),其文本会被替换成_classname__spam的形式。classname是当前类的名字。这种替换和标示符的位置无关,只要是被定义在类里,就会被替换。在类中可以使用__spam这种形式调用,在类外要使用_classname__spam这种形式调用。

(28)迭代器类型iterator

(29)generators

发表评论