wim*_*wim 15 python django stdout python-3.x django-management-command
在Python 3.5.0上运行Django v1.10:
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **options):
print('hello ', end='', file=self.stdout)
print('world', file=self.stdout)
Run Code Online (Sandbox Code Playgroud)
预期产量:
hello world
Run Code Online (Sandbox Code Playgroud)
实际产量:
hello
world
Run Code Online (Sandbox Code Playgroud)
如何正确传递结束字符?我目前使用明确设置的解决方法:
self.stdout.ending = ''
Run Code Online (Sandbox Code Playgroud)
但是这个hack意味着你没有获得打印功能的所有功能,你必须self.stdout.write手动使用和准备字节.
Moi*_*dri 12
正如Django 1.10的自定义管理命令文档中所述:
当您使用管理命令并希望提供控制台输出时,您应该写入self.stdout和self.stderr,而不是直接打印到stdout和stderr.通过使用这些代理,可以更轻松地测试自定义命令.另请注意,除非指定结束参数,否则不需要使用换行符结束消息,它将自动添加.
Run Code Online (Sandbox Code Playgroud)self.stdout.write("Unterminated line", ending='')
因此,为了在Command课堂上打印,您应该将您的handle()功能定义为:
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout.write("hello ", ending='')
self.stdout.write("world", ending='')
# prints: hello world
Run Code Online (Sandbox Code Playgroud)
此外,通过显式设置self.stdout.ending = '',您正在修改self.stdout对象的属性.但你可能不希望这在未来的电话中反映出来self.stdout.write().因此,最好ending在self.stdout.write()函数内使用参数(如上面的示例代码所示).
正如您所提到的"但是这个hack意味着您没有获得打印功能的所有功能,您必须使用self.stdout.write并手动准备字节." 不,您不必担心创建bytes其他功能print(),因为self.stdout.write()属于OutputWrapper类的函数需要数据str格式化.另外我想提一下,print()并且OutputWrapper.write()表现得非常相似,都充当了包装器sys.stdout.write().
print()和之间唯一的区别OutputWrapper.write()是:
print()接受消息字符串*args与separator参数一起加入多个字符串,而OutputWrapper.write() 接受单个消息字符串但是,通过使用分隔符显式连接字符串并将其传递给,可以轻松处理这种差异OutputWrapper.write().
结论:您不必担心print()由于没有提供的附加功能,并且应该继续self.stdout.write()按照本回答引用的自定义管理命令文档中引用的内容进行使用.
如果您有兴趣,可以查看以下内容的源代码BaseCommand和OutputWrapper类:源代码django.core.management.base.它可能有助于消除你的一些疑虑.您也可以查看与Python 3相关的PEP-3105print().
首先,self.stdout是一个django.core.management.base.OutputWrapper命令实例.它write期望一个str,而不是bytes,因此你可以使用
self.stdout.write('hello ', ending='')
self.stdout.write('world')
Run Code Online (Sandbox Code Playgroud)
实际上self.stdout.write只接受字节,但只有当它ending 是空字符串时 - 这是因为它的write方法是定义的
def write(self, msg, style_func=None, ending=None):
ending = self.ending if ending is None else ending
if ending and not msg.endswith(ending):
msg += ending
style_func = style_func or self.style_func
self._out.write(force_str(style_func(msg)))
Run Code Online (Sandbox Code Playgroud)
如果ending为真,那么msg.endswith(ending)如果msg是bytes实例并且结尾是a 则将失败str.
此外,当我明确设置时print,self.stdout它可以正常工作self.stdout.ending = ''; 但是,这样做可能意味着其他使用self.stdout.write期望它插入换行符的代码会失败.
在你的情况下,我要做的是为以下print方法定义一个方法Command:
from django.core.management.base import OutputWrapper
class PrintHelper:
def __init__(self, wrapped):
self.wrapped = wrapped
def write(self, s):
if isinstance(self.wrapped, OutputWrapper):
self.wrapped.write(s, ending='')
else:
self.wrapped.write(s)
class Command(BaseCommand):
def print(self, *args, file=None, **kwargs):
if file is None:
file = self.stdout
print(*args, file=PrintHelper(file), **kwargs)
def handle(self, *args, **options):
self.print('hello ', end='')
self.print('world')
Run Code Online (Sandbox Code Playgroud)
您可以将它变成您自己的BaseCommand子类 - 您也可以将它与不同的文件一起使用:
def handle(self, *args, **options):
for c in '|/-\\' * 100:
self.print('\rhello world: ' + c, end='', file=self.stderr)
time.sleep(0.1)
self.print('\bOK')
Run Code Online (Sandbox Code Playgroud)
self.stdout.ending显式设置时,print命令按预期工作.
截至需求的行中设置self.stdout.ending的时候file=self.stdout,因为那是的一个实例django.core.management.base.OutputWrapper.
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout.ending = ''
print('hello ', end='', file=self.stdout)
print('world', file=self.stdout)
Run Code Online (Sandbox Code Playgroud)
返回
hello world
Run Code Online (Sandbox Code Playgroud)