【问题标题】:Python string interpolation implementationPython字符串插值实现
【发布时间】:2013-05-06 11:09:01
【问题描述】:

[EDIT 00]:我已经对帖子进行了多次编辑,现在连标题都编辑了,请阅读下文。

我刚刚了解了格式化字符串方法,以及它与字典的使用,例如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() dict,但是变量名当然没有在那个范围内定义,有什么想法可以做到这一点吗?

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

我尝试过使用非本地和点符号来访问主要模块变量,但我仍然无法弄清楚。


[EDIT 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

你们怎么看?


[EDIT 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

并在此处克隆 grom git repo: https://github.com/Ismael-VC/python_string_interpolation.git

【问题讨论】:

标签: python string-interpolation


【解决方案1】:

this question 中突出显示了您的部分问题 - 嗯,它不起作用的原因。

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

虽然在 Ruby 中可能很方便,但如果您想充分利用 Python,我建议您不要用 Python 编写 Ruby。

【讨论】:

  • 我真的只想少打字! ;) 我开始在我的脚本中大量使用成语''.format(**vars()),然后我意识到我必须重构它,所以我做了(尝试过),我真的不在乎它是否看起来像红宝石,因为我没有直到最近才对编程一无所知,但它对我来说仍然更具可读性,而且我经常使用它来进行简单的格式化。我希望能够这样称呼它:from my_print import mprint; name= 'Ismael'; mprint('Hello! My name is {name}.') 没有全局变量等每次调用只是为了知道怎么做,一定有办法!
  • 基本上我想要实现的是将其设置为默认行为:mprint('Hello my name is {name}', vars()) 无需每次都显式调用 vars() 。顺便谢谢你的链接!
【解决方案2】:

模块在 python 中不共享命名空间,所以 globals() for 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

文件:main.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

【讨论】:

  • 难道没有办法从my_print.py 获取main.py 的命名空间作为字典吗?我正在阅读有关继承的信息,现在,类点符号不会起到作用吗?但是,我将不得不使该类可调用¿?哈哈,我现在就收工吧,谢谢 Ashwini!
  • 来自 python 文档:docs.python.org/2/library/functions.html#vars 所以我需要从 mprint 内部获取 main.py __dict__,真的不可能吗?我无法停止思考这个问题。
  • @user2374329 您可以使用main.__dict__,但它只会包含在导入main 时定义的变量。顺便说一句,继承与类而不是模块有关。
  • 再次感谢我完全迷路了。
【解决方案3】:

语言设计不仅仅是解决难题:;)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多