您的位置:首页 > 编程语言 > Python开发

循序渐进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

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)

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))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: