循序渐进Python3(六) -- 初识内置变量、反射、递归

#python用下划线作为变量前缀和后缀指定特殊变量。稍后我们会发现,  
#对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的。  
#我们总结一下Python中下划线的特殊用法  
#_xxx:不用'from module import *'导入  
#__xxx__:系统定义的名字  
#__xxx:类中的私有变量名

1.__name__

#__name__指示模块应该如何被加载
#由于主程序代码无论模块是被直接执行都会运行,我们必须知道模块如何决定运行方向。
#一个应用程序可能需要导入另个引用程序的一个模块,以便重用一些有用的代码。
#这种情况下,你只想访问那些位于其它应用程序中的代码,而不是像运行那个应用程序。
#因此一个问题产生了,"Python"是否有一种方法能在运行时检测该模块是被导入还是直接被执行呢?
#__name__系统变量就是正确的答案
#如果模块是被导入,__name__的值为模块名字
#如果模块是被直接执行,__name__的值为'__main__'

if __name__ == '__main__':
    main()

以上代码表示只有在此文件执行时才会调用main()函数,其他时候则不会执行。

2.__file__

用__file__ 来获得脚本所在的路径是比较方便的,但这可能得到的是一个相对路径,比如在脚本test.py中写入:

#!/usr/bin/env python
print __file__

按相对路径./test.py来执行,则打印得到的是相对路径,
按绝对路径执行则得到的是绝对路径。
而按用户目录来执行(~/practice/test.py),则得到的也是绝对路径(~被展开)

所以为了得到绝对路径,我们需要 os.path.realpath(__file__)。

3.__doc__

文档字符串。一般而言,是对函数/方法/模块所实现功能的简单描述。但当指向具体对象时,会显示此对象从属的类型的构造函数的文档字符串。


'''
本文件__doc__输出
'''
if __name__=='__main__':
print(__doc__) # print globals()['__doc__']
Login_User = {"is_login":False} def check_login(func):
"""
此处为函数__doc__变量输出值
:param func:
:return:
"""
def chk_inner(*args,**kwargs):
if Login_User["is_login"]:
func()
else:
print('请登录')
return chk_inner
print(check_login.__doc__) # 输出结果
本文件__doc__输出 此处为函数__doc__变量输出值
:param func:
:return:

4.__package__  和 __name__ 类似,当自己调用的时候返回none,当通过导入操作后输出文件所在的目录名

import os,sys
from lib import class6
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
print(__package__)
print(class6.__package__) # 输出
None
lib

hasattr(object, name)

说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的)。

参数object:对象。

参数name:特性名称。

示例:

>>> hasattr(list, 'append')
True >>> hasattr(list, 'add')
False
getattr()
getattr()函数是Python自省的核心函数,具体使用大体如下:

获取对象引用getattr
Getattr用于返回一个对象属性,或者方法


    1. class A:
    2. def __init__(self):
    3. self.name = 'zhangjing'
    4.     #self.age='24'
    5. def method(self):
    6. print"method print"
    7. Instance = A()
    8. print getattr(Instance , 'name, 'not find') #如果Instance 对象中有属性name则打印self.name的值,否则打印'not find'
    9. print getattr(Instance , 'age', 'not find')   #如果Instance 对象中有属性age则打印self.age的值,否则打印'not find'
    10. print getattr(a, 'method', 'default')
    11. #如果有方法method,否则打印其地址,否则打印default
    12. print getattr(a, 'method', 'default')()
    13. #如果有方法method,运行函数并打印None否则打印default
 

sys.modules

与其它任何 Python 的东西一样,模块也是对象。只要导入了,总可以用全局 dictionary sys.modules 来得到一个模块的引用。
 是一个字典,它包含了从 Python 开始运行起,被导入的所有模块。键字就是模块名,键值就是模块对象。请注意除了你的程序
导入的模块外还有其它模块。Python 在启动时预先装入了一些模块,如果你在一个 Python IDE 环境下,sys.modules 包含了你
在 IDE 中运行的所有程序所导入的所有模块。 反射

反射的作用就是列出对象的所有属性和方法,反射就是告诉我们,这个对象到底是什么,提供了什么功能 。

举个例子:

>>> import json
>>> dir(json)             
['JSONDecoder', 'JSONEncoder', '__all__', '__author__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__version__', '_default_decoder', '_default_encoder', 'decoder', 'dump', 'dumps', 'encoder', 'load', 'loads', 'scanner']
>>>

如上所看,dir 是一个内置的 反射函数 ,可以列出对象的属性和方法。

再看另外一个内置的方法 :getattr

>>> getattr(json,'encoder')
<module 'json.encoder' from '/usr/lib/python2.7/json/encoder.pyc'>
>>> getattr(json,'load')
<function load at 0x7f66af736140>
>>>

可以取出指定属性

再看另外一个方法 :callable

>>> callable(getattr(json,'load'))
True
>>> callable(getattr(json,'encoder'))
False
>>>

检查属性是否是可以调用的函数 。

了解基础之后,就需要考虑,它存在的价值在哪里了?

考虑一个应用的场景:IDE的自动补全。

在IDE中可以这样做:

>>> methodList = [attr for attr in dir(json)  if callable(getattr(json,attr))]
>>> methodList
['JSONDecoder', 'JSONEncoder', 'dump', 'dumps', 'load', 'loads']
>>>

>>> getattr(json,'load').__doc__
'Deserialize ``fp`` (a ``.read()``-supporting file-like object containing\n    a JSON document) to a Python object.\n\n    If the contents of ``fp`` is encoded with an ASCII based encoding other\n    than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must\n    be specified. Encodings that are not ASCII based (such as UCS-2) are\n    not allowed, and should be wrapped with\n    ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode``\n    object and passed to ``loads()``\n\n    ``object_hook`` is an optional function that will be called with the\n    result of any object literal decode (a ``dict``). The return value of\n    ``object_hook`` will be used instead of the ``dict``. This feature\n    can be used to implement custom decoders (e.g. JSON-RPC class hinting).\n\n    ``object_pairs_hook`` is an optional function that will be called with the\n    result of any object literal decoded with an ordered list of pairs.  The\n    return value of ``object_pairs_hook`` will be used instead of the ``dict``.\n    This feature can be used to implement custom decoders that rely on the\n    order that the key and value pairs are decoded (for example,\n    collections.OrderedDict will remember the order of insertion). If\n    ``object_hook`` is also defined, the ``object_pairs_hook`` takes priority.\n\n    To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``\n    kwarg; otherwise ``JSONDecoder`` is used.\n\n    '
>>>

大概就明白了 反射的功能了。

#-*- coding:utf8 -*-

class Obj :
    """ An object that use reflection """

def __init__(self,name):
        """ 构造函数 """
        self.name = name

def echo_methods(self):
        """ 输出类中所有的方法,以及doc 文档 """
        print "\n Method List: "
        for attrName in dir(self):
            attr = getattr(self,attrName)
            if callable(attr):
                print attrName,"():",attr.__doc__

def echo_attributes(self):
        print "\n Attributes"

for name in dit(self):
            attr = getattr(self,attr)
            if not callable(attr):
                print name,":",attr

obj = Obj("testObject")
obj.echo_methods()

ubuntu@yee:/tmp$ python ref.py

Method List:
__init__ ():  构造函数
echo_attributes (): None
echo_methods ():  输出类中所有的方法,以及doc 文档

可以看到,通过反射,我们可以知道类中所有的方法以及方法的属性和注释文档信息。

内置函数__import__

我们知道import语句是用来导入外部模块的,当然还有from...import...也可以,但是其实import实际上是使用builtin函数__import__来工作的。
    在一些程序中,我们可以动态地去调用函数,如果我们知道模块的名称(字符串)的时候,我们可以很方便的使用动态调用。

  1. import glob,os
  2. modules = []
  3. for module_file in glob.glob("*-plugin.py"):
  4. try:
  5. module_name,ext = os.path.splitext(os.path.basename(module_file))
  6. module = __import__(module_name)
  7. modules.append(module)
  8. except ImportError:
  9. pass #ignore broken modules
  10. #say hello to all modules
  11. for module in modules:
  12. module.hello()
 导入其他目下的模块:
   使用参数  fromlist=True,进行字符串拼接。
 

递归

递归(recursion):程序调用自身的编程技巧。
  递归满足2个条件:
    1)有反复执行的过程(调用自身)
    2)有跳出反复执行过程的条件(递归出口)

(1)阶乘
         n! = n * (n-1) * (n-2) * ...* 1(n>0)

def recursion(x):
if x == 1:
y = 1
else:
y = x * recursion(x - 1)
return y print(recursion(5))

(2)斐波那契数列

斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、……

这个数列从第三项开始,每一项都等于前两项之和。

有趣的兔子问题:

循序渐进Python3(六) -- 初识内置变量、反射、递归

一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?

分析如下:

第一个月小兔子没有繁殖能力,所以还是一对;

两个月后,生下一对小兔子,总数共有两对;

三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,总数共是三对;

…… 

依次类推可以列出下表:

循序渐进Python3(六) -- 初识内置变量、反射、递归

def fibo(n):
if n == 0:
return 0
if n == 1:
return 1
if n > 1:
return fibo(n - 1) + fibo(n - 2) print(fibo(4))
 
 
 
 
上一篇:js遍历jsonTree


下一篇:ROC AUC