2015-04-15 17 views
7

Tôi đang tìm một số trợ giúp để hiểu các phương pháp hay nhất về từ điển trong Python.Được khuyến nghị sử dụng từ điển Python, hàm làm giá trị

Tôi có một ví dụ dưới đây:

def convert_to_celsius(temp, source): 
    conversion_dict = { 
     'kelvin': temp - 273.15, 
     'romer': (temp - 7.5) * 40/21 
    } 
    return conversion_dict[source] 


def convert_to_celsius_lambda(temp, source): 
    conversion_dict = { 
     'kelvin': lambda x: x - 273.15, 
     'romer': lambda x: (x - 7.5) * 40/21 
    } 
    return conversion_dict[source](temp) 

Rõ ràng, hai chức năng đạt được mục tiêu giống nhau, nhưng qua các phương tiện khác nhau. Ai đó có thể giúp tôi hiểu sự khác biệt tinh tế giữa hai người, và cách 'tốt nhất' để tiếp tục điều này sẽ là gì?

+0

Việc đầu tiên là tốt hơn trong trường hợp này! và sự khác biệt là trong thứ hai, giá trị của bạn là một hàm tính toán tạm thời và trả về nó! – Kasramvd

+0

Nếu bạn di chuyển 'conversion_dict' bằng' lambda '** bên ngoài ** của hàm, bạn không phải tạo lại nó mỗi khi bạn gọi hàm, điều này sẽ hiệu quả hơn. Nếu không, bạn cũng có thể sử dụng cái đầu tiên. – jonrsharpe

+0

@Kasra bạn có thể giải thích * tại sao * bạn nghĩ rằng, lý tưởng nhất là sử dụng dấu chấm câu ngoài dấu chấm than? – jonrsharpe

Trả lời

3

Nếu bạn có cả từ điển được tạo ra bên chức năng, sau đó cựu sẽ hiệu quả hơn - mặc dù này thực hiện trước đây hai tính toán khi chỉ có một là cần thiết, có overhead ở những phiên bản sau để tạo lambdas mỗi Hiện nó được gọi là:

>>> import timeit 
>>> setup = "from __main__ import convert_to_celsius, convert_to_celsius_lambda, convert_to_celsius_lambda_once" 
>>> timeit.timeit("convert_to_celsius(100, 'kelvin')", setup=setup) 
0.5716437913429102 
>>> timeit.timeit("convert_to_celsius_lambda(100, 'kelvin')", setup=setup) 
0.6484164544288618 

Tuy nhiên, nếu bạn di chuyển các từ điển của lambda s ngoài chức năng:

CONVERSION_DICT = { 
    'kelvin': lambda x: x - 273.15, 
    'romer': lambda x: (x - 7.5) * 40/21 
} 

def convert_to_celsius_lambda_once(temp, source): 
    return CONVERSION_DICT[source](temp) 

rồi sau này là hiệu quả hơn, như các đối tượng lambda chỉ được tạo ra một lần, và các chức năng chỉ thực hiện việc tính toán cần thiết trên mỗi cuộc gọi:

>>> timeit.timeit("convert_to_celsius_lambda_once(100, 'kelvin')", setup=setup) 
0.3904035060131186 

Lưu ý rằng điều này sẽ chỉ là một lợi ích trong đó hàm được gọi rất nhiều (trong trường hợp này là 1.000.000 lần), sao cho chi phí của việc tạo hai đối tượng hàm lambda nhỏ hơn thời gian lãng phí khi tính hai kết quả khi chỉ cần một kết quả.

+0

Cảm ơn! Giả sử rằng thay vì hai chuyển đổi, tôi có nhiều cặp khóa/giá trị trong từ điển. Rõ ràng, việc có dict bên ngoài hàm có ý nghĩa nhất, nhưng điều đó ảnh hưởng đến so sánh ban đầu như thế nào? – chungsangh

+0

@chungsangh Rất nhiều cặp ...? Có bao nhiêu đơn vị nhiệt độ có thể có ??? –

+0

Sử dụng ['timeit'] (https://docs.python.org/2/library/timeit.html) và tìm hiểu! Về cơ bản, 'convert_to_celsius_lambda' không bao giờ là câu trả lời đúng. Tôi mong đợi nhiều phím hơn sẽ làm cho lợi ích của 'convert_to_celsius_lambda_once' * lớn hơn * đối với bất kỳ cuộc gọi nào nhiều hơn, vì hiện nay có nhiều tính toán không cần thiết trên mỗi cuộc gọi đến' convert_to_celsius' (nhưng 'lambda's vẫn chỉ được tạo ra Một lần). – jonrsharpe

1

Từ điển là hoàn toàn vô nghĩa, vì bạn cần phải tạo lại nó trên mỗi cuộc gọi nhưng tất cả những gì bạn từng làm chỉ là một lần tra cứu. Juse sử dụng một số if:

def convert_to_celsius(temp, source): 
    if source == "kelvin": return temp - 273.15 
    elif source == "romer": return (temp - 7.5) * 40/21 
    raise KeyError("unknown temperature source '%s'" % source) 
+1

điều này không đạt được kết quả tương tự trong trường hợp mặc định. Mã OP sẽ phát ra lỗi nếu không tìm thấy mã nguồn – njzk2

+0

@ njzk2 Tôi biết, đó là lý do tại sao tôi có nhận xét. Tôi đã thay đổi nó để ném một 'KeyError'. – unwind

0

Mặc dù cả hai đều đạt được điều tương tự, phần đầu tiên dễ đọc hơn và nhanh hơn.

Trong ví dụ đầu tiên của bạn, bạn có một phép tính số học đơn giản sẽ được tính khi một lần gọi là convert_to_celsius.

Trong ví dụ thứ hai, bạn tính chỉ nhiệt độ yêu cầu.

Nếu bạn có hàm thứ hai thực hiện phép tính đắt tiền, thì có thể sẽ có ý nghĩa khi sử dụng hàm thay vào đó, nhưng đối với ví dụ cụ thể này thì không bắt buộc.

0

Như những người khác đã chỉ ra, không có lựa chọn nào của bạn là lý tưởng. Việc đầu tiên cả hai tính toán mỗi lần và có một dict không cần thiết. Người thứ hai phải tạo ra lambdas mỗi lần. Nếu ví dụ này là mục tiêu thì tôi đồng ý với thư giãn để chỉ sử dụng câu lệnh if. Nếu mục tiêu là để học một cái gì đó có thể được mở rộng sang mục đích khác, tôi thích phương pháp này:

convert_to_celsius = { 'kelvin' : lambda temp: temp - 273.15 , 
         'romer' : lambda temp: (temp-7.5) * 40/21} 

newtemp = convert_to_celsius[source](temp) 

defintions tính của bạn đều được lưu trữ với nhau và gọi hàm của bạn là gọn gàng và có ý nghĩa.

Các vấn đề liên quan