Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/amazon-web-services/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python元类,execfile,inspect,globals(),命名空间_Python_Metaclass_Execfile - Fatal编程技术网

Python元类,execfile,inspect,globals(),命名空间

Python元类,execfile,inspect,globals(),命名空间,python,metaclass,execfile,Python,Metaclass,Execfile,直接运行以下脚本时,它将按预期操作: import inspect __module__ = "__main__" __file__ = "classes.py" test_str = "test" class met(type): def __init__(cls, name, bases, dct): setattr(cls, "source", inspect.getsource(cls)) #setattr(cls, "source", tes

直接运行以下脚本时,它将按预期操作:

import inspect

__module__ = "__main__"
__file__ = "classes.py"
test_str = "test"

class met(type):
    def __init__(cls, name, bases, dct):
        setattr(cls, "source", inspect.getsource(cls))
        #setattr(cls, "source", test_str)
        super(met, cls).__init__(name, bases, dct)

class ParentModel(object):
    __metaclass__ = met
    def __init__(self):
        super(object, self).__init__(ParentModel.__class__)
    def setsource(self):
        self.source = inspect.getsource(self.__class__)
        #self.source = test_str
    def getsource(self):
        return self.source

class ChildB(ParentModel):
    name = "childb"
    pass

class ChildA(ChildB):
    name = "childa"
    pass

class ChildC(ChildA):
    name = "childc"
    pass
当试图通过pythonshell或其他脚本中的exec或execfile运行此脚本时,会出现困难。例如:

>>> execfile("classes.py")
运行时没有问题,但是:

>>> ns = {}
>>> execfile("classes.py", ns)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "classes.py", line 13, in <module>
    class ParentModel(object):
  File "classes.py", line 9, in __init__
    setattr(cls, "source", inspect.getsource(cls))
  File "D:\Python27\lib\inspect.py", line 701, in getsource
    lines, lnum = getsourcelines(object)
  File "D:\Python27\lib\inspect.py", line 690, in getsourcelines
    lines, lnum = findsource(object)
  File "D:\Python27\lib\inspect.py", line 526, in findsource
    file = getfile(object)
  File "D:\Python27\lib\inspect.py", line 408, in getfile
    raise TypeError('{!r} is a built-in class'.format(object))
TypeError: <module '__builtin__' (built-in)> is a built-in class
同样,运行没有问题,但:

>>> ns = dict(globals())
>>> execfile("classes.py", ns)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "classes.py", line 13, in <module>
    class ParentModel(object):
  File "classes.py", line 9, in __init__
    setattr(cls, "source", inspect.getsource(cls))
  File "D:\Python27\lib\inspect.py", line 701, in getsource
    lines, lnum = getsourcelines(object)
  File "D:\Python27\lib\inspect.py", line 690, in getsourcelines
    lines, lnum = findsource(object)
  File "D:\Python27\lib\inspect.py", line 526, in findsource
    file = getfile(object)
  File "D:\Python27\lib\inspect.py", line 408, in getfile
    raise TypeError('{!r} is a built-in class'.format(object))
TypeError: <module '__builtin__' (built-in)> is a built-in class
ns=dict(globals()) >>>execfile(“classes.py”,ns) 回溯(最近一次呼叫最后一次): 文件“”,第1行,在 文件“classes.py”,第13行,在 类ParentModel(对象): 文件“classes.py”,第9行,在_init中__ setattr(cls,“源”,inspect.getsource(cls)) getsource中第701行的文件“D:\Python27\lib\inspect.py” 行,lnum=getsourcelines(对象) getsourcelines中第690行的文件“D:\Python27\lib\inspect.py” 行,lnum=findsource(对象) findsource中第526行的文件“D:\Python27\lib\inspect.py” file=getfile(对象) getfile中第408行的文件“D:\Python27\lib\inspect.py” raise TypeError(“{!r}是内置类”。格式(对象)) TypeError:是一个内置类 从回溯来看,它与inspect相关,但是它也应该在execfile(“classes.py”)或execfile(“classes.py”,globals())上出错

那么,就这个错误而言,dict(globals())如何呢globals()以及为什么会导致此错误


编辑:读者应参考Martijn Pieters和Lennart Regebro的答案以获得完整的图片。

使用
execfile()
执行python文件时,您是在当前名称空间中执行它。REPL命名空间是一个内置模块:

>>> import sys
>>> sys.modules['__main__']
<module '__main__' (built-in)>
您的下一个问题是,因为您使用的是
execfile
,所以为代码设置的模块总是会出错
inspect.getsource()
无法确定在何处定义代码,因为
execfile()
绕过了正常的导入机制:

$ cat test.py
execfile('classes.py')
$ python test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    execfile('classes.py')
  File "classes.py", line 13, in <module>
    class ParentModel(object):
  File "classes.py", line 9, in __init__
    setattr(cls, "source", inspect.getsource(cls))
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 701, in getsource
    lines, lnum = getsourcelines(object)
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 690, in getsourcelines
    lines, lnum = findsource(object)
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 564, in findsource
    raise IOError('could not find class definition')
IOError: could not find class definition

为了明确起见,创建
globals()
的副本只能防止
execfile()
修改当前模块名称空间(或REPL名称空间)。如果在当前名称空间中使用
execfile()。REPL命名空间是一个内置模块:

>>> import sys
>>> sys.modules['__main__']
<module '__main__' (built-in)>
您的下一个问题是,因为您使用的是
execfile
,所以为代码设置的模块总是会出错
inspect.getsource()
无法确定在何处定义代码,因为
execfile()
绕过了正常的导入机制:

$ cat test.py
execfile('classes.py')
$ python test.py
Traceback (most recent call last):
  File "test.py", line 1, in <module>
    execfile('classes.py')
  File "classes.py", line 13, in <module>
    class ParentModel(object):
  File "classes.py", line 9, in __init__
    setattr(cls, "source", inspect.getsource(cls))
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 701, in getsource
    lines, lnum = getsourcelines(object)
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 690, in getsourcelines
    lines, lnum = findsource(object)
  File "/usr/local/Cellar/python/2.7.5/Frameworks/Python.framework/Versions/2.7/lib/python2.7/inspect.py", line 564, in findsource
    raise IOError('could not find class definition')
IOError: could not find class definition

为了明确起见,创建
globals()
的副本只能防止
execfile()
修改当前模块名称空间(或REPL名称空间)。否则,传递给
execfile()

的字典之间没有区别。这个问题不是
dict(globals())!=globals()
,因为它是。这里的问题是,您执行的
execfile()
上下文中的
globals()
classes.py中的
globals()
不同

当您传入一个名称空间时,您将替换否则将创建的名称空间。如果传入一个名称空间,您将为
模块创建一个名称空间。这意味着
\uuuu main\uuuu
将是classes.py文件。但是,当您传入调用
execfile()
的文件的名称空间时,将使用该名称空间,而
\uuuuu main\uuuu
将是该模块

这导致inspect无法在源代码中找到类定义,因为它在错误的文件中查找

如果传入一个空名称空间,它将根本找不到
\uuuuu main\uuuuu
,并且该类将被假定为一个内置类,没有可用的源代码,并且会引发一个错误

总之,您在这里犯的错误是认为
globals()
对于解释器是全局的,而实际上对于模块是全局的

从与Marjtin的讨论中,很明显,在OSX上的工作方式略有不同。这意味着即使不传入名称空间,也不能依赖这种工作方式


这就引出了一个问题,你为什么要这样做,以及你真正想要实现的目标。

这个问题不是
dict(globals())!=globals()
,因为它是。这里的问题是,您执行的
execfile()
上下文中的
globals()
classes.py中的
globals()
不同

当您传入一个名称空间时,您将替换否则将创建的名称空间。如果传入一个名称空间,您将为
模块创建一个名称空间。这意味着
\uuuu main\uuuu
将是classes.py文件。但是,当您传入调用
execfile()
的文件的名称空间时,将使用该名称空间,而
\uuuuu main\uuuu
将是该模块

这导致inspect无法在源代码中找到类定义,因为它在错误的文件中查找

如果传入一个空名称空间,它将根本找不到
\uuuuu main\uuuuu
,并且该类将被假定为一个内置类,没有可用的源代码,并且会引发一个错误

总之,您在这里犯的错误是认为
globals()
对于解释器是全局的,而实际上对于模块是全局的

从与Marjtin的讨论中,很明显,在OSX上的工作方式略有不同。这意味着即使不传入名称空间,也不能依赖这种工作方式


这就引出了一个问题,你为什么要这样做,你到底想达到什么目的。

事实上,事实并非如此。如果您创建第二个文件,并调用
execfile('classes.py',globals())
,您会发现它引发了一个错误。对不起,Martijn,
>>> import sys
>>> import types
>>> sys.modules['fake_classes'] = types.ModuleType('fake_classes')
>>> sys.modules['fake_classes'].__file__='classes.py'
>>> ns = {'__name__': 'fake_classes'}
>>> execfile('classes.py', ns)
>>> >>> ns.keys()
['__module__', 'ChildA', '__builtins__', 'inspect', '__package__', 'met', 'ChildB', 'ChildC', 'ParentModel', '__name__', 'test_str']