2012-08-07 19 views
7

Gần đây tôi đã thử nghiệm với máy tạo python một chút, và tôi đã xem xét hành vi tò mò sau đây, và tôi tò mò muốn hiểu tại sao điều này xảy ra và những gì đang diễn ra:Python - hành vi tò mò/bất ngờ - ưu tiên của các nhà khai thác

def generating_test(n): 
    for a in range(n): 
     yield "a squared is %s" % a*a # Notice instead of a**2 we have written a*a 

for asquare in generating_test(3): 
    print asquare 

Output:

a squared is 1 
a squared is 2a squared is 2 

so với kịch bản sau đó tạo ra kết quả mong muốn:

def generating_test(n): 
    for a in range(n): 
     yield "a squared is %s" % a**2 # we use the correct a**2 here 

for asquare in generating_test(3): 
    print asquare 

Output:

a squared is 0 
a squared is 1 
a squared is 4 
+1

sang một bên: Nếu bạn thực sự định dạng một số nguyên, hãy sử dụng '% d', không phải'% s'. – kojiro

+5

Hoặc nắm lấy cú pháp 'định dạng' mới. Tôi nghĩ rằng nó đã được một chút dài khi tôi lần đầu tiên nhìn thấy nó, nhưng tôi đã phát triển để thích nó. – DSM

+0

Là một đồng nghiệp đã từng nói với tôi, * luôn * sử dụng một bộ dữ liệu sau '%' – chepner

Trả lời

20

này không có bất cứ điều gì để làm với máy phát điện:

>>> a = 2 
>>> "a squared is %s" % a 
'a squared is 2' 
>>> ("a squared is %s" % a)*a 
'a squared is 2a squared is 2' 
>>> "a squared is %s" % a*a 
'a squared is 2a squared is 2' 
>>> "a squared is %s" % (a*a) 
'a squared is 4' 

Các % op được thực hiện trước khi nhân, bằng cách sử dụng chuỗi và a đầu tiên như các đối số. Công cụ a**2 của bạn hoạt động vì số lần xem ** với a2 làm đối số được đánh giá trước %.

+0

Điều đó thật nhanh! – jamylak

+2

yeh đánh tôi với nó ... hầu như không: P –

+0

Rất thú vị, cảm ơn phản ứng nhanh - Tôi vẫn phải đợi 11 phút trước khi tôi có thể đánh dấu là đã chấp nhận. Tôi đã xóa các thẻ cho máy phát và năng suất vì chúng không liên quan. –

8

Python's order of operations là từ trái sang phải trừ khi PEMDAS áp dụng. Các nhà điều hành chuỗi suy rõ ràng có ưu tiên giống như modulo và nhân, bởi vì nếu bạn đảo ngược thứ tự, làm cho nhân trái của phép nội suy, nó được ưu tiên:

>>> print 3 * "a foo %s" % 'hi' 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: not enough arguments for format string 
>>> print 3 * "a foo %s" % ('hi', 'ho', 'yo') 
a foo hia foo hoa foo yo 

Tuy nhiên, như bạn đã chứng minh, át chủ bài lũy thừa thứ tự từ trái sang phải.

Cập nhật: Trong same document under Binary Arithmetic Operations rằng nó khẳng định một cái gì đó denotatively rõ ràng, nhưng connotatively liên quan:

... các nhà điều hành% cũng bị quá tải bởi chuỗi và unicode đối tượng để thực hiện chuỗi định dạng (hay còn gọi là nội suy).

Trong khi đó dường như chỉ được nói cho bạn những gì % hành không, tôi nghĩ rằng vị trí và bối cảnh của nó cũng cho bạn biết nó có ưu tiên như nhau cho dù nó được sử dụng như modulo hoặc suy.

+2

Tóm tắt ở phần cuối của tài liệu đó đặt nó rõ ràng hơn - cụ thể, chú thích cuối trang 8 nói: "Toán tử'% 'cũng được sử dụng để định dạng chuỗi; ưu tiên tương tự cũng được áp dụng". – lvc

+0

Hãy tưởng tượng nếu nó được nếu không ... bạn sẽ không thể phân tích mã Python cho đến khi bạn biết các loại thời gian chạy của các biểu thức con! – Aaron

+0

@Aaron * Mọi thứ sẽ rất khác nếu chúng không giống như chúng. * - [Anna Russell] (http://en.wikipedia.org/wiki/Anna_Russell). Nếu loại [chú thích] (http://www.python.org/dev/peps/pep-3107/) được yêu cầu bởi python và được sử dụng để thực thi kiểu tại thời gian biên dịch, nó sẽ là một ngôn ngữ khác, nhưng không phải là một ý tưởng điên rồ . :) – kojiro

5

Khi bạn quan sát hành vi không mong muốn, hãy bắt đầu phân tích bằng cách chưng cất nó với trường hợp đơn giản nhất có thể. Một trường hợp đơn giản sẽ dễ học và dễ hiểu hơn.

Các hành vi bất ngờ:

>>> 'hello %s' % 3 * 2 
'hello 3hello 3' 

(Bạn mong đợi 'hello 6')


Chúng tôi lý do Python phải được giải thích các lệnh như 'hello 3' * 2 hơn 'hello %d' % 6.Chúng tôi cố gắng thực hiện giải thích thứ hai với các dấu ngoặc đơn

>>> "hello %s" % (3*2) 
'hello 6' 

Eureka!

Chúng tôi đã chứng minh rằng toán tử định dạng chuỗi % có mức ưu tiên lớn hơn hoặc bằng nhau so với phép nhân. Chúng tôi kiểm tra tài liệu Python - có nó xác nhận điều này http://docs.python.org/reference/expressions.html#summary

Để xác nhận rằng các ưu tiên là như nhau, chúng ta có thể thử nó theo cách khác xung quanh:

>>> "%d,"*2%(1,2) 
'1,2,' 

Thấy dấu phẩy (,) được nhân đôi, chúng tôi lý do nhân số "%d," * 2 được thực hiện trước khi định dạng chuỗi %. Nếu phép nhân có thể đứng trước định dạng chuỗi và định dạng chuỗi trước phép nhân, chúng phải bằng nhau trước.