调用函数时如何更改函数中的字符串?

时间:2018-03-14 06:38:30

标签: python string printing

我不确定这是否可行但是有没有办法在从另一个函数调用函数时更改函数打印的字符串?我想做这样的事情:

def string():
    print ("This cat was scared.")

def main():
    for words in string():
        str.replace("cat", "dog")
        # Print "The do was scared."

main()

3 个答案:

答案 0 :(得分:4)

根据大众需求(好吧,一个人的好奇心......),这里是你在调用该函数之前如何更改函数中的字符串。

你不应该在实践中这样做。有一些用于解决代码对象的用例,但这实际上并不是其中之一。另外,如果你做的事情不那么简单,你应该使用像bytecodebyteplay这样的库,而不是手动操作。此外,不言而喻,并非所有Python实现都使用CPython风格的代码对象。但无论如何,这里有:

import types

def string():
    print ("This cat was scared.")

def main():
    # A function object is a wrapper around a code object, with
    # a bit of extra stuff like default values and closure cells.
    # See inspect module docs for more details.
    co = string.__code__
    # A code object is a wrapper around a string of bytecode, with a
    # whole bunch of extra stuff, including a list of constants used
    # by that bytecode. Again see inspect module docs. Anyway, inside
    # the bytecode for string (which you can read by typing
    # dis.dis(string) in your REPL), there's going to be an
    # instruction like LOAD_CONST 1 to load the string literal onto
    # the stack to pass to the print function, and that works by just
    # reading co.co_consts[1]. So, that's what we want to change.
    consts = tuple(c.replace("cat", "dog") if isinstance(c, str) else c
                   for c in co.co_consts)
    # Unfortunately, code objects are immutable, so we have to create
    # a new one, copying over everything except for co_consts, which
    # we'll replace. And the initializer has a zillion parameters.
    # Try help(types.CodeType) at the REPL to see the whole list.
    co = types.CodeType(
        co.co_argcount, co.co_kwonlyargcount, co.co_nlocals,
        co.co_stacksize, co.co_flags, co.co_code,
        consts, co.co_names, co.co_varnames, co.co_filename,
        co.co_name, co.co_firstlineno, co.co_lnotab,
        co.co_freevars, co.co_cellvars)
    string.__code__ = co
    string()

main()

如果这对你来说不够hacky:我提到代码对象是不可变的。当然弦也是如此。但是在封面下足够深,他们只是指向一些C数据,对吧?同样,只有我们使用CPython,但如果我们是......

首先,从GitHub上抓取我的superhackyinternals项目。 (它故意不是可以安装的,因为你真的不应该使用它,除了试验你的本地构建的解释器等。)然后:

import ctypes
import internals

def string():
    print ("This cat was scared.")

def main():
    for c in string.__code__.co_consts:
        if isinstance(c, str):
            idx = c.find('cat')
            if idx != -1:
                # Too much to explain here; see superhackyinternals
                # and of course the C API docs and C source.
                p = internals.PyUnicodeObject.from_address(id(c))
                assert p.compact and p.ascii
                length = p.length
                addr = id(c) + internals.PyUnicodeObject.utf8_length.offset
                buf = (ctypes.c_int8 * 3).from_address(addr + idx)
                buf[:3] = b'dog'

    string()

main()

答案 1 :(得分:3)

猜猜:

  • 您希望string() 返回调用者可以使用的值,而不是仅仅将某些内容打印到屏幕上。因此,您需要return语句而不是print来电。
  • 您希望遍历返回的字符串中的所有字词,而不是所有字符,因此您需要在字符串上调用split()
  • 您想要替换每个单词中的内容,而不是文字"cat"中的内容。因此,您需要在replace上致电word,而不是str课程。另外,replace实际上并没有更改单词,而是返回 new ,您必须记住这一点。
  • 你想要打印出这些单词。

如果是这样的话:

def string():
    return "This cat was scared."

def main():
    for word in string().split():
        word = word.replace("cat", "dog")
        print(word, end=' ')
    print()

main()

解决了所有问题。但是,它可以简化,因为您在这里并不需要word.replace。您正在更换整个单词,因此您可以执行此操作:

def main():
    for word in string().split():
        if word == "cat": word = "dog"
        print(word, end=' ')
    print()

但是,更简单地说,你可以在整个字符串上调用replace,而你根本不需要循环:

def main():
    print(string().replace("cat", "dog"))

答案 2 :(得分:2)

我认为您可能正在寻找的是能够使用默认参数调用您的函数:

def string(animal='cat'):
    print("This {} was scared.".format(animal))

>>> string()
This cat was scared.

>>> string('dog')
This dog was scared.

如果您没有传递任何内容到string,则会假定默认值。否则,字符串将打印出您明确传递的子字符串。