循序渐进Python3(六) -- 初识内置变量、反射、递归
2016-08-10 10:40
387 查看
#python用下划线作为变量前缀和后缀指定特殊变量。稍后我们会发现,
#对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的。
#我们总结一下Python中下划线的特殊用法
#_xxx:不用'frommoduleimport*'导入
#__xxx__:系统定义的名字
#__xxx:类中的私有变量名
1.__name__
#__name__指示模块应该如何被加载
#由于主程序代码无论模块是被直接执行都会运行,我们必须知道模块如何决定运行方向。
#一个应用程序可能需要导入另个引用程序的一个模块,以便重用一些有用的代码。
#这种情况下,你只想访问那些位于其它应用程序中的代码,而不是像运行那个应用程序。
#因此一个问题产生了,"Python"是否有一种方法能在运行时检测该模块是被导入还是直接被执行呢?
#__name__系统变量就是正确的答案
#如果模块是被导入,__name__的值为模块名字
#如果模块是被直接执行,__name__的值为'__main__'
if__name__=='__main__':
main()
以上代码表示只有在此文件执行时才会调用main()函数,其他时候则不会执行。
2.__file__
用__file__来获得脚本所在的路径是比较方便的,但这可能得到的是一个相对路径,比如在脚本test.py中写入:
#!/usr/bin/envpython
print__file__
按相对路径./test.py来执行,则打印得到的是相对路径,
按绝对路径执行则得到的是绝对路径。
而按用户目录来执行(~/practice/test.py),则得到的也是绝对路径(~被展开)
所以为了得到绝对路径,我们需要os.path.realpath(__file__)。
3.__doc__
文档字符串。一般而言,是对函数/方法/模块所实现功能的简单描述。但当指向具体对象时,会显示此对象从属的类型的构造函数的文档字符串。
'''
本文件__doc__输出
'''
if__name__=='__main__':
print(__doc__)
#printglobals()['__doc__']
Login_User={"is_login":False}
defcheck_login(func):
"""
此处为函数__doc__变量输出值
:paramfunc:
:return:
"""
defchk_inner(*args,**kwargs):
ifLogin_User["is_login"]:
func()
else:
print('请登录')
returnchk_inner
print(check_login.__doc__)
#输出结果
本文件__doc__输出
此处为函数__doc__变量输出值
:paramfunc:
:return:
4.__package__和__name__类似,当自己调用的时候返回none,当通过导入操作后输出文件所在的目录名
importos,sys
fromlibimportclass6
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
print(__package__)
print(class6.__package__)
#输出
None
lib
参数object:对象。
参数name:特性名称。
示例:
获取对象引用getattr
Getattr用于返回一个对象属性,或者方法
classA:
def__init__(self):
self.name='zhangjing'
#self.age='24'
defmethod(self):
print"methodprint"
Instance=A()
printgetattr(Instance,'name,'notfind')#如果Instance对象中有属性name则打印self.name的值,否则打印'notfind'
printgetattr(Instance,'age','notfind')#如果Instance对象中有属性age则打印self.age的值,否则打印'notfind'
printgetattr(a,'method','default')
#如果有方法method,否则打印其地址,否则打印default
printgetattr(a,'method','default')()
#如果有方法method,运行函数并打印None否则打印default
反射的作用就是列出对象的所有属性和方法,反射就是告诉我们,这个对象到底是什么,提供了什么功能。
举个例子:
>>>importjson
>>>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')
<functionloadat0x7f66af736140>
>>>
可以取出指定属性
再看另外一个方法:callable
>>>callable(getattr(json,'load'))
True
>>>callable(getattr(json,'encoder'))
False
>>>
检查属性是否是可以调用的函数。
了解基础之后,就需要考虑,它存在的价值在哪里了?
考虑一个应用的场景:IDE的自动补全。
在IDE中可以这样做:
>>>methodList=[attrforattrindir(json)ifcallable(getattr(json,attr))]
>>>methodList
['JSONDecoder','JSONEncoder','dump','dumps','load','loads']
>>>
>>>getattr(json,'load').__doc__
'Deserialize``fp``(a``.read()``-supportingfile-likeobjectcontaining\naJSONdocument)toaPythonobject.\n\nIfthecontentsof``fp``isencodedwithanASCIIbasedencodingother\nthanutf-8(e.g.latin-1),thenanappropriate``encoding``namemust\nbespecified.EncodingsthatarenotASCIIbased(suchasUCS-2)are\nnotallowed,andshouldbewrappedwith\n``codecs.getreader(fp)(encoding)``,orsimplydecodedtoa``unicode``\nobjectandpassedto``loads()``\n\n``object_hook``isanoptionalfunctionthatwillbecalledwiththe\nresultofanyobjectliteraldecode(a``dict``).Thereturnvalueof\n``object_hook``willbeusedinsteadofthe``dict``.Thisfeature\ncanbeusedtoimplementcustomdecoders(e.g.JSON-RPCclasshinting).\n\n``object_pairs_hook``isanoptionalfunctionthatwillbecalledwiththe\nresultofanyobjectliteraldecodedwithanorderedlistofpairs.The\nreturnvalueof``object_pairs_hook``willbeusedinsteadofthe``dict``.\nThisfeaturecanbeusedtoimplementcustomdecodersthatrelyonthe\norderthatthekeyandvaluepairsaredecoded(forexample,\ncollections.OrderedDictwillremembertheorderofinsertion).If\n``object_hook``isalsodefined,the``object_pairs_hook``takespriority.\n\nTouseacustom``JSONDecoder``subclass,specifyitwiththe``cls``\nkwarg;otherwise``JSONDecoder``isused.\n\n'
>>>
大概就明白了反射的功能了。
#-*-coding:utf8-*-
classObj:
"""Anobjectthatusereflection"""
def__init__(self,name):
"""构造函数"""
self.name=name
defecho_methods(self):
"""输出类中所有的方法,以及doc文档"""
print"\nMethodList:"
forattrNameindir(self):
attr=getattr(self,attrName)
ifcallable(attr):
printattrName,"():",attr.__doc__
defecho_attributes(self):
print"\nAttributes"
fornameindit(self):
attr=getattr(self,attr)
ifnotcallable(attr):
printname,":",attr
obj=Obj("testObject")
obj.echo_methods()
ubuntu@yee:/tmp$pythonref.py
MethodList:
__init__():构造函数
echo_attributes():None
echo_methods():输出类中所有的方法,以及doc文档
可以看到,通过反射,我们可以知道类中所有的方法以及方法的属性和注释文档信息。
在一些程序中,我们可以动态地去调用函数,如果我们知道模块的名称(字符串)的时候,我们可以很方便的使用动态调用。
Python代码
importglob,os
modules=[]
formodule_fileinglob.glob("*-plugin.py"):
try:
module_name,ext=os.path.splitext(os.path.basename(module_file))
module=__import__(module_name)
modules.append(module)
exceptImportError:
pass#ignorebrokenmodules
#sayhellotoallmodules
formoduleinmodules:
module.hello()
导入其他目下的模块:
使用参数fromlist=True,进行字符串拼接。
递归满足2个条件:
1)有反复执行的过程(调用自身)
2)有跳出反复执行过程的条件(递归出口)
(1)阶乘
n!=n*(n-1)*(n-2)*...*1(n>0)
defrecursion(x):
ifx==1:
y=1
else:
y=x*recursion(x-1)
returny
print(recursion(5))
(2)斐波那契数列
斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、……
这个数列从第三项开始,每一项都等于前两项之和。
有趣的兔子问题:
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
分析如下:
第一个月小兔子没有繁殖能力,所以还是一对;
两个月后,生下一对小兔子,总数共有两对;
三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,总数共是三对;
……
依次类推可以列出下表:
deffibo(n):
ifn==0:
return0
ifn==1:
return1
ifn>1:
returnfibo(n-1)+fibo(n-2)
print(fibo(4))
#对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的。
#我们总结一下
#_xxx:不用'frommoduleimport*'导入
#__xxx__:
#__xxx:类中的私有变量名
1.__name__
#__name__指示模块应该如何被加载
#由于主程序代码无论模块是被直接执行都会运行,我们必须知道模块如何决定运行方向。
#一个应用程序可能需要导入另个引用程序的一个模块,以便重用一些有用的代码。
#这种情况下,你只想访问那些位于其它应用程序中的代码,而不是像运行那个应用程序。
#因此一个问题产生了,"Python"是否有一种方法能在运行时检测该模块是被导入还是直接被执行呢?
#__name__系统变量就是正确的答案
#如果模块是被导入,__name__的值为模块名字
#如果模块是被直接执行,__name__的值为'__main__'
if__name__=='__main__':
main()
以上代码表示只有在此文件执行时才会调用main()函数,其他时候则不会执行。
2.__file__
用__file__来获得脚本所在的路径是比较方便的,但这可能得到的是一个相对路径,比如在脚本test.py中写入:
#!/usr/bin/envpython
print__file__
按相对路径./test.py来执行,则打印得到的是相对路径,
按绝对路径执行则得到的是绝对路径。
而按用户目录来执行(~/practice/test.py),则得到的也是绝对路径(~被展开)
所以为了得到绝对路径,我们需要os.path.realpath(__file__)。
3.__doc__
文档字符串。一般而言,是对函数/方法/模块所实现功能的简单描述。但当指向具体对象时,会显示此对象从属的类型的构造函数的文档字符串。
4.__package__和__name__类似,当自己调用的时候返回none,当通过导入操作后输出文件所在的目录名
hasattr(object,name)
说明:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect,name)是否抛出异常来实现的)。参数object:对象。
参数name:特性名称。
示例:
>>>hasattr(list,'append') True>>>hasattr(list,'add') False
getattr() getattr()函数是Python自省的核心函数,具体使用大体如下:
获取对象引用getattr
Getattr用于返回一个对象属性,或者方法
classA:
def__init__(self):
self.name='zhangjing'
#self.age='24'
defmethod(self):
print"methodprint"
Instance=A()
printgetattr(Instance,'name,'notfind')#如果Instance对象中有属性name则打印self.name的值,否则打印'notfind'
printgetattr(Instance,'age','notfind')#如果Instance对象中有属性age则打印self.age的值,否则打印'notfind'
printgetattr(a,'method','default')
#如果有方法method,否则打印其地址,否则打印default
printgetattr(a,'method','default')()
#如果有方法method,运行函数并打印None否则打印default
sys.modules
与其它任何Python的东西一样,模块也是对象。只要导入了,总可以用全局dictionarysys.modules来得到一个模块的引用。
是一个字典,它包含了从Python开始运行起,被导入的所有模块。键字就是模块名,键值就是模块对象。请注意除了你的程序
导入的模块外还有其它模块。Python在启动时预先装入了一些模块,如果你在一个PythonIDE环境下,sys.modules包含了你
在IDE中运行的所有程序所导入的所有模块。
反射
反射的作用就是列出对象的所有属性和方法,反射就是告诉我们,这个对象到底是什么,提供了什么功能。
举个例子:
>>>importjson
>>>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')
<functionloadat0x7f66af736140>
>>>
可以取出指定属性
再看另外一个方法:callable
>>>callable(getattr(json,'load'))
True
>>>callable(getattr(json,'encoder'))
False
>>>
检查属性是否是可以调用的函数。
了解基础之后,就需要考虑,它存在的价值在哪里了?
考虑一个应用的场景:IDE的自动补全。
在IDE中可以这样做:
>>>methodList=[attrforattrindir(json)ifcallable(getattr(json,attr))]
>>>methodList
['JSONDecoder','JSONEncoder','dump','dumps','load','loads']
>>>
>>>getattr(json,'load').__doc__
'Deserialize``fp``(a``.read()``-supportingfile-likeobjectcontaining\naJSONdocument)toaPythonobject.\n\nIfthecontentsof``fp``isencodedwithanASCIIbasedencodingother\nthanutf-8(e.g.latin-1),thenanappropriate``encoding``namemust\nbespecified.EncodingsthatarenotASCIIbased(suchasUCS-2)are\nnotallowed,andshouldbewrappedwith\n``codecs.getreader(fp)(encoding)``,orsimplydecodedtoa``unicode``\nobjectandpassedto``loads()``\n\n``object_hook``isanoptionalfunctionthatwillbecalledwiththe\nresultofanyobjectliteraldecode(a``dict``).Thereturnvalueof\n``object_hook``willbeusedinsteadofthe``dict``.Thisfeature\ncanbeusedtoimplementcustomdecoders(e.g.JSON-RPCclasshinting).\n\n``object_pairs_hook``isanoptionalfunctionthatwillbecalledwiththe\nresultofanyobjectliteraldecodedwithanorderedlistofpairs.The\nreturnvalueof``object_pairs_hook``willbeusedinsteadofthe``dict``.\nThisfeaturecanbeusedtoimplementcustomdecodersthatrelyonthe\norderthatthekeyandvaluepairsaredecoded(forexample,\ncollections.OrderedDictwillremembertheorderofinsertion).If\n``object_hook``isalsodefined,the``object_pairs_hook``takespriority.\n\nTouseacustom``JSONDecoder``subclass,specifyitwiththe``cls``\nkwarg;otherwise``JSONDecoder``isused.\n\n'
>>>
大概就明白了反射的功能了。
#-*-coding:utf8-*-
classObj:
"""Anobjectthatusereflection"""
def__init__(self,name):
"""构造函数"""
self.name=name
defecho_methods(self):
"""输出类中所有的方法,以及doc文档"""
print"\nMethodList:"
forattrNameindir(self):
attr=getattr(self,attrName)
ifcallable(attr):
printattrName,"():",attr.__doc__
defecho_attributes(self):
print"\nAttributes"
fornameindit(self):
attr=getattr(self,attr)
ifnotcallable(attr):
printname,":",attr
obj=Obj("testObject")
obj.echo_methods()
ubuntu@yee:/tmp$pythonref.py
MethodList:
__init__():构造函数
echo_attributes():None
echo_methods():输出类中所有的方法,以及doc文档
可以看到,通过反射,我们可以知道类中所有的方法以及方法的属性和注释文档信息。
内置函数__import__
我们知道import语句是用来导入外部模块的,当然还有from...import...也可以,但是其实import实际上是使用builtin函数__import__来工作的。在一些程序中,我们可以动态地去调用函数,如果我们知道模块的名称(字符串)的时候,我们可以很方便的使用动态调用。
Python代码
importglob,os
modules=[]
formodule_fileinglob.glob("*-plugin.py"):
try:
module_name,ext=os.path.splitext(os.path.basename(module_file))
module=__import__(module_name)
modules.append(module)
exceptImportError:
pass#ignorebrokenmodules
#sayhellotoallmodules
formoduleinmodules:
module.hello()
导入其他目下的模块:
使用参数fromlist=True,进行字符串拼接。
递归
递归(recursion):程序调用自身的编程技巧。递归满足2个条件:
1)有反复执行的过程(调用自身)
2)有跳出反复执行过程的条件(递归出口)
(1)阶乘
n!=n*(n-1)*(n-2)*...*1(n>0)
ifx==1:
y=1
else:
y=x*recursion(x-1)
returny
print(recursion(5))
(2)斐波那契数列
斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1、1、2、3、5、8、13、21、……
这个数列从第三项开始,每一项都等于前两项之和。
有趣的兔子问题:
一般而言,兔子在出生两个月后,就有繁殖能力,一对兔子每个月能生出一对小兔子来。如果所有兔子都不死,那么一年以后可以繁殖多少对兔子?
分析如下:
第一个月小兔子没有繁殖能力,所以还是一对;
两个月后,生下一对小兔子,总数共有两对;
三个月以后,老兔子又生下一对,因为小兔子还没有繁殖能力,总数共是三对;
……
依次类推可以列出下表:
ifn==0:
return0
ifn==1:
return1
ifn>1:
returnfibo(n-1)+fibo(n-2)
print(fibo(4))
相关文章推荐
- 循序渐进Python3(一)-- 初识Python
- 第三十九节,python内置全局变量
- Python基础之初识递归
- 初识Python-2、Python的常/变量、数据类型、运算符
- Python之变量初识
- 01python初识—编辑器&版本&变量知识
- python初识,变量及命名规则
- 浅谈python内置变量-reversed(seq)
- 【Python】Java程序员学习Python(四)— 内置方法和内置变量
- Python反射、模块中的变量os、sys、__file__、加密模块等
- 循序渐进Python3(八) -- 0 -- 初识socket
- Py修行路 python基础 (十四)递归 及 面向对象初识及编程思想
- Python 学习笔记 - 递归和模块中的特殊变量
- Python--反射(重点)、面向对象内置方法:如__str__、面向对象的软件开发
- 018--python 函数参数、变量、前向引用、递归
- 循序渐进Python3(五) -- 初识模块
- Python第八天 模块 包 全局变量和内置变量__name__ Python path
- 循序渐进学Python2变量与输入
- python 递归时存储中间变量要用copy 方法,否则出栈就废了
- python内置字符串处理变量整理