读书笔记八

来源:互联网 发布:Ubuntu 软件怎么打不开 编辑:程序博客网 时间:2024/05/01 18:15

python tutorial 第九章

Classes

python的class机制是提供所有OOP的标准特征的:类允许继承自多个基类;一个派生类可以重写基类中的任何方法;方法可以与基类中的方法重名。由于是真正的模块,类分享了python的动态性质:它们在运行时间内被创造,并且可以在创造之后依然被改变。


python的范围和命名空间

命名空间是从名字到对象的映射关系网。大多数的命名空间现在被用来作为python字典的工具,但是不管从什么途径正常情况下都不容易被察觉,而且在未来还有被改变的可能。举一些命名空间的例子:已编译函数名字的集合;模块中的全局名字;函数中的局部名字。很关键的一点是不同命名空间中的名字之间是没有任何联系的。

严格的来说,模块中名字的引用是属性的引用:modname.funcname中modname是模块,funcname是它的属性。在这个例子中,模块的属性和在该模块中被定义的全局名字之间是有一个直接的映射关系的,它们共享同一个命名空间。

范围是一个容易理解命名空间的python程序的文本区域。容易理解在这里的解释是可以用不是很合格的引用就可以从该命名空间中找到名字。


Class

类对象提供了两种方式的操作:属性引用和实例。

在属性的引用名称中有两种不同的方式,数据引用和方法。

x是MyClass的实例,这里要注意的是,MyClass.f和x.f是不同的东西,x.f是方法对象,而MyClass.f是函数对象。


类和实例的变量

在类中被定义的变量(非方法中被定义的变量)是可以被任意实例引用的,同时实例对该变量的操作也只会作用在该实例中。这其中有例外,如果该变量时列表或者字典的形式,就会导致不同的实例会对同一个变量产生影响。为避免这种情况,正确的做法是将定义变量放在__init__方法中。


随机备注

如果名称相同,数据属性是会重载方法属性的,所以为避免这种可能引发很难查找bug的情况的发生,特别是在大型的项目中,我们需要用一些习惯来减少这种错误出现的可能。这些可能的习惯包括方法名称首字母大写,用一个不寻常的字符串(也可能是一个下划线)作为数据属性名称的前缀或者用动词作为方法名,名词作为数据属性的名字。

在python的类中会经常看到self的存在,但其实self本身并没有什么特别的意思,更多的是一种约定俗成。我们可以用self来读取该类中的方法以及数据属性。


继承

class DerivedClassName(BaseClassName):

...

当类对象被构造时,其父类也会被记住。这样会作用在属性引用上:如果在类中没有发现需要的属性,那么搜索进程就会寻找其基类。当然,该规则也会被用在基类及其他类上。

在方法引用中也遵循一定的规则:相符的类属性被找到,如果可能,沿着基类的链条走下去,如果这个产生了一个函数对象,那么方法引用就生效了。

因为在调用同个对象中的其他方式时,方法是没有特权的,所以一个会调用该基类中其他被定义的方法的基类的方法可能会结束调用一个重写了的派生类的方法。解释一下:如果某个方法被派生类个重写了,按理来说,以后调用的该方法都应该是重写后的,但有可能当基类本身在调用该方法的时候还是会调用被重写前的。很好理解,派生类是后出现的,基类先被构造的,如果可以任由重写影响基类本身的一些行为,那么基类将会很难被整理使用了。


多类继承

class DerivedClassName(Base1, Base2, Base3):

...

对于老式风格的类来说,唯一的规则就是深度优先,从左至右。因此,如果一个属性没有在DerivedClassName中被找到,那么先找Base1,然后在Base1的基类,如果还是没找到,再找Base2,以此类推。

但是对于新式风格的类来说,动态的调整顺序变得更加正常,因为不同派生类的所有例子中会表现出一个或者多个的菱形关系。所以有可能某些基类会被多次调用,为了让调用顺序保持顺序形式,需要做一些适当的调整,比如在每个类中,保持从左至右的特殊顺序;只调用每个父类一个;单调调用(可能在不损害其父类顺序优先级的情况下将某类作为子类排序)。同样对于新式风格来说,还有一个重要的事情就是支持合作调用super()。


迭代器

迭代器的使用可以说遍布整个python中。其实从幕后来说,for也是调用了iter()。该函数会返回一个迭代对象,该对象定义了next()方法,可以每次得到容易中一个元素。当没有元素时,next()就会抛出一个StopIteration异常来告诉for循环可以结束了。

我们也可以在类中自己创建一个迭代器,定义一个__iter__()方法,该方法返回通过调用next()方法返回一个对象即可。如果我们定义了next()方法,那么__iter__()方法就只需返回self就可以了。


生成器

生成器可以快速的生成一个迭代器,只需用yield将要生成的迭代器的每个元素加入即可。这样自动生成的迭代器要更加整洁简单和安全。


0 0