chạy nước rút như chức năng trong Python


131

Tôi muốn tạo một bộ đệm chuỗi để thực hiện nhiều xử lý, định dạng và cuối cùng viết bộ đệm trong tệp văn bản bằng cách sử dụng sprintfchức năng kiểu C trong Python. Vì các tuyên bố có điều kiện, tôi không thể viết chúng trực tiếp vào tập tin.

ví dụ mã giả:

sprintf(buf,"A = %d\n , B= %s\n",A,B)
/* some processing */
sprint(buf,"C=%d\n",c)
....
...
fprintf(file,buf)

Vì vậy, trong tệp đầu ra, chúng ta có loại o / p:

A= foo B= bar
C= ded
etc...

Chỉnh sửa, để làm rõ câu hỏi của tôi:
buf là một bộ đệm lớn chứa tất cả các chuỗi đã được định dạng bằng sprintf. Đi theo ví dụ của bạn, bufsẽ chỉ chứa các giá trị hiện tại, không chứa các giá trị cũ hơn. ví dụ đầu tiên trong buftôi đã viết A= something ,B= somethingsau C= somethingđược nối trong cùng buf, nhưng trong câu trả lời Python của bạn bufchỉ chứa giá trị cuối cùng, mà không phải là tôi muốn - Tôi muốn bufcó tất cả các printfs Tôi đã làm ngay từ đầu, giống như trong C.


1
Đó không phải là cách sprintf () hoạt động trong C. (Nó viết nội dung khi bắt đầu buf, không phải ở cuối.) Có lẽ sẽ tốt nhất khi sử dụng một chuỗi các chuỗi, sau đó nối chúng lại với nhau trước khi bạn ghi vào tệp.
yam655

@dividitherzero Đây có phải là chuyện nhỏ trong Python vì nó là ngôn ngữ lập trình chung không? Ví dụ: xem giải pháp của Michael J. Barber (được đăng sau bình luận của bạn). def sprintf(buf, fmt, *args): ...
jdk1.0

@ jdk1.0 Tôi không hiểu ý tôi là gì, tôi là một lập trình viên Python trẻ và ngây thơ ... Câu hỏi này thực sự kỳ lạ bởi vì điều này sử dụng lại bộ đệm không đơn giản, bạn cần tăng một con trỏ với đầu ra của mỗi cuộc gọi chạy nước rút, và loại điều này không phải là điều bạn nên lo lắng nếu bạn đang làm Python. Dù sao, tôi rất vui vì tôi đã chuyển đến Scala và bây giờ là Julia!
splititherzero

Câu trả lời:


169

Python có một %toán tử cho việc này.

>>> a = 5
>>> b = "hello"
>>> buf = "A = %d\n , B = %s\n" % (a, b)
>>> print buf
A = 5
 , B = hello

>>> c = 10
>>> buf = "C = %d\n" % c
>>> print buf
C = 10

Xem tài liệu tham khảo này cho tất cả các chỉ định định dạng được hỗ trợ.

Bạn cũng có thể sử dụng format:

>>> print "This is the {}th tome of {}".format(5, "knowledge")
This is the 5th tome of knowledge

40

Nếu tôi hiểu chính xác câu hỏi của bạn, định dạng () là những gì bạn đang tìm kiếm, cùng với ngôn ngữ nhỏ của nó .

Ví dụ ngớ ngẩn cho python 2.7 trở lên:

>>> print "{} ...\r\n {}!".format("Hello", "world")
Hello ...
 world!

Đối với các phiên bản python trước đó: (đã thử nghiệm với 2.6.2)

>>> print "{0} ...\r\n {1}!".format("Hello", "world")
Hello ...
 world!

4
Có lẽ bạn nên lưu ý rằng phiên bản đó chỉ hoạt động trong Python 3. Chẳng hạn, trong Python 2.6, bạn cần phải làm:"{0} ...\r\n {1}!".format("Hello", "world")
Đánh dấu Longair

1
Chỉnh sửa câu trả lời của tôi để bao gồm điều đó; không phải là nó cũng hoạt động cho python 2.7!
Nicolas Lefebvre

20

Tôi không hoàn toàn chắc chắn rằng tôi hiểu mục tiêu của bạn, nhưng bạn có thể sử dụng một StringIOví dụ làm bộ đệm:

>>> import StringIO 
>>> buf = StringIO.StringIO()
>>> buf.write("A = %d, B = %s\n" % (3, "bar"))
>>> buf.write("C=%d\n" % 5)
>>> print(buf.getvalue())
A = 3, B = bar
C=5

Không giống như sprintf, bạn chỉ cần truyền một chuỗi tới buf.write, định dạng nó bằng %toán tử hoặc formatphương thức của chuỗi.

Tất nhiên bạn có thể xác định một chức năng để có được sprintfgiao diện mà bạn hy vọng:

def sprintf(buf, fmt, *args):
    buf.write(fmt % args)

sẽ được sử dụng như thế này:

>>> buf = StringIO.StringIO()
>>> sprintf(buf, "A = %d, B = %s\n", 3, "foo")
>>> sprintf(buf, "C = %d\n", 5)
>>> print(buf.getvalue())
A = 3, B = foo
C = 5

2
+1 để chỉ cho tôi cách sử dụng * args với toán tử định dạng chuỗi (%).
Curtis Yallop

io.StringIO()thay vào đó hãy sử dụng Python3
Wolf


11

Bạn có thể sử dụng định dạng chuỗi:

>>> a=42
>>> b="bar"
>>> "The number is %d and the word is %s" % (a,b)
'The number is 42 and the word is bar'

Nhưng điều này đã bị xóa trong Python 3, bạn nên sử dụng "str.format ()":

>>> a=42
>>> b="bar"
>>> "The number is {0} and the word is {1}".format(a,b)
'The number is 42 and the word is bar'

4
Sai, nó không bị xóa trong Python 3. Python 3.0 cho biết nó sẽ không được chấp nhận trong 3.1 nhưng tôi tin rằng điều đó không bao giờ xảy ra. Sử dụng format()có thể được ưa thích hơn nhưng %định dạng vẫn tồn tại. (Xem mail.python.org/pipermail/python-dev/2009-September/092399.html để biết một số lý do tại sao nó không được phản đối)
Duncan

1
@Duncan; cảm ơn, tôi không biết điều đó Tôi đọc ở đâu đó nó không tán thành và không bao giờ thử lại :).
utdemir

7

Để chèn vào một chuỗi rất dài, thật tốt khi sử dụng tên cho các đối số khác nhau, thay vì hy vọng chúng ở đúng vị trí. Điều này cũng làm cho nó dễ dàng hơn để thay thế nhiều lần tái phát.

>>> 'Coordinates: {latitude}, {longitude}'.format(latitude='37.24N', longitude='-115.81W')
'Coordinates: 37.24N, -115.81W'

Lấy từ các ví dụ về Định dạng , trong đó tất cả các Formatcâu trả lời liên quan khác cũng được hiển thị.


3

Đây có lẽ là bản dịch gần nhất từ ​​mã C của bạn sang mã Python.

A = 1
B = "hello"
buf = "A = %d\n , B= %s\n" % (A, B)

c = 2
buf += "C=%d\n" % c

f = open('output.txt', 'w')
print >> f, c
f.close()

Các %nhà điều hành trong Python thực hiện gần như chính xác những điều tương tự như C sprintf. Bạn cũng có thể in chuỗi trực tiếp vào một tập tin. Nếu có rất nhiều chuỗi ký tự được định dạng chuỗi này có liên quan, có thể là khôn ngoan khi sử dụng một StringIOđối tượng để tăng tốc thời gian xử lý.

Vì vậy, thay vì làm +=, hãy làm điều này:

import cStringIO
buf = cStringIO.StringIO()

...

print >> buf, "A = %d\n , B= %s\n" % (A, B)

...

print >> buf, "C=%d\n" % c

...

print >> f, buf.getvalue()

3

Nếu bạn muốn một cái gì đó giống như chức năng in python3 nhưng thành một chuỗi:

def sprint(*args, **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}\n"

hoặc không có '\n'cuối:

def sprint(*args, end='', **kwargs):
    sio = io.StringIO()
    print(*args, **kwargs, end=end, file=sio)
    return sio.getvalue()
>>> x = sprint('abc', 10, ['one', 'two'], {'a': 1, 'b': 2}, {1, 2, 3})
>>> x
"abc 10 ['one', 'two'] {'a': 1, 'b': 2} {1, 2, 3}"

1

Cái gì đó như...

greetings = 'Hello {name}'.format(name = 'John')

Hello John

Điều này in một chuỗi ra bàn điều khiển, không phải chuỗi, đó là những gì OP muốn.
Teemu Leisti

Điều này cũng in% s lên màn hình, điều không được mong đợi; nhưng tôi thích rằng tôi có thể thêm nhiều biến bằng dấu phẩy.
b01


0

Hai cách tiếp cận là ghi vào bộ đệm chuỗi hoặc ghi dòng vào danh sách và nối chúng sau. Tôi nghĩ rằng StringIOcách tiếp cận này có tính chất pythonic hơn, nhưng không hoạt động trước Python 2.6.

from io import StringIO

with StringIO() as s:
   print("Hello", file=s)
   print("Goodbye", file=s)
   # And later...
   with open('myfile', 'w') as f:
       f.write(s.getvalue())

Bạn cũng có thể sử dụng chúng mà không có ContextMananger( s = StringIO()). Hiện tại, tôi đang sử dụng một lớp trình quản lý bối cảnh với một printchức năng. Đoạn này có thể hữu ích để có thể chèn các yêu cầu phân trang hoặc gỡ lỗi lẻ:

class Report:
    ... usual init/enter/exit
    def print(self, *args, **kwargs):
        with StringIO() as s:
            print(*args, **kwargs, file=s)
            out = s.getvalue()
        ... stuff with out

with Report() as r:
   r.print(f"This is {datetime.date.today()}!", 'Yikes!', end=':')
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.