2012-01-14 78 views
9

Tôi có phải định nghĩa chính thức một hàm trước khi tôi có thể sử dụng nó làm thành phần của từ điển không?Làm thế nào để khai báo một từ điển có chức năng nội tuyến

def my_func(): 
    print 'my_func' 

d = { 
    'function': my_func 
} 

Tôi muốn xác định hàm nội dòng. Tôi chỉ cố gắng để loại ra những gì tôi muốn làm, nhưng các chính sách khoảng trắng của cú pháp python làm cho nó rất khó để xác định một func nội tuyến trong một dict. Có cách nào để làm điều này không?

+3

Bạn có thể giải thích lý do bạn muốn thực hiện việc này không? Nếu bạn muốn một giá trị trở lại từ một hàm, bạn có thể đặt nó vào từ điển bằng cách sử dụng 'd ['function'] = my_func()'; nếu bạn muốn một hàm bạn sẽ không bao giờ thực sự cần nữa, bạn có thể sử dụng 'lambda'. – Makoto

+2

Một lambda không làm việc cho tôi, bởi vì tôi cần các câu lệnh trong hàm. Hàm này không nhỏ. Tôi muốn tránh tuyên bố chức năng nếu tôi có thể. Tôi muốn hàm được khai báo nội dòng. –

+0

Làm thế nào để bạn mong đợi để có thể sử dụng bất cứ điều gì mà không được xác định tại thời điểm (không phải vị trí tập tin vật lý) nó sẽ được sử dụng? Python định nghĩa một hàm bằng cách thực thi câu lệnh 'def'. Python định nghĩa dict của bạn bằng cách thực thi 'd = {etc etc etc}'. –

Trả lời

13

Câu trả lời dường như là không có cách nào để khai báo một hàm inline một định nghĩa từ điển trong python. Nhờ tất cả những người dành thời gian để đóng góp.

+2

Đây là câu trả lời đúng nhất. Mặc dù rất hay để biết về 5 cách để làm điều gì đó tương tự trong Python, không có cách nào để làm điều đơn giản trong Javascript với các hàm ẩn danh khác với lambdas, được giới hạn trong các hàm đơn giản có thể khớp trên một dòng . –

+0

Tôi muốn chỉ ra lý do mà Python không làm những gì JavaScript làm cho khả năng đọc và hậu quả của việc chọn sử dụng khoảng trắng để chỉ khối điều khiển chứ không phải dấu ngoặc. Chỉ sau khi sử dụng Python trong nhiều năm, tôi đã có thể dễ dàng mò mẫm những "phần tốt" của JavaScript. –

+0

Đồng ý rằng JavaScript có phần này đúng, nó dễ dàng và dễ đọc để khai báo một số hàm nội tuyến với đối tượng chứa chúng –

3

Một số chức năng có thể dễ dàng 'inlined' nặc danh với các biểu thức lambda, ví dụ .:

>>> d={'function': lambda x : x**2} 
>>> d['function'](5) 
25 

Nhưng đối với bất cứ điều gì bán phức tạp (hoặc sử dụng báo cáo), bạn có thể chỉ cần xác định họ trước đó.

+2

Cảm ơn, nhưng một lambda là không đủ. Tôi cần các câu lệnh trong hàm. –

4

xem xét sử dụng lambdas, nhưng lưu ý rằng lambdas phải được chức năng và không thể chứa báo cáo (xem http://docs.python.org/reference/expressions.html#lambda)

ví dụ

d = { 'func': lambda x: x + 1 } 
# call d['func'](2) will return 3 

Ngoài ra, lưu ý rằng trong python2, print không phải là chức năng. Vì vậy, bạn phải làm một trong hai:

from __future__ import print_function 

d = { 
    'function': print 
} 

hoặc sử dụng sys.stdout.write thay

d = { 
    'function': sys.stdout.write 
} 
+0

Tôi phản đối cách diễn đạt "phải là hàm, không phải thủ tục". Bất kể định nghĩa mâu thuẫn nào của các thuật ngữ bạn sử dụng, không có định nghĩa nào thực sự phù hợp. Hạn chế duy nhất là cơ thể của lambda phải là một biểu thức duy nhất. – delnan

+0

@delnan Cảm ơn bạn đã làm rõ. Đã chỉnh sửa câu trả lời. Tôi đã sử dụng các luồng điều khiển (ví dụ: 'if'' for') làm thủ tục, do đó dẫn đến sự mơ hồ. – qiao

+0

Cảm ơn ghi chú về 'in'. –

6

Bạn có thực sự cần một cuốn từ điển, hoặc chỉ getitem truy cập?

Nếu sau này, sau đó sử dụng một lớp:

>>> class Dispatch(object): 
...  def funcA(self, *args): 
...   print('funcA%r' % (args,)) 
...  def funcB(self, *args): 
...   print('funcB%r' % (args,)) 
...  def __getitem__(self, name): 
...   return getattr(self, name) 
... 
>>> d = Dispatch() 
>>> 
>>> d['funcA'](1, 2, 3) 
funcA(1, 2, 3) 
+0

Đây là một cách tốt nếu anh ta thực sự muốn khởi tạo các đối tượng, hy vọng bởi vì chúng chứa một số trạng thái hữu ích.Điểm mấu chốt ở đây là, ví dụ của bạn không hiển thị, là lớp nên chứa một số trạng thái hữu ích để có giá trị instantiating, nếu không anh ta chỉ có thể sử dụng phương thức được mô tả trong câu trả lời của tôi để truy cập các hàm bằng khóa chuỗi. –

+0

@DerekLitz. Thực tiễn đánh bại sự tinh khiết. Câu hỏi của OP là về các chức năng nội tuyến trong một từ điển, rất gần với những gì một lớp python đã có (tức là một trình bao bọc xung quanh một dict). Ví dụ của tôi cung cấp chức năng mà OP thực sự cần ở dạng có thể đọc và dễ bảo trì. – ekhumoro

+0

Tôi nghĩ rằng bạn đã bỏ lỡ quan điểm của tôi. Việc khởi tạo đối tượng d ở trên không có mục đích có ý nghĩa, có thể dẫn đến nhầm lẫn. Nó bổ sung thêm sự phức tạp mà không cần thiết (vì bạn không có trạng thái có ý nghĩa). d dường như cư xử như một dict ở cái nhìn đầu tiên, nhưng trên thực tế thì không. Bạn không sử dụng một Class bạn đang sử dụng một đối tượng Dispatch để cung cấp chức năng, và IMHO được viết bằng văn bản đối tượng Dispatch không thêm chức năng và đơn giản hóa có ý nghĩa. __getitem__ nên được sử dụng để đơn giản hóa việc sử dụng một lớp phức tạp, bằng cách sử dụng lại các thành ngữ Python thông thường, như sqlalchemy làm cho các truy vấn. –

3

Không có lý do chính đáng để muốn viết này sử dụng một từ điển trong Python. Thật kỳ lạ và không phải là một cách phổ biến cho các chức năng không gian tên.

Các triết lý Python mà áp dụng ở đây là:

Nên có cùng-- và tốt nhất là chỉ có một cách --obvious để làm điều đó.

Kết hợp với

Độ khó đếm.

Làm theo cách này cũng làm cho mọi thứ khó hiểu và dễ đọc đối với người dùng Python điển hình.

Những điều tốt mà từ điển trong trường hợp này là các chuỗi bản đồ hoạt động và không gian tên chúng trong từ điển, nhưng chức năng này đã được cung cấp bởi cả mô đun và lớp và dễ hiểu hơn với những người quen thuộc với Python.

Ví dụ: phương pháp

Module:

#cool.py 

def cool(): 
    print 'cool' 

Bây giờ sử dụng các mô-đun như bạn sẽ được sử dụng dict của bạn: Phương pháp

import cool 
#cool.__dict__['cool']() 
#update - to the more correct idiom vars 
vars(cool)['cool']() 

Class:

class Cool(): 
    def cool(): 
     print 'cool' 

#Cool.__dict__['cool']() 
#update - to the more correct idiom vars 
vars(Cool)['cool']() 

Chỉnh sửa sau khi nhận xét bên dưới:

argparse có vẻ phù hợp với vấn đề này, vì vậy bạn không phải phát minh lại bánh xe. Nếu bạn quyết định thực hiện nó hoàn toàn cho mình mặc dù nguồn argparse sẽ cung cấp cho bạn một số hướng tốt. Dù sao, các phần bên dưới dường như áp dụng cho trường hợp sử dụng này:

15.4.4.5. Ngoài sys.argv

Thỉnh thoảng có thể hữu ích khi có đối số phân tích cú pháp ArgumentParser khác với đối số của sys.argv. Điều này có thể được thực hiện bằng cách chuyển một danh sách các chuỗi tới parse_args(). Điều này hữu ích khi thử nghiệm tại dấu nhắc tương tác :

15.4.5.1. Sub-commands¶

ArgumentParser.add_subparsers()

Nhiều chương trình chia tay chức năng của họ thành một số tiểu lệnh, ví dụ, chương trình svn có thể gọi tiểu lệnh như thanh toán svn, cập nhật svn, và svn cam kết.

15.4.4.6. Đối tượng Không gian tên

Cũng có thể hữu ích khi có một thuộc tính gán ArgumentParser cho đối tượng đã tồn tại, thay vì đối tượng Không gian tên mới. này có thể đạt được bằng cách xác định namespace = từ khóa luận:

Update, đây là một ví dụ sử dụng argparse

strategizer = argparse.ArgumentParser() 
strat_subs = strategizer.add_subparsers() 
math = strat_subs.add_parser('math') 
math_subs = math.add_subparsers() 
math_max = math_subs.add_parser('max') 
math_sum = math_subs.add_parser('sum') 
math_max.set_defaults(strategy=max) 
math_sum.set_defaults(strategy=sum) 

strategizer.parse_args('math max'.split()) 
Out[46]: Namespace(strategy=<built-in function max>) 

strategizer.parse_args('math sum'.split()) 
Out[47]: Namespace(strategy=<built-in function sum>) 

Tôi muốn lưu ý những lý do tôi muốn giới thiệu argparse

  1. Chủ yếu là yêu cầu sử dụng các chuỗi đại diện cho các tùy chọn và tùy chọn phụ để ánh xạ tới các hàm.
  2. Nó chết đơn giản (sau khi vượt qua mô-đun đầy tính năng argparse).
  3. Sử dụng Mô-đun thư viện chuẩn Python. Điều này cho phép những người khác quen thuộc với Python grok những gì bạn đang làm mà không cần phải đưa vào chi tiết triển khai và được tài liệu rất tốt cho những người không làm việc đó.
  4. Nhiều tính năng bổ sung có thể được tận dụng lợi thế ngoài hộp (không phải lý do tốt nhất!).

Sử dụng argparse và Chiến lược Pattern cùng

Đối với việc thực hiện đơn giản và đơn giản của mẫu chiến lược, điều này đã được trả lời rất tốt.

How to write Strategy Pattern in Python differently than example in Wikipedia?

#continuing from the above example 
class MathStudent(): 
    def do_math(self, numbers): 
     return self.strategy(numbers) 


maximus = strategizer.parse_args('math max'.split(), 
            namespace=MathStudent()) 

sumera = strategizer.parse_args('math sum'.split(), 
           namespace=MathStudent()) 

maximus.do_math([1, 2, 3]) 
Out[71]: 3 

sumera.do_math([1, 2, 3]) 
Out[72]: 6 
+0

Điều tôi thực sự cố gắng thực hiện ở đây là Mẫu chiến lược. Tôi muốn một từ điển có chứa một số mức độ tùy chọn và chức năng, vì vậy tôi có thể làm một cái gì đó như thế này: 'd [option1] [option2] (args)'. Nhưng tôi muốn làm điều đó một cách đơn giản nhất có thể. Trong Groovy hoặc JavaScript, bạn có thể đóng nội tuyến trong bản đồ. Có thể tôi cần tạo một lớp cho các hàm tôi muốn là các tùy chọn trong chiến lược. –

+0

Có nhiều lý do chính đáng để làm những gì mà OP đang làm. Đó là một kỹ thuật rất phổ biến được gọi là [Dynamic Dispatch] (http://en.wikipedia.org/wiki/Dynamic_dispatch). – ekhumoro

+0

@ekhumoro Ngôn ngữ Python thực hiện công văn động ... OP không triển khai công văn động ... –

2

Điểm của các chức năng nội tuyến là làm mờ sự khác biệt giữa từ điển và phiên bản lớp. Trong javascript, ví dụ, techinque này làm cho nó rất dễ chịu để viết các lớp kiểm soát có ít reusability. Ngoài ra, và rất hữu ích các API sau đó phù hợp với các giao thức từ điển nổi tiếng, được tự giải thích (chơi chữ dự định).

Bạn có thể làm điều này trong python - nó không giống như một từ điển! Trong thực tế, bạn có thể sử dụng từ khóa lớp trong BẤT K scope phạm vi (nghĩa là một lớp def trong một hàm, hoặc một lớp def bên trong của một lớp def), và đó là trẻ em có thể là dictonary bạn đang tìm kiếm; chỉ cần kiểm tra các thuộc tính của một định nghĩa như thể nó là một từ điển javascript.

Ví dụ như nếu đó là sự thật:

somedict = { 
    "foo":5, 
    "one_function":your method here, 
    "two_function":your method here, 
} 

là thực sự hoàn thành như

class somedict: 
    foo = 5 
    @classmethod 
    def one_method(self): 
     print self.foo 
     self.foo *= 2; 

    @classmethod 
    def two_method(self): 
     print self.foo 

Vì vậy mà sau đó bạn có thể nói:

somedict.foo   #(prints 5) 
somedict.one_method() #(prints 5) 
somedict.two_method() #(prints 10) 

Và bằng cách này, bạn sẽ có được cùng một nhóm hợp lý như bạn làm với "nội tuyến" của bạn.

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