刚开始写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 the global 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命名空间的本质

本文系Spark & Shine原创,转载需注明出处本文最近一次修改时间 2022-03-18 20:22

results matching ""

    No results matching ""