2013-05-12 47 views
6

[编辑00]:我已经编辑了好几次帖子,现在甚至是标题,请在下面阅读。Python字符串插值实现

我只是了解了格式字符串的方法,其使用词典使用,就像vars()locals()globals(),例如提供者:

name = 'Ismael' 
print 'My name is {name}.'.format(**vars()) 

但我想做的事:

name = 'Ismael' 
print 'My name is {name}.' # Similar to ruby 

所以我想出了这个:

def mprint(string='', dictionary=globals()): 
    print string.format(**dictionary) 

你可以用这里的代码交互: http://labs.codecademy.com/BA0B/3#:workspace

最后,我很想做的是在另一个文件中的函数,名为my_print.py,所以我可以做的:

from my_print import mprint 

name= 'Ismael' 
mprint('Hello! My name is {name}.') 

但因为它现在,范围有问题,我怎么能从导入的mprint函数中将主模块名称空间作为字典来获取。 (不是从my_print.py

我希望我让自己理解,如果不是,尝试从另一个模块导入功能。 (回溯在链接中)

它从my_print.py访问globals()字典,但当然变量名没有在该范围内定义,有关如何完成此任务的任何想法?

该函数如果在同一个模块中定义,但注意我必须如何使用globals(),因为如果不是,我只会得到一个值在mprint()范围内的字典。

我已经尝试使用nonlocal和点符号来访问主模块变量,但我仍然无法弄清楚。


[编辑01]:我想我已经找到了一个解决方案:

在my_print.py:

def mprint(string='',dictionary=None): 
    if dictionary is None: 
     import sys 
     caller = sys._getframe(1) 
     dictionary = caller.f_locals 
    print string.format(**dictionary) 

在test.py:

from my_print import mprint 

name = 'Ismael' 
country = 'Mexico' 
languages = ['English', 'Spanish'] 

mprint("Hello! My name is {name}, I'm from {country}\n" 
     "and I can speak {languages[1]} and {languages[0]}.") 

它打印:

Hello! My name is Ismael, I'm from Mexico 
and I can speak Spanish and English. 

你认为什么人?对我来说这是一件困难的事情!

我喜欢它,对我更具可读性。


[EDIT 02]:我已完成的模块与interpolate功能,Interpolate类和用于interpolate类方法类似的方法的功能的尝试。

它有一个小测试套件和它的记录!

我卡在方法的实现,我不明白。

下面的代码:http://pastebin.com/N2WubRSB

你觉得什么人?


[编辑03]:好的我现在只用interpolate()函数解决了。

string_interpolation.py

import sys 


def get_scope(scope): 
    scope = scope.lower() 
    caller = sys._getframe(2) 
    options = ['l', 'local', 'g', 'global'] 

    if scope not in options[:2]: 
     if scope in options[2:]: 
      return caller.f_globals 
     else: 
      raise ValueError('invalid mode: {0}'.format(scope)) 
    return caller.f_locals 


def interpolate(format_string=str(),sequence=None,scope='local',returns=False): 
    if type(sequence) is str: 
     scope = sequence 
     sequence = get_scope(scope) 
    else: 
     if not sequence: 
      sequence = get_scope(scope) 

    format = 'format_string.format(**sequence)' 
    if returns is False: 
     print eval(format) 

    elif returns is True: 
     return eval(format) 

再次感谢你们!有什么意见?


[编辑04]:

这是我的最后一个版本,它有一个测试,文档字符串并介绍了一些限制,我发现: http://pastebin.com/ssqbbs57

您可以在这里快速测试代码: http://labs.codecademy.com/BBMF#:workspace

和克隆格罗姆混帐回购协议在这里: https://github.com/Ismael-VC/python_string_interpolation.git

+2

相关:?是一个字符串格式化从其呼叫范围的做法不好拉变量(http://stackoverflow.com/questions/13312240/is- a-string-formatter-that-pulls-variables-from-calling-scope-bad-practice) – jfs 2013-05-12 08:10:35

+1

related:[打印变量名称和内容作为调试工具;寻找emacs/Python快捷方式](http://stackoverflow.com/questions/2813227/printing-variable-names-and-contents-as-debugging-tool-looking-for-emacs-python) – jfs 2013-05-12 08:13:29

+0

这是一个有趣的练习,但我会警告这种隐含的行为:Python不鼓励它(“显式比隐式更好”意味着这里'mprint('...',vars())'比'mprint('...')要好回到调用者并获取它的局部变量),我认为它的确有很好的理由(明确的代码可以更容易地阅读和维护)。 – EOL 2013-05-12 13:28:55

回答

0

语言设计不仅仅是解决困惑:;)

http://www.artima.com/forums/flat.jsp?forum=106&thread=147358

编辑:PEP-0498解决这个问题!

string模块Template类,也不会是我需要的东西(但更类似于串format法),到底它也有我所寻求的可读性,它也有推荐的明确性,它在标准图书馆,它也可以很容易地定制和扩展。

http://docs.python.org/2/library/string.html?highlight=template#string.Template

from string import Template 

name = 'Renata' 
place = 'hospital' 
job = 'Dr.' 
how = 'glad' 
header = '\nTo Ms. {name}:' 

letter = Template(""" 
Hello Ms. $name. 

I'm glad to inform, you've been 
accepted in our $place, and $job Red 
will ${how}ly recieve you tomorrow morning. 
""") 

print header.format(**vars()) 
print letter.substitute(vars()) 

有趣的是,现在我越来越喜欢用{},而不是$的,我还是喜欢string_interpolation模块我想到了,因为它的打字比任何一个在少长远来看。大声笑!

运行的代码在这里:

http://labs.codecademy.com/BE3n/3#:workspace

1

您的问题的一部分 - 呃,它不工作的原因 - 在this question中突出显示。

通过传入globals()作为第二个参数mprint('Hello my name is {name}',globals()),可以使您的功能正常工作。

尽管在Ruby中可能会很方便,但如果您想充分利用该语言,我鼓励您不要在Python中编写Ruby。

+0

我只想输入更少的内容! ;)我开始在脚本中使用成语'''.format(** vars())',然后我重新考虑了我必须重构它,所以我做了(尝试),我并不在乎它是否看起来像是红宝石,因为直到最近我还不知道编程方面的任何内容,但它看起来对我来说更具可读性,我使用它进行简单的格式化。我想能够像这样调用它:'from my_print import mprint; name ='Ismael'; mprint('你好!我的名字是{name}。')没有全局变量,每次调用只是为了知道它是如何做到的,一定有办法! – SalchiPapa 2013-05-12 06:59:26

+0

基本上我想实现的就是使这个默认行为:'mprint('你好我的名字是{name}',vars())',而不是每次都明确地调用vars()。感谢您的链接! – SalchiPapa 2013-05-12 07:04:01

2

模块不共享Python中的命名空间,所以globals()对于my_print总是将是my_print.py文件的globals();即功能实际定义的位置。

def mprint(string='', dic = None): 
    dictionary = dic if dic is not None else globals() 
    print string.format(**dictionary) 

您应该明确传递当前模块的globals()以使其工作。

Ans在Python函数中不使用可变对象作为默认值,它可能导致unexpected results。改为使用None作为默认值。

在模块理解作用域一个简单的例子:

文件:my_print.py

x = 10 
def func(): 
    global x 
    x += 1 
    print x 

文件:主。PY

from my_print import * 
x = 50 
func() #prints 11 because for func() global scope is still 
     #the global scope of my_print file 
print x #prints 50 
+0

是不是有办法从'my_print.py'中获取'main.py'的命名空间作为字典?我正在阅读关于继承的知识,现在,不会有类似点符号的做法吗?但是,我必须让这个课程可以被调用?大声笑我现在要打电话给你,谢谢阿什维尼! – SalchiPapa 2013-05-12 07:27:47

+0

来自python文档:http://docs.python.org/2/library/functions.html#vars 所以我需要从mprint中获取main.py'__dict__',这真的不可能吗?我不能停止想这件事。 – SalchiPapa 2013-05-12 07:36:33

+0

@ user2374329您可以使用'main .__ dict__',但它只包含'main'导入时定义的变量。 BTW继承与类而不是模块有关。 – 2013-05-12 07:43:34