Python学习笔记 === python自省

  1. 示例代码:
    from types import BuiltinFunctionType, BuiltinMethodType, \
            FunctionType, MethodType, ClassType
       
    def help(object, spacing=10, collapse=1):
        """Print method and doc string.
        Takes module, class, list, dictionary, or string."""
        typeList = (BuiltinFunctionType, BuiltinMethodType, FunctionType. MethodType, ClassType)
        methodList = [method for method in dir(object) if type(getattr(object, method)) in typeList]
        processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s:s)
        print "\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) for method i    n methodList])
      
        if __name__ == "__main__":
            print help.__doc__
  2. 自省综述:根据上边示例代码分析
    • 这个模块有一个函数,help, 有三个参数object, spacing, collapse, 后两个是可选参数
    • 函数的代码是缩排的,help函数有一个多行的文档字符串,并没有返回值,因为函数只使用他的效果并非它的值
    • __name__技巧只是用于测试模块,在别的程序引入这个模块的时候不会引起冲突,
    • help函数的设计是为了在ide环境下是用的,接受任何拥有函数或者方法的对象,打印出对象所有的函数和文档字符串
    • 用法举例
      >>> from apihelper import help
      >>> li = []
      >>> help(li)
      append     L.append(object) -- append object to end
      count      L.count(value) -> integer -- return number of occurrences of value
      extend     L.extend(list) -- extend list by appending list elements
      index      L.index(value) -> integer -- return index of first occurrence of value
      insert     L.insert(index, object) -- insert object before index
      pop        L.pop([index]) -> item -- remove and return item at index (default last)
      remove     L.remove(value) -- remove first occurrence of value
      reverse    L.reverse() -- reverse *IN PLACE*
      sort       L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
    • 高级用法:注意参数变化
      >>> import odbchelper
      >>> help(odbchelper)
      buildConnectionString Build a connection string from a dictionary Returns string.
      >>> help(odbchelper, 30)
      buildConnectionString          Build a connection string from a dictionary Returns string.
      >>> help(odbchelper, 30, 0)
      buildConnectionString          Build a connection string from a dictionary
          
          Returns string.
  3. 导入模块:两种导入模块的方法
    • 基本的from module import 语法
      from types import BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, ClassType

      注意:与module导入方法类似,但是,导入模块types的属性和方法被直接导入到局部名字空间中,使用的时候不用模块的名字来限定;

    • import 和 from module import 对比
      >>> import types        #只是有每个对象类型的属性
      >>> types.FunctionType  #必须用module 名称来限定
      <type 'function'>
      >>> FunctionType  #没有定义在当前的名字空间中,只是存在与types的上下问环境当中
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      NameError: name 'FunctionType' is not defined
      >>> from types import FunctionType
      >>> FunctionType
      <type 'function'>
    • 什么时候要用from module import
      • 如果想经常存取模块的属性和方法,但是不想一遍遍的敲入模块名称
      • 想选择性的导入某些属性和方法,不想要其他的
      • 如果模块包含的属性或者方法和你自己的某个模块名字相同,只能用import module
  4. 可选和定名参数(指定参数名字):
    • help的合法调用
      help(odbchelper)                       
      help(odbchelper, 12)                 
      help(odbchelper, collapse=0)    #spacing 缺省      
      help(spacing=15, object=odbchelper) #object可以定名,任意顺序都行
  5. type,str,dir和其他内置函数:
    • type:返回任意对象的数据类型
      >>> type("333")
      <type 'str'>
      >>> li=[]
      >>> type(li)
      <type 'list'>
      >>> import odbchelper
      >>> type(odbchelper)
      <type 'module'>
      >>> import types 
      >>> type(odbchelper) == types.ModuleType
      True
    • str:强制将数据转换为字符串
      >>> str(1)
      '1'
      >>> ho = ["sd", 1, "sdd"]      #可以工作于任何类型的任何对象
      >>> str(ho)
      "['sd', 1, 'sdd']"
      >>> str(odbchelper) #模块的字符串表示包含了模块在磁盘上的路径
      "<module 'odbchelper' from 'odbchelper.pyc'>"
      >>> str(None)  #python空值 返回字符串 很重要???
      'None'
    • dir:help函数的核心,返回任意一个对象的属性和方法的列表:模块,函数,字符串,列表,字典... 相当多的东西
      >>> li = []
      >>> dir(li)           
      ['append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
      >>> d = {}
      >>> dir(d)            
      ['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'setdefault', 'update', 'values']
      >>> import odbchelper
      >>> dir(odbchelper)     #模块,返回模块中定义的所有东西,包括自定义的
      ['__builtins__', '__doc__', '__file__', '__name__', 'buildConnectionString']
    • 内置属性和函数
      >>> from apihelper import help
      >>> help(__builtins__, 20)
      ArithmeticError      Base class for arithmetic errors.
      AssertionError       Assertion failed.
      AttributeError       Attribute not found.
      EOFError             Read beyond end of file.
      EnvironmentError     Base class for I/O related errors.
      Exception            Common base class for all exceptions.
      FloatingPointError   Floating point operation failed.
      IOError              I/O operation failed.
      
      [...snip...]
      ???
    • 综合:type dir str, 以及所有其他的python内置函数一样被组合进入一个名字叫做__builtins__的特别模块中,python启动的时候自动from __builtins__ import * 可以直接使用,好处是,可以通过得到builtins的信息,作为一个组,存取所有内置的函数和属性,help函数实现了那个功能。???
  6. 使用getattr得到对象的各种引用:可以得到一个直到运行时候才知道的函数的引用???
    • getattr介绍
      >>> li=["larry", "curly"]                
      >>> li.pop              #得到列表的pop方法的一个引用,并不是调用pop方法,而是方法本身
      <built-in method pop of list object at 0xb7724f4c>
      >>> getattr(li, "pop")   #也返回pop方法的一个引用,但是,方法的名字被指定为一个字符串参数,getattr可以返回任意对象的任意属性,在这个例子中,对象是列表,属性是pop方法
      <built-in method pop of list object at 0xb7724f4c>
      >>> getattr(li, "append")("moe")  #li.append("moe") 返回值是方法,没有直接调用方法,而是把函数名当作字符串来指定。
      >>> li
      ['larry', 'curly', 'moe']
      >>> getattr({}, "clear")  #也可以用给字典
      <built-in method clear of dict object at 0x828e604>
      >>> getattr((), "pop")     #理论上可以用个序列,但是序列没有方法,所以不管给出什么属性名,getattr都将引发一个异常,
      Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
      AttributeError: 'tuple' object has no attribute 'pop'
    • 用于apihelper.py, 不仅可以用于内置数据类型,也可以用于模块
      >>> import odbchelper
      >>> odbchelper.buildConnectionString         #返回在odbchelper模块中的bulidConnectionString函数的引用
      <function buildConnectionString at 0x820bb8c>
      >>> getattr(odbchelper, "buildConnectionString") #使用getattr,我们可以得到同一函数的同一引用。 相当于object.attribute. 如果object是一个模块,那么attribute可以是模块中的任何东西:函数,类,或者全局变量。
      <function buildConnectionString at 0x820bb8c>
      >>> object = odbchelper
      >>> method = "buildConnectionString"
      >>> getattr(object, method)  #help函数中用到的东西,method字符串是方法或者函数的名字。
      <function buildConnectionString at 0x820bb8c>
      >>> type(getattr(object, method))  本地方method是一个函数的名字
      <type 'function'>
      >>> import types
      >>> type(getattr(object, method)) == types.FunctionType
      True
  7. 过滤列表:python强大的列表映射到其他列表的能力,同一种过滤机制合并,列表中的某个元素被映射,其他的都忽略掉。
    • 列表过滤语法
      [mapping-expression for element in source-list if filter-expression]

      以if开头的就是过滤表达式,可以是任意真假的表达式,任何对于过滤表达式计算出真值的元素将包括在映射中,其他元素忽略掉,他们不会出现在映射表达式中,也不包括在输出列表中。

    • 列表过滤介绍
      >>> li = ["a", "mpilgrim", "foo", "b", "c", "b", "d", "d"]
      >>> [elem for elem in li if len(elem) > 1]         
      ['mpilgrim', 'foo']
      >>> [elem for elem in li if elem != "b"]        # 过滤掉特殊值b,每次b出来过滤表达式都不成立
      ['a', 'mpilgrim', 'foo', 'c', 'd', 'd']
      >>> [elem for elem in li if li.count(elem) == 1] #count返回的是一个元素出现的次数 
      ['a', 'mpilgrim', 'foo', 'c']
    • apihelper.py中过滤列表
      typeList = (BuiltinFunctionType, BuiltinMethodType, FunctionType, MethodType, ClassType)
      methodList = [method for method in dir(object) if type(getattr(objec, method)) in typeList]

      看上去挺复杂,但是基本结构是一样的。整个表达式返回一个列表,列表赋给变量methodList,前半部分是列表映射部分,dir(object)返回一个对象的属性和方法的列表,就是正在映射的列表。表达式getattr(object, method)返回一个函数对象,method是模块中的函数名字,这个表达式接受一个object对象,获得它的属性方法,和一些其他东西的名字列表,然后过滤列表,执行过滤通过得到每个属性方法函数的名字,让后通过getattr函数得到指向实际东西的引用。然后用type检查对象类型,我们关心方法和函数,不关心其他属性。classType对象现在不用担心,后边将讨论python的类。

  8. and-or技巧:要对比bool?a:b 理解其如何工作
    >>> a = "first"
    >>> b = "second"
    >>> 1 and a or b                   #类似c
    'first'
    >>> 0 and a or b                   #类似c
    'second'
    >>> a = ""
    >>> 1 and a or b                    #区别,看成纯粹的布尔逻辑去分析。
    'second'
    
    
    >>> a = ""
    >>> b = "second"
    >>> 1 and a or b
    'second'
    >>> 0 and a or b
    'second'
    >>> (1 and [a] or [b])[0]  [a] 是一个非空列表 永远为真,
    ''

    Python 中很多时候,不允许使用if语句,一个负责的的程序猿应该将and or 技巧封装成函数:

    def choose(bool, a, b):
        return (bool and [a] or [b])[0]

    ???

  9. 使用lambda函数:快速定义单行的最小函数,可以被用在任何需要函数的地方,函数的语法通常与其他函数有点不同???
    • lambda函数介绍
      >>> def f(x):
      ...     return x*2
      ... 
      >>> f(2)
      4
      >>> g = lambda x: x*2  #lambda函数, 没有小括号,return是默认的,函数没有名字。只有将它赋值给变量的变量名g
      >>> g(3)
      6
      >>> (lambda x: x*2)(3)     #可以不赋值给一个变量然后使用它,证明是一个内联函数
      6

      可以接收任意多个参数(包括可选参数)值并且返回单个表达式的值的函数,lambda函数不能包括命令,表达式不能超过一个,不要赛入过多东西。

      lambda函数是风格问题,不一定非要使用,许多小的一行代码不会弄乱我的代码,用在需要特殊封装的,非重用的代码上。

    • 例子中的lambda函数
      processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

      lambda函数在一个布尔环境下总为真,并不意味着不能返回假值,函数本身总是真,返回值可以任何值。

    • split不带参数:上边式子中不带参数
      >>> s = "this   is\na\ttest"  
      >>> print s
      this   is
      a    test
      >>> print s.split() # split不带参数按空白进行分割!!!          
      ['this', 'is', 'a', 'test']
      >>> print " ".join(s.split()) #将空白统一化!!!
      'this is a test'
    • 将函数赋给一个变量
      processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)

      processFunc现在是一个函数,但是函数为哪一个要看collapse的值。如果为真processFunc(string)将压缩空白,否则,将返回未改变的参数。

    • 注意:其他不健壮的语言实现它,可能创建一个函数,它接收一个字符串和一个collapse函数,使用一个If语句来判断是否需要压缩空白或者不压缩,然后返回相应的值,但是这样效率比较低,每次调用它,不得不再给出想要的东西之前,判断是否空白。在python中,可以将这种判断逻辑拿到函数之外,定义一个裁剪过的函数lambda来给出确切的(唯一的)你想要的。这样做更有效率更漂亮,并且更少导致那些令人讨厌的错误???
  10. 全部放在一起:所有的多米诺骨牌拼接到一起了,然后将它推倒吧。
    • 最后一行的内容
print "\n".join(["%s %s" % (method.ljust(spacing), processFunc(str(getattr(object, method).__doc__))) for method in methodList])
    • 最后一句告诉我们这是一个列表映射,methodLIst是一个在object中所有我们关心的方法的列表。我们用method遍历列表
    • 动态得到文档字符串
      >>> import odbchelper  
      >>> object = odbchelper        #object是我们要得到的帮助的对象                   
      >>> method = 'buildConnectionString'      #method 是当前方法的名字
      >>> getattr(object, method)               #得到在object模块中对于method函数的一个引用
      <function buildConnectionString at 010D6D74>
      >>> print getattr(object, method).__doc__   #打印文档字符串
      Build a connection string from a dictionary of parameters.
      
          Returns string.
      
      #至于str 是一个 内置函数,强制转换数据,但是不是每个函数都有文档字符串,如果没有的话,__doc__属性是None.
    • 为什么对一个文档字符串使用str
      >>>{}.keys__doc__
      >>>{}.keys__doc__ == None
      1
      >>>str({}.keys__doc__)  #使用str函数就接收了空值,返回它的字符串表示
      None

      然后保证有了字符串,传递字符串给processFunc,这个函数定义了一个要不要压缩空白或者不压缩,因为process假定一个字符串参数,并且调用了split方法,如果传给的是方法None,而不是字符串,函数就会失败了。

    • ljust方法介绍
      >>>s = "build"
      >>>s.ljust(30) #用空格填充到指定长度,这样就可以继续对齐了
      "build        "
      >>>s.ljust(2) #少于字符串的话 返回原字符串
      "build"
    • 打印列表
      >>>li=['a','b']
      >>>print "\n".join(li)   # 一个有用的调试技巧

11,小结

    • apihelper.py代码和输出
      # 代码
      from types import BiultinFunctionType, BulitinMethodType, FunctionType, MethodType, ClassType
      
      def help(object, collapse=1, spacing=10):
          ""Print methods and doc string.
          Take module, class, list, dictionary, or string."""
          typeList = (BiultinFunctionType, BulitinMethodType, FunctionType, MethodType, ClassType)
          methodList = [method for method in dir(object) if type(getattr(object, emthod)) in typeList]
          processFunc = collapse and (lambda s: " ".join(split())) or (lambda s: s)
          print "\n".join(["%s %s" % (method.ljust(spacing),  processFunc(str(getattr(object, method).__doc__))) for method in methodList])
      
      if __name__ == "__main__":
          print help.__doc__
      
      # 输出
      >>> from apihelper import help
      >>> li = [ ]
      >>>help(li)
      append     L.append(object) -- append object to end
      count      L.count(value) -> integer -- return number of occurrences of value
      extend     L.extend(list) -- extend list by appending list elements
      index      L.index(value) -> integer -- return index of first occurrence of value
      insert     L.insert(index, object) -- insert object before index
      pop        L.pop([index]) -> item -- remove and return item at index (default last)
      remove     L.remove(value) -- remove first occurrence of value
      reverse    L.reverse() -- reverse *IN PLACE*
      sort       L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
    • 自我完成作业
      • 选用Import或者from module import导入模块
      • 可选和定名参数定义和调用函数
      • str强制转换为字符串表达式
      • 使用getattr动态函数得到函数和其他的什么引用
      • 扩展映射列表进行列表过滤
      • and-or的技巧的应用
      • 定义lambda函数
      • 将函数赋值给变量,然后通过引用变量调用函数。这种思考方式会提高对python的理解力???

可通过本人转载的“Django实战系列”进行django的进一步学习;另外,实战系列的源代码下载地址:在实战系列文章中留言写下邮箱地址,一天内会发送给你全部源代码。

posted @ 2012-10-27 18:15  事件轮询,回不到过去  阅读(4477)  评论(2编辑  收藏  举报