Как изменить строку в функции при вызове функции?
Я не уверен, если это возможно, но есть ли способ изменить строку, которую функция печатает при вызове из другой функции? Я хочу сделать что-то вроде этого:
def string():
print ("This cat was scared.")
def main():
for words in string():
str.replace("cat", "dog")
# Print "The do was scared."
main()
3 ответа
Как предположение:
- Вы хотели
string()
чтобы вернуть значение, которое может использовать вызывающая сторона, вместо того, чтобы просто печатать что-то на экране. Так что вам нужноreturn
заявление вместоprint
вызов. - Вы хотите перебрать все слова в этой возвращаемой строке, а не все символы, поэтому вам нужно вызвать
split()
на веревочке. - Вы хотите заменить вещи в каждом слове, а не в буквальном
"cat"
, Итак, вам нужно позвонитьreplace
наword
не наstr
учебный класс. Также,replace
на самом деле не меняет слово, оно возвращает новое, которое вы должны запомнить. - Вы хотите распечатать каждое из этих слов.
Если так:
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"))
По многочисленным просьбам (ну, любопытство одного человека...), вот как вы можете изменить строку в функции перед вызовом этой функции.
Вы никогда не должны делать это на практике. Есть несколько вариантов использования для работы с объектами кода, но на самом деле это не один из них. Кроме того, если вы делаете что-то менее тривиальное, вы должны использовать библиотеку, как bytecode
или же byteplay
вместо того, чтобы делать это вручную. Кроме того, само собой разумеется, что не все реализации 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()
Если вам этого не хватает, я упомянул, что объекты кода неизменны. И, конечно же, струны. Но достаточно глубоко под прикрытием, они просто указывают на некоторые данные C, верно? Опять же, только если мы используем CPython, но если мы...
Во-первых, хватай мой superhackyinternals
проект от GitHub. (Это намеренно не может быть установлено с помощью pip, потому что вы действительно не должны использовать это, кроме как для экспериментов с вашей локальной сборкой интерпретатора и т.п.). Затем:
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()
Я думаю, что вы действительно можете искать, это возможность вызывать вашу функцию с аргументом по умолчанию:
def string(animal='cat'):
print("This {} was scared.".format(animal))
>>> string()
This cat was scared.
>>> string('dog')
This dog was scared.
Если вы ничего не передаете string
предполагается значение по умолчанию. В противном случае строка печатается с подстрокой, которую вы явно передали.