Backticks có ý nghĩa gì đối với trình thông dịch python: `num`


88

Tôi đang tìm hiểu về danh sách và tôi đã tìm thấy đoạn mã nhỏ này trên một trang web khác:

return ''.join([`num` for num in xrange(loop_count)])

Tôi đã dành một vài phút để cố gắng tái tạo chức năng (bằng cách nhập) trước khi nhận ra rằng `num`bit đang phá vỡ nó.

Bao quanh một câu lệnh trong các ký tự đó làm gì? Từ những gì tôi có thể thấy nó tương đương với str (num). Nhưng khi tôi hẹn giờ nó:

return ''.join([str(num) for num in xrange(10000000)])

Mất 4,09 giây trong khi:

return ''.join([`num` for num in xrange(10000000)])

mất 2,43s.

Cả hai đều cho kết quả giống hệt nhau nhưng một kết quả chậm hơn rất nhiều. Chuyện gì đang xảy ra ở đây?

CHỈNH SỬA: Kỳ lạ là ... repr()cho kết quả hơi chậm hơn `num`. 2,99 giây so với 2,43 giây. Sử dụng Python 2.6 (chưa thử 3.0).


8
Sau khi đọc "trang web khác" tại skymind.com/~ocrow/python_string , tôi đã có một câu hỏi tương tự và tìm thấy trang này. Câu hỏi hay và câu trả lời hay :)
netvope

Câu trả lời:


123

Backticks là một bí danh không dùng nữa cho repr(). Đừng sử dụng chúng nữa, cú pháp đã bị xóa trong Python 3.0.

Sử dụng backticks dường như nhanh hơn so với sử dụng repr(num)hoặc num.__repr__()trong phiên bản 2.x. Tôi đoán đó là vì cần phải tra cứu từ điển bổ sung trong không gian tên chung (for repr) hoặc trong không gian tên của đối tượng (for __repr__), tương ứng.


Sử dụng dismô-đun chứng minh giả định của tôi:

def f1(a):
    return repr(a)

def f2(a):
    return a.__repr__()

def f3(a):
    return `a`

Các chương trình tháo lắp:

>>> import dis
>>> dis.dis(f1)
  3           0 LOAD_GLOBAL              0 (repr)
              3 LOAD_FAST                0 (a)
              6 CALL_FUNCTION            1
              9 RETURN_VALUE
>>> dis.dis(f2)
  6           0 LOAD_FAST                0 (a)
              3 LOAD_ATTR                0 (__repr__)
              6 CALL_FUNCTION            0
              9 RETURN_VALUE        
>>> dis.dis(f3)
  9           0 LOAD_FAST                0 (a)
              3 UNARY_CONVERT       
              4 RETURN_VALUE   

f1liên quan đến tra cứu toàn cục repr, f2tra cứu thuộc tính __repr__, trong khi toán tử biểu tượng nền được triển khai trong một opcode riêng biệt. Vì không có chi phí cho việc tra cứu từ điển ( LOAD_GLOBAL/ LOAD_ATTR) cũng như cho các cuộc gọi hàm ( CALL_FUNCTION), dấu gạch chéo nhanh hơn.

Tôi đoán rằng những người dùng Python đã quyết định rằng việc có một hoạt động cấp thấp riêng biệt cho repr()nó là không đáng và việc có cả hai repr()và dấu lùi vi phạm nguyên tắc

"Nên có một-- và tốt nhất là chỉ có một - cách thức đơn giản để làm điều đó"

vì vậy tính năng này đã bị loại bỏ trong Python 3.0.


Tôi muốn tìm, làm thế nào bạn có thể thay thế các dấu gạch ngược bằng một số lệnh gọi hàm, nhưng có vẻ như không thể, hoặc là nó?
Jiri

2
Sử dụng repr () thay vì backticks. Backticks là cú pháp khấu hao cho repr () đến 3.0. Tôi thực sự thích giao diện của backticks hơn là sau đó gọi hàm KHÁC.
Dominic Bou-Samra

8
Lý do backticks không được chấp nhận cũng là do bản thân ký tự `; nó có thể khó nhập (trên một số bàn phím), khó nhìn thấy nó là gì, khó in chính xác trong sách Python. Vv
u0b34a0f6ae

4
@ kaizer.se: Cảm ơn bạn đã chỉ ra điều đó. Đây có lẽ là lý do chính dẫn đến việc đánh rơi backticks, xem tuyên bố Guidos trong
Ferdinand Beyer

Câu hỏi ban đầu mà điều này được đăng là vì tôi thực sự không thể tìm thấy dấu gạch lưng trên bàn phím của mình;) Bên dưới dấu ngã có vẻ như sau khi googling.
Dominic Bou-Samra

10

Trích dẫn backtick thường không hữu ích và đã biến mất trong Python 3.

Đối với những gì nó đáng giá, điều này:

''.join(map(repr, xrange(10000000)))

nhanh hơn một chút so với phiên bản backtick đối với tôi. Nhưng lo lắng về điều này có lẽ là một sự tối ưu hóa quá sớm.


2
Tại sao lại đi lùi một bước và sử dụng bản đồ thay vì hiểu danh sách / trình lặp?
nikow

4
Trên thực tế, timeitmang lại kết quả nhanh ''.join(map(repr, xrange(0, 1000000)))hơn cho ''.join([repr(i) for i in xrange(0, 1000000)])(thậm chí tệ hơn cho ''.join( (repr(i) for i in xrange(0, 1000000)) )). Có một chút thất vọng ;-)
RedGlyph

8
Kết quả của bobince không gây ngạc nhiên cho tôi. Theo quy tắc chung, các vòng lặp ẩn trong Python nhanh hơn các vòng lặp tường minh, thường nhanh hơn đáng kể. mapđược triển khai bằng C, sử dụng vòng lặp C, nhanh hơn nhiều so với vòng lặp Python được thực thi trong máy ảo.
Ferdinand Beyer

7
Cũng không ngạc nhiên, nó chỉ quá tệ đối với danh tiếng của danh sách hiểu được (với 30% lượt truy cập trong ví dụ này). Nhưng tôi muốn có mã rõ ràng hơn là tốc độ nhanh trừ khi điều này thực sự quan trọng, vì vậy không có vấn đề gì lớn ở đây. Điều đó đang được nói, hàm map () không làm tôi thấy rõ ràng, LC đôi khi được đánh giá quá cao.
RedGlyph

4
mapcó vẻ hoàn toàn rõ ràng và ngắn gọn đối với tôi, và tôi thậm chí không biết Python.
Zenexer

1

Suy đoán của tôi là điều numđó không xác định phương pháp __str__(), vì vậy str()phải thực hiện tra cứu thứ hai __repr__.

Các backticks tìm kiếm trực tiếp __repr__. Nếu điều đó là đúng, thì việc sử dụng repr()thay vì các que ngược sẽ cho bạn kết quả tương tự.

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.