刚开始写Python脚本时,将简单的语句叠加在一起,结构性很差。前几天,有意识地用函数(结构化程序设计),但遇到一个问题:处理全局变量非常麻烦。用Python的对象可以很好解决这个问题,所以决定花点时间整理下Python面向对象的一些基本操作,以便日后查阅。
1. 类和对象
Python的类机制可以看成C++和Modula-3(我第一次听说,最大的特点是简单和安全)的混合,拥有所有面向对象编程语言的基本特性[1]:封装(encapsulation)、继承(inheritance)、多态(polymorphism)。
- the class inheritance mechanism allows multiple base classes
- a derived class can override any methods of its base class or classes
- a method can call the method of a base class with the same name.
1.1 一个实例
class Employee:
"""所有员工的基类""" # 类的描述信息,通过Employee.__doc__查看
empCount = 0 # 类变量,在该类的所有实例之间共享。访问该问题:Employee.empCount
__weight = 0 # 私有属性,在类外部无法直接进行访问。可以使用object._className__attrName访问属性
def __init__(self, name, weight): # 构造函数
self.name = name # 实例变量,实例之间独立
self.__weight = weight
Employee.empCount += 1
def __del__(self): # 析构函数
pass
def displayEmployee(self): # 方法
print("Name : %s" % self.name)
self.__displayWeight() # 调用类中的私有方法,slef.__private_methods
def __displayWeight(self): # 私有方法,不能在类地外部调用
print("Weight : %d" % self.__weight)
# 创建实例对象
emp = Employee("Zara")
# 访问属性
emp.displayEmployee()
# 访问私有属性
emp._Employee__wight
# 添加,删除,修改类的属性
emp.age = 7 # 添加一个 'age' 属性
emp.age = 8 # 修改 'age' 属性
del emp.age # 删除 'age' 属性
1.2 内置类属性[5]
__dict__
: 类的属性(包含一个字典,由类的数据属性组成)__doc__
:类的文档字符串__name__
: 类名,如class_name = self.__class__.__name__
__module__
: 类定义所在的模块(类的全名是__main__.className
,如果类位于一个导入模块mymod中,那么className.__module__
等于 mymod)__bases__
: 类的所有父类构成元素(包含了以个由所有父类组成的元组)
举例如下:
class Employee:
'所有员工的基类' # __doc__
empCount = 0
# Employee类属于的值如下:
Employee.__doc__: '所有员工的基类'
Employee.__name__: Employee
Employee.__module__: __main__
Employee.__bases__: ()
1.3 内置函数操作对象的属性
可以以下Python内建函数来操作对象的属性:
getattr(obj, name[, default])
: 访问对象的属性hasattr(obj,name)
: 检查是否存在一个属性setattr(obj,name,value)
: 设置一个属性。如果属性不存在,会创建一个新属性delattr(obj, name)
: 删除属性
2. 命名空间和作用域
2.1 命名空间
A namespace is a mapping from names to objects. Most namespaces are currently implemented as Python dictionaries. The important thing to know about namespaces is that there is absolutely no relation between names in different namespaces.
命名空间类型和生命周期:
- the set of built-in names,which is created when the Python interpreter starts up, and is never deleted
- the global names in a module,which is created when the module definition is read in; normally, module namespaces also last until the interpreter quits
- the local names in a function invocation, which is created when the function is called, and deleted when the function returns or raises an exception that is not handled within the function
命名空间的查找顺序:局部 –> 全局 –> 内置。若都没找到,就触发异常:NameError: name * is not defined
。一个错误的例子如下:
i=1
def func():
i=i+1 # 解释时,对i赋值,假定i为局部命名空间;但在运行时,发现i并没有在局部命名空间分配空间
func() # UnboundLocalError: local variable 'i' referenced before assignment
可以用内建函数globals()
和locals()
得到全局/局部的符号表,如下:
globals()
# Return a dictionary representing the current global symbol table. This is always the dictionary of the current module (inside a function or method, this is the module where it is defined, not the module from which it is called).
locals()
# Update and return a dictionary representing the current local symbol table. Free variables are returned by locals() when it is called in function blocks, but not in class blocks.
2.2 作用域
关于作用域,直接摘抄官方文档Scopes and Namespaces Example的例子:
Note how the local assignment (which is default) didn’t change scope_test’s binding of spam. The
nonlocal
assignment changed scope_test’s binding of spam, and theglobal
assignment changed the module-level binding.
实例如下:
def scope_test():
def do_local():
spam = "local spam" # local
def do_nonlocal():
nonlocal spam # nonlocal
spam = "nonlocal spam"
def do_global():
global spam # global
spam = "global spam"
spam = "test spam"
do_local()
print("After local assignment:", spam) # After local assignment: test spam
do_nonlocal()
print("After nonlocal assignment:", spam) # After nonlocal assignment: nonlocal spam
do_global()
print("After global assignment:", spam) # After global assignment: nonlocal spam
scope_test()
print("In global scope:", spam) # In global scope: global spam
3. 抽象、继承、多态
# 1.encapsulation
class MyClass: # MyClass.i; f=MyClass.f, f()
i = 12345
def f(self):
return 'hello world'
# 2.inheritance
class DerivedClassName(BaseClassName): # class DerivedClassName(modname.BaseClassName):
# multiple inheritance
class DerivedClassName(Base1, Base2, Base3):
# 3.polymorphism
4. 其他
# Standard boilerplate to call the main() function to begin the program.
# call a main() function when the module is run directly, but not when the module is imported by some other module.
if __name__ == '__main__':
main()
参考资料:
[1] 博文《优秀Python学习资源收集汇总(强烈推荐)》
[2] Key differences between Python 2.7.x and Python 3.x
[3] Should I use Python 2 or Python 3 for my development activity?
[4] The Python Tutorial » Classes (python3)
[5] w3school.cc : Python 面向对象
[6] 博文:Python命名空间的本质