python学习笔记系列----(七)类
7.1 python类和相关术语的简介
Python 通过最小的新语法和语义在语言中实现了类。 它是 C++ 或者 Modula-3 语言中类机制的混合。类的大多数重要特性都被完整的保留下来:类继承机制允许多重继承,派生类可以覆盖(override)基类中的任何方法或类,可以使用相同的方法名称调用基类的方法。 对象可以包含任意数量的私有数据。下面介绍下python的一些相关术语:
A. 对象
在python中一切都是对象,每个对象都有自己的id(内存中的地址),类型,值;对象一旦建立,其id值就不会改变。
a =
print 'id of a :',id(a)
b = a
print 'id of b :',id(b)
b =
print a
print b
print 'id of a :',id(a)
print 'id of b :',id(b)
运行结果如下:
id of a :
id of b : id of a :
id of b :
说明:id()方法作用:得到对象的内存地址。变量a,b开始指向同一个对象,后面给b赋值后,实际是在当前作用域新建了一个局部变量,其变量名也是b,但是已经是一块新的内存。
B. 标识符
标识符:各类对象的名称,比如函数名、方法名、类名,变量名、常量名等。在python中,赋值不会直接复制数据,而是将标识符绑定到对象上去。对象本身并不知道也不需要关心(该关心这个的是使用对象的人)自己叫什么名字的。一个对象可以有读个不同的标识符,上例中的'a' 'b'便是如此。真正管理这些【标识符:对象】的关系的是”命名空间” 。
C. 命名空间
“A namespace is a mapping from names to objects”,命名空间是从命名到对象的映射。
D. 作用域
“A scope is a textual region of a Python program where a namespace is directly accessible” 是可以直接访问到命名空间的文本区域。
7.2 命名空间和作用域
命名空间表示标识符(identifier)的可见范围,当前命名空间主要是通过 Python 字典实现的,不过通常不关心具体的实现方式(除非出于性能考虑),以后也有可能会改变其实现方式。有一些命名空间的例子:内置命名(像 abs() 这样的函数,以及内置异常名)集,模块中的全局命名,函数调用中的局部命名。某种意义上讲对象的属性集也是一个命名空间。有几个点需要注意下:
第一:不同命名空间中的命名没有任何联系,例如两个不同的模块可能都会定义一个名为 maximize的函数而不会发生混淆--用户必须以模块名为前缀来引用它们。
第二:不同的命名空间在不同的时刻创建,有不同的生存期。包含内置命名的命名空间在 Python 解释器启动时创建,会一直保留,不被删除。模块的全局命名空间在模块定义被读入时创建,通常,模块命名空间也会一直保存到解释器退出。由解释器在最高层调用执行的语句,不管它是从脚本文件中读入还是来自交互式输入,都是 __main__ 模块的一部分,所以它们也拥有自己的命名空间。(内置命名也同样被包含在一个模块中,它被称作 __builtin__ 。)
第三:当调用函数时,就会为它创建一个局部命名空间,并且在函数返回或抛出一个并没有在函数内部处理的异常时被删除。 (实际上,用遗忘来形容到底发生了什么更为贴切。) 当然,每个递归调用都有自己的局部命名空间。
作用域是定义程序该如何搜索确切地“名字-对象”的名空间的层级关系。是一个 Python 程序可以直接访问命名空间的正文区域。 意思是一个对名称的错误引用会尝试在命名空间内查找。尽管作用域是静态定义,在使用时他们都是动态的。每次执行时,至少有四个命名空间可以直接访问的作用域嵌套在一起:
第一:innermost scope ,包含局部命名的使用域在最里面,首先被搜索;
第二:enclosing scope ,中层的作用域,是内层嵌套作用域搜索起点,包含非局部,但是也非全局的命名
第三:Global scope ,包含当前模块的全局命名
第四:Built-in scope ,包含内置命名的命名空间。
so,这么多的作用域,Python是按什么顺序搜索对应作用域的呢?著名的”LEGB-rule”,即scope的搜索顺序:Local -> Enclosing -> Global -> Built-in;当有一个变量在 local 域中找不到时,Python会找上一层的作用域,即 enclosing 域(该域不一定存在)。enclosing 域还找不到的时候,再往上一层,搜索模块内的 global 域。最后,会在 built-in 域中搜索。对于最终没有搜索到时,Python会抛出一个 NameError 异常。作用域可以嵌套。比如模块导入时。这也是为什么不推荐使用 from a_module import * 的原因,导入的变量可能被当前模块覆盖。下面是一个例子:
def outer():
a =
b = def inner():
print a
print b
b = inner()
if __name__=="__main__":
outer()
Traceback (most recent call last):
File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line , in <module>
outer()
File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line , in outer
inner()
File "E:/PycharmProjects/CodeStatisticsTools/test_namespaces.py", line , in inner
print b
UnboundLocalError: local variable 'b' referenced before assignment
如果去掉b = 4 就能正常运行,这是为啥呢?在没有b=4这行代码时,Python解释器执行到 inner() 中的 print b 时,发现有个变量 b 在当前作用域(local)中无法找到变量b,于是尝试从enclosing scope中查找,找到后就能正常打印了。加上这行代码后,在当前作用域找到了b ,但是变量 b 的赋值发生在 print 语句之后,于是抛出错误:变量在赋值前就被引用。赋值语句通常隐式地会创建一个局部(local)变量,即便该变量名已存在于赋值语句发生的上一层作用域中;
7.3 初始类以及一些说明
类定义最简单的形式如下:
class ClassName:
<statement-1>
.
.
.
<statement-N>
进入类定义部分后,会创建出一个新的命名空间,作为局部作用域——因此,所有的赋值成为这个新命名空间的局部变量。特别是函数定义在此绑定了新的命名。类定义完成时(正常退出),就创建了一个 类对象 。基本上它是对类定义创建的命名空间进行了一个包装;原始的局部作用域(类定义引入之前生效的那个)得到恢复,类对象在这里绑定到类定义头部的类名(例子中是 ClassName )。
类对象支持两种操作:属性引用和实例化。属性引用的使用和 Python 中所有的属性引用一样的标准语法:obj.name 。类对象创建后,类命名空间中所有的命名都是有效属性名。类的实例化使用函数符号。只要将类对象看作是一个返回新的类实例的无参数函数即可。如下所示:
class MyClass:
"""A simple example class"""
id = 12345
def __init__(self,realpart,imagpart):
self.r = realpart
self.i = imagpart
def f(self): return 'hello world'
if __name__=="__main__":
x = MyClass(3.0, -4.5)
那么 MyClass.id 和 MyClass.f 是有效的属性引用(MyClass.r不属于类对象的有效引用,属于实例的有效引用),分别返回一个整数和一个方法对象。也可以对类属性赋值,可以通过给 MyClass.id 赋值来修改它。MyClass()是一个新的类实例 并将该对象赋给局部变量 x 。类的实例化操作会自动为新创建的类实例调用 __init__() 方法。
按照定义,类中所有(用户定义)的函数对象对应它的实例中的方法。在例子中,x.f 是一个有效的方法引用,因为 MyClass.f 是一个函数。但 x.id不是,因为 MyClass.id 不是函数。不过 x.f 和 MyClass.f 不同--它是一个方法对象 ,不是一个函数对象。而且 x.f 是一个方法对象,它可以存储起来以后调用。下面的例子会不断的打印 hello world 。
xf = x.f
while True:
print xf()
7.4 继承
派生类的定义如下所示:
class DerivedClassName(BaseClassName):
<statement->
.
.
.
<statement-N>
命名 BaseClassName (示例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:
class DerivedClassName(modname.BaseClassName):
派生类的实例化没有什么特殊之处: DerivedClassName() (示列中的派生类)创建一个新的类实例。方法引用按如下规则解析:搜索对应的类属性,必要时沿基类链逐级搜索,如果找到了函数对象这个方法引用就是合法的。派生类可能会覆盖其基类的方法。因为方法调用同一个对象中的其它方法时没有特权,基类的方法调用同一个基类的方法时,可能实际上最终调用了派生类中的覆盖方法。派生类中的覆盖方法可能是想要扩充而不是简单的替代基类中的重名方法。有一个简单的方法可以直接调用基类方法,只要调用: BaseClassName.methodname(self, arguments)。
Python 有两个用于继承的函数:
- 函数 isinstance() 用于检查实例类型: isinstance(obj, int) 只有在 obj.__class__ 是 int 或其它从int 继承的类型
- 函数 issubclass() 用于检查类继承: issubclass(bool, int) 为 True ,因为 bool 是 int 的子类。但是, issubclass(unicode, str) 是 False ,因为 unicode 不是 str 的子类(它们只是共享一个通用祖先类 basestring )。
python学习笔记系列----(七)类的更多相关文章
- Python学习笔记(七)
Python学习笔记(七): 深浅拷贝 Set-集合 函数 1. 深浅拷贝 1. 浅拷贝-多层嵌套只拷贝第一层 a = [[1,2],3,4] b = a.copy() print(b) # 结果:[ ...
- python学习笔记系列----(一)python简介
一个月前,就按下决心要系统的学习下python了,虽然之前有学习过java,学习过c++,也能较为熟练的使用java做自动化测试看懂c++里的业务逻辑,但是实际上有那么多的东西自己还是不清楚,今天下定 ...
- Python基础笔记系列七:字符串定义和访问
本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! 字符串定义和访问 1.字符串基础 a.字符串可以用单引号.双引号.三引号( ...
- Python学习笔记系列
1.小甲鱼 python 学习系列笔记
- python学习笔记系列----(八)python常用的标准库
终于学到了python手册的最后一部分:常用标准库.这部分内容主要就是介绍了一些基础的常用的基础库,可以大概了解下,在以后真正使用的时候也能想起来再拿出来用. 8.1 操作系统接口模块:OS OS模块 ...
- [Python学习笔记][第七章Python文件操作]
2016/1/30学习内容 第七章 Python文件操作 文本文件 文本文件存储的是常规字符串,通常每行以换行符'\n'结尾. 二进制文件 二进制文件把对象内容以字节串(bytes)进行存储,无法用笔 ...
- python 学习笔记7(类/对象的属性;特性,__getattr__)
27. 属性的__dict__系统 1)对象的属性可能来自: 其类的定义,叫做类属性 继承父类的定义 该对象实例定义(初始化对象时赋值),叫做对象属性 2)对象的属性存储在对象的 __dict__ 属 ...
- python学习笔记系列----(二)控制流
实际开始看这一章节的时候,觉得都不想看了,因为每种语言都会有控制流,感觉好像我不看就会了似的.快速预览的时候,发现了原来还包含了对函数定义的一些描述,重点讲了3种函数形参的定义方法,章节的最后讲述了P ...
- Python学习笔记系列——函数
今年下半年的计划主要是Python和Mysql了,公司不方便看书和视频,就照着廖雪峰的Python网站开始看了.以下纯为个人笔记记录,若是想系统学习的小伙伴还是看这里的好一些,毕竟系统.https:/ ...
随机推荐
- Java_动态重新加载Class机制
Java动态重新加载Class 项目中使用到了动态重新加载Class的机制,作用是让一些代码上线之前可以在线上环境测试一下,当然,这是非常不好的测试机制,我刚来的时候也为这种机制感到惊讶—怎么可以在线 ...
- Struts2基础数据校验和框架校验
一:三种校验的方式 1.用validate()方法实现数据校验 2.用execute()方法实现数据校验 3.用validateXxx()方法实现数据校验 1.用validate()方法实现数据校验 ...
- Lua字符串库
1. 基础字符串函数: 字符串库中有一些函数非常简单,如: 1). string.len(s) 返回字符串s的长度: 2). string.rep(s,n) 返回字符串s重复n次的结 ...
- iOS 模仿一个小项目,总结一下里边的模块
ManoBoo: 参考链接:http://www.jianshu.com/p/fd4c46c31508 这个小的项目是参考ManoBoo的简书的,链接在上方,自己在仿做的过程中,也离不开Man ...
- Android-java基础内部类
@在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.下面就来了解下成员内部类,局部内部类,匿名内部类 的使用方法 1.成员内部类 成员内部类是最普通的内部类,它的定义为 ...
- 第一章-第十一题(请问 “软件” 和 “软件工程” 这些词汇是如何出现的 - 何时、何地、何人)--By 侯伟婷
从邹欣老师的<构建执法:现代软件工程>一书中,我们得到有关这些名词的起源的信息是软件工程的概念是1968年第一次提出的[1].而在一篇专访Margaret Hamilton的报道中,我们通 ...
- C#拾遗-接口与抽象类
抽象类中可以有构造函数(无参构造函数和有参构造函数)无参构造函数在子类实例化时被调用有参构造函数必须显示调用 抽象类中可以有抽象方法 但是不能有方法体,子类必须实现抽象方法子类必须重写抽象类中的抽象方 ...
- Maven项目WEB-INF/views无法引入js,css静态文件解决方法
web.xml针对文件后缀配置以下,对客户端请求的静态资源如图片.JS文件等的请求交由默认的servlet进行处理 <servlet-mapping> <servlet-name&g ...
- jdk(多版本)安装注意!
♣安装jdk和jre ♣jdk配置环境变量和测试 ♣安装多版本jdk和切换 ♣jdk下的jre和第二次安装的jre的区别 注意点: 1.jdk版本需要是64位 2.安装JDK 选择安装目录 安装过程中 ...
- 多个Excel文件快速导入到DB里面
1 . 文件比较多,需要把这么多的数据都导入到DB里面,一个个导入太慢了,能想到的是先把数据整个到一个Excel中,然后再导入 2. 第一步准备合并Excel,新建一个新的excel,命名为total ...