2017-09-08 17 views
9

Tôi có một từ điển có giá trị đôi khi là chuỗi và đôi khi là một hàm. Đối với các giá trị có chức năng là có một cách để thực hiện các chức năng mà không cần gõ một cách rõ ràng () khi khóa được truy cập?Giá trị từ điển là hàm được gọi khi khóa được truy cập, mà không sử dụng "()"

Ví dụ:

d = {1: "A", 2: "B", 3: fn_1} 
d[3]() # To run function 

Tôi muốn:

d = {1: "A", 2: "B", 3: magic(fn_1)} 
d[3] # To run function 
+5

Tại sao không '()'? Đừng đan áo len quanh nút ... – Alexander

+2

Đừng làm điều này. 'Rõ ràng là tốt hơn là ngầm '. Ý nghĩa trong mã của bạn là tìm kiếm một hàm và gọi nó; vì vậy mã * sẽ giống như * bạn đang làm chính xác điều đó. Là một sang một bên, trộn các loại như thế là một ý tưởng tồi; bạn cần phải kiểm tra xem bạn có một chuỗi đầu tiên không (kể từ khi bạn không thể gọi chuỗi), và điều đó làm cho cuộc sống của bạn khó khăn hơn. –

+1

... Nhưng trên phản ánh, có vẻ như bạn thực sự có câu hỏi * thiết kế * và nên đặt câu hỏi phản ánh chặt chẽ hơn những gì bạn thực sự muốn làm. Tức là, tại sao bạn có từ điển này ở nơi đầu tiên? –

Trả lời

6

Tôi không nghĩ đó là (dễ dàng) có thể với các thư viện chuẩn nhưng bạn có thể sử dụng lazy_object_proxy.Proxy từ các module lazy_object_proxy (bên thứ ba của nó vì vậy bạn cần phải cài đặt nó):

>>> import lazy_object_proxy 
>>> def fn_1(): 
...  print('calculation') 
...  return 1000 
... 
>>> d = {1: "A", 2: "B", 3: lazy_object_proxy.Proxy(fn_1)} 
>>> print(d[3]) 
calculation 
1000 
+0

Ah, giải pháp rất thú vị. Thư viện đó có vẻ sẽ rất hữu ích cho việc tính thời gian. +1 –

0

Sử dụng callable() để kiểm tra xem biến là, tốt, callable:

d = {1: "A", 2: "B", 3: fn_1} 
if callable(d[3]): 
    d[3]() 
else: 
    d[3] 
+2

Yêu cầu cụ thể nói mà không sử dụng '()' khi hàm được gọi là –

11

Một giải pháp khả thi, là để tạo ra một đối tượng từ điển tùy chỉnh mà thực hiện hành vi này:

>>> class CallableDict(dict): 
...  def __getitem__(self, key): 
...   val = super().__getitem__(key) 
...   if callable(val): 
...    return val() 
...   return val 
... 
>>> 
>>> d = CallableDict({1: "A", 2: "B", 3: lambda: print('run')}) 
>>> d[1] 
'A' 
>>> d[3] 
run 

Một perhaps more idiomatic solution sẽ được sử dụng try/except:

def __getitem__(self, key): 
    val = super().__getitem__(key) 
    try: 
     return val() 
    except TypeError: 
     return val 

Lưu ý tuy nhiên, phương pháp trên thực sự là để hoàn thành. Tôi sẽ không khuyên bạn nên sử dụng nó. As pointed out in the comments, nó sẽ che dấu TypeError được nâng lên bởi hàm. Bạn có thể kiểm tra nội dung chính xác của TypeError, nhưng tại thời điểm đó, bạn nên sử dụng kiểu LBYL.

+0

EAFP - 'try: return val(); ngoại trừ TypeError: trả về val'? – AChampion

+0

@AChampion Eh, tôi có thể sử dụng EAFP thay thế. Trong một số trường hợp, tôi thực sự không nghĩ rằng nó quan trọng nhiều :) Tôi thực sự đã không suy nghĩ về nó khi tôi đăng câu trả lời của tôi. –

+0

Loại trừ EAFPĐối tượng xảy ra bên trong hàm được gọi trong trường hợp này. Tôi sẽ không sử dụng nó. –

-2

Một giải pháp khác: bạn cũng có thể vượt qua một số phương pháp lớp học được trang trí bằng @property:

class Test: 
    @property 
    def method(self): 
     return 'X' 

d = {'a': 1, 'b': Test().method} 
print(d) 
print(d['a']) 
print(d['b']) 
+1

Đây không phải là chức năng được gọi khi khóa được truy cập. Nó chỉ đặt giá trị từ điển khi được định nghĩa: '{'a': 1, 'b': 'X'}' –

+0

Argh .... bạn nói đúng. Xấu hổ với tôi: / – msztolcman

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