在学习dict的时候,肯定听过dict是Python中最重要的数据类型,但是不一定知道为什么。马上你就会明白原因了。
Python中从模块、到函数、到类、到元类,其实主要管理方法就是靠一个一个的字典。
先来学一个重要的内置函数。
dir返回一个列表。
列表中包含了实例的属性名,实例的类的属性名,实例的所有超类的属性名。
如果你想获取一个对象所有有效属性,你应该使用dir()来替代__dict__
或者__slots__
。
我们先来写一个没有什么实际意义的module。
a.py
PRint('start')import sysfrom threading import Threadimport datetimedef f1(): x=a #这里故意设置了一个没有初始化的变量a def inner(): y=1 return y return innerclass A: xx=1 def f2(self): yy=2 return yya=A()print('end')
在Python运行的时候,会从上到下把变量放入一个叫__dict__
字典中,并运行所有的打印语句。
>>> import astart #打印语句会全部运行。end>>> a.__dict__.keys() #会把全局变量放在这个字典中,同时Python会自动生成一些字典键值对。dict_keys(['__name__', '__package__', '__doc__', '__loader__', 'datetime', 'A', '__spec__', '__builtins__', '__cached__', '__file__', 'f1', 'sys', 'a', 'Thread'])
你肯定听说过import和from语句是隐形的赋值语句,现在可以看到他们的名字出现在这个字典中了吧。
你也肯定听说过def和class语句是隐形的赋值语句,找找看是不是也出现在这个字典中了?
当然还包括我们的赋值语句中定义的变量a了。
现在我们进一步探究一下这个有用的字典。
>>> a.__builtins__.keys() #这个是builtins模块中定义的所有变量,中间省略了很多。#Python判断我们的一个变量是否定义过,就是看变量是否出现在a.__dict__或a.__builtins__中。dict_keys(['setattr', 'slice', 'ZeroDivisionError', 'IndexError', 'KeyError', 'TimeoutError', 'map', 'isinstance', 'bin', 'bytearray', 'zip', 'locals', 'IsADirectoryError', 'AttributeError', ...'False', 'print', 'vars', 'exit', 'EnvironmentError'])>>> a.__doc__ #这个是模块的文档字符串,由于我们没有定义,所以为Null>>> a.__file__ #这个是运行的文件名。'/home/aaa/proj/a.py'>>> a.__name__ #这个是我们的文件名,不包括路径和扩展名py'a'
额外说一句,如果我们直接运行一个Python文件,那么这个文件会出现在sys.modules中,事实上,我们所有import的对象都会出现在这个字典中。
>>> sys.modules[__name__]<module '__main__' (built-in)> #这个就是我们运行的Python文件。>>> sys.modules['datetime']<module 'datetime' from '/usr/lib/python3.4/datetime.py'> #这是我们导入的datetime文件。>>> sys.modules['logging'] #我们没有import过logging模块,所以找不到。Traceback (most recent call last): File "<stdin>", line 1, in <module>KeyError: 'logging'
我们在a.py中输入一下测试内容。
g=55def f1(arg=2,arg2='c',*,kargs=3,kargs2='dd'): x=a #这里故意设置了一个没有初始化的变量a def inner(): y=1 return y return innerf1.val=3f1.val2='python'
我们运行下面的测试内容来进行探索。
>>> from a import f1>>> f1.__class__ #由于Python内部采用function类来创建函数,所以函数是function类的实例,通过__class__可以看到一个实例的类。<class 'function'>>>> f1.__module__ #找到函数属于那个模块'a'>>> f1.__name__ #函数的名词'f1'>>>f1.__code__ #这是f1的代码对象,请移步"解释型和编译型语言的区别以及Python的运作方式"去查看。>>> f1.__globals__.keys() #该函数能够使用的所有全局变量,所以Python通过如果判断函数中的变量没有在本地定义,且不在f1.__dict__中,且不在f1.__globals__字典中,且不在f1.__modules__.__builtins__中的话,那么会报参数为定义的错误。dict_keys(['f1', '__name__', '__doc__', '__builtins__', '__file__', '__spec__', '__cached__', '__package__', 'g', '__loader__'])>> f1.__dict__ #如果定义了函数的属性,那么出现在__dict__中。{'val2': 'python', 'val': 3}>>> f1.__defaults__ #如果定义了位置默认参数,那么出现在这个字典中,也就是说函数的默认参数是在函数定义的时候评估的(2, 'c')#如果默认参数获取失败,那么函数定义就会失败。>>> def f(x=c):... #默认参数评估出错,定义阶段就会报错。... Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'c' is not defined>>> def ff(x): #如果是函数内部变量评估出错,那么函数定义阶段捕获报错,但是运行阶段会报错。... x=c... >>> ff(1)Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in fNameError: name 'c' is not defined>>> f1.__kwdefaults__ #关键字参数的默认参数放在__kedefaults__中。{'kargs': 3, 'kargs2': 'dd'}
我知道如果我们定义类,那么Python默认采用元类type来初始化该类,而且我会在元类部分详细介绍其运作方式。
我知道我们的函数是通过class function来初始化的,但是具体的运作方式有所不知,如果你知道哪里有介绍内容,。
这个很重要,我们先稍微了解一下,在下面几篇文章中,我会着重介绍。
先定义一个简单的类:
a.py
g=55class Desc: def __get__(self,ins, cls): print(self)class A: arg=2 arg2=Desc() def __init__(self, name, age): self.name = name self.age=age def f2(self,x=1): y='a' print(x)
下面开始我们的测试:
>>> from a import A>>> dir(A) #所有A可以用的属性名列表['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'arg', 'arg2', 'f2']>>> A.__doc__ #A的文档字符串>>> A.f2 #A中定义的方法f2,每个定义的方法名都会出现在A.__dict__中。<function A.f2 at 0x7f970a8d2bf8>>>> A.__module__ #A所在的模块名。'a'>>> A.arg #A中的所有属性都会出现在A.__dict__中。2>>> A.arg2 #这是A的arg2属性,是一个描述符对象。<a.Desc object at 0x7f11f25e7588>>>> A.__dict__ #类A的__dict__属性,这是一个相当重要的属性。mappingproxy({'arg': 2, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None, 'arg2': <a.Desc object at 0x7f9708995550>, '__module__': 'a', '__dict__': <attribute '__dict__' of 'A' objects>, 'f2': <function A.f2 at 0x7f970a8d2bf8>})>>> ins=A('js',22)>>> ins.__dict__ #这是A的实例ins的__dict__对象,在很多时候,该属性需要看类A的__dict__的脸色。{'age': 22, 'name': 'js'}
模块、类、函数均有以下属性:__dict__
:该对象的属性字典。__doc__
:返回说明性的文字,定义在块语句的最前面__name__
:返回该对象的名字
类、函数均有以下属性:__module
,用来返回该对象的模块名。__class__
:用来返回类的类型(或者实例的类)、或者函数的类型__globals__
:用来返回该对象所有可用的全局变量名。
模块有__file__
属性,用来返回模块包含路径的文件名,有__builtins__
属性,用来返回所有的可以使用的内置函数、内置异常对象、内置保留字等对象。
无论在任何位置,Python均会按照LEGB法则,在最后搜索模块的__builtins__
属性,来最后判断该变量是否已经定义。
模块、类、寒酸通过调用dir函数,可以得到该对象实际可以使用的所有属性。
新闻热点
疑难解答