2012-01-14 36 views
9

在我可以使用它作为字典的元素之前,我必须正式定义一个函数吗?如何声明带内联函数的字典

def my_func(): 
    print 'my_func' 

d = { 
    'function': my_func 
} 

我宁愿定义函数内联。我只是试图输入我想要做的事情,但python语法的空白策略使得在dict内定义一个内联func非常困难。有没有办法做到这一点?

+3

你能解释一下你为什么要这样做吗?如果你想从一个函数返回一个值,你可以用'd ['function'] = my_func()'把它放到字典中。如果你想要一个你再也不需要的函数,你可以使用'lambda'。 – Makoto 2012-01-14 17:59:06

+2

lambda不适用于我,因为我需要函数内的语句。该功能不是微不足道的。我想尽量避免宣布函数。我想要内联声明函数。 – 2012-01-14 19:04:48

+0

您如何期望能够使用当时未定义的任何内容(不是物理文件位置)? Python通过执行一个'def'语句来定义一个函数。 Python通过执行你的'd = {etc等等'''来定义你的字典。 – 2012-01-14 23:02:00

回答

13

答案似乎是没有办法在Python内联函数声明为一个字典的定义。感谢所有花时间参与贡献的人。

+2

这是最正确的答案。尽管知道五种左右的迂回方式在Python中做类似的事情是很好的,但是在Javascript中使用除lambda以外的匿名函数没有办法做到这一点,这些功能仅限于可以适用于一行的简单函数。 – 2013-01-08 08:21:24

+0

我想指出的Python没有做什么JavaScript本身是可读性和选择使用空格来指示控制块而不是支架的结果的原因。只有在使用Python多年之后,我才能够轻松地理解JavaScript的“优秀部分”。 – 2013-08-15 16:34:02

+0

同意了JavaScript了这部分的权利,它仅仅是如此简单和可读性与包含它们的对象在线声明一些功能 – 2014-04-16 19:00:34

3

一些功能可以很容易地“内联”匿名与lambda表达式,例如:

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

但对于任何半复杂(或using语句),你可能只是应事先定义它们。

+2

谢谢,但lambda不足。我需要在函数中声明。 – 2012-01-14 19:35:53

4

考虑使用lambda表达式,但请注意,lambda表达式必须功能,不能包含语句(见http://docs.python.org/reference/expressions.html#lambda

例如

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

另请注意,在python2中,print不是函数。所以,你需要做的要么:

from __future__ import print_function 

d = { 
    'function': print 
} 

或使用sys.stdout.write代替

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

我反对措辞“必须是功能,而不是程序”。无论您使用的这些术语中哪些相冲突的定义,都不适合。唯一的限制是lambda的主体必须是单个表达式。 – delnan 2012-01-14 18:17:32

+0

@delnan感谢您的澄清。回答编辑。我曾经把控制流程(例如'if'' for')作为程序,因此导致模糊性。 – qiao 2012-01-14 18:26:02

+0

感谢您关于'print'的注意事项。 – 2012-01-14 19:07:29

6

你真的需要一本字典,或者只是getitem访问?

如果是后者,那么使用类:

>>> 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

如果他真的想要实例化对象,这是一个好方法,希望是因为它们包含一些有用的状态。这里的关键是,你的例子没有显示,是类应该包含一些有用的状态值得实例化,否则他可以只用在我的答案中描述的方法,通过字符串键访问功能。 – 2012-01-14 18:45:49

+0

@DerekLitz。实用性胜过纯净。 OP的问题是关于在字典中内联函数,这与Python类已经是非常接近(即围绕字典的封装)。我的例子提供了OP真正需要的可读性和易维护形式的功能。 – ekhumoro 2012-01-14 19:07:12

+0

我想你错过了我的观点。实例化上面的d对象没有意义,这可能导致混淆。它增加了额外的复杂性,因为没有必要(因为你没有有意义的状态)。乍看起来似乎是一个字典,但实际上并不如此。您没有使用您正在使用Dispatch对象来提供功能的Class,并且恕我直言,如Dispatch对象所写,Dispatch对象不会添加任何有意义的功能或简化。 __getitem__应该被用来简化复杂类的使用,通过重用常用的Python语言,正如sqlalchemy对查询所做的那样。 – 2012-01-14 20:01:46

3

没有充分的理由要使用Python中的字典来写这个。这很奇怪,并不是命名空间函数的常用方法。

的是,这里采用Python的哲学是:

应该有one--和最好只有一个--obvious办法做到这一点。

结合

可读性计数。

这样做也会使得一些Python用户很难理解和阅读。

字典在这种情况下所做的好处是将字符串映射到函数并在字典中将它们命名空间,但是这个功能已经由模块和类提供,熟悉Python的人更容易理解。

例子:

模块方法:

#cool.py 

def cool(): 
    print 'cool' 

现在使用的模块,就像您使用您的字典:

​​

类方法:

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

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

编辑后评论如下:

argparse似乎很适合这个问题,所以你不必重新发明轮子。如果你决定完全自己实现它,尽管源头应该给你一些好的方向。无论如何,以下部分似乎适用于此用例:

15.4.4.5。超越sys.argv

有时,除了sys.argv的ArgumentParser解析参数 以外可能会有用。这可以通过将 字符串列表传递给parse_args()来完成。这对于在 交互式提示下进行测试很有用:

15.4.5.1。子commands¶

ArgumentParser.add_subparsers()

许多程序拆分它们的功能分成若干子命令,例如,使用svn程序可以调用子命令 像svn签,SVN更新,和svn提交。

15.4.4.6。名称空间对象

将ArgumentParser的属性分配给 已存在的对象而非新的命名空间对象也可能有用。这 可以通过指定的命名空间=关键字参数来实现:

更新,这是一个使用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>) 

我想指出的原因一个例子,我会建议argparse

  1. 主要需要使用表示选项和子选项的字符串映射到函数。
  2. 它很简单(在通过功能填充的argparse模块之后)。
  3. 使用Python标准库模块。这让让其他熟悉Python的人不需要深入了解实现细节就可以了解自己的工作,并且对于那些不了解实际情况的人来说,它们的记录非常详尽
  4. 许多额外的功能可以利用开箱即用(不是最好的理由!)。

使用argparse和策略模式一起

对于普通和简单的实现策略模式,这已经回答得非常好。

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

我真正想在这里实施的是战略模式。我想要一个包含多个选项和函数级别的字典,所以我可以这样做:'d [option1] [option2](args)'。但我想尽可能以最简单的方式做到这一点。在Groovy或JavaScript中,您可以在地图中内联关闭。这可能是我需要为我希望成为战略中的选项的职能创建一个班级。 – 2012-01-14 19:09:03

+0

想要做OP的工作有很多很好的理由。这是一种非常常见的技术,称为[Dynamic Dispatch](http://en.wikipedia.org/wiki/Dynamic_dispatch)。 – ekhumoro 2012-01-14 19:15:38

+0

@ekhumoro Python语言实现动态调度...的OP没有实现动态调度... – 2012-01-14 20:17:09

2

内联函数的要点是模糊词典和类实例之间的区别。例如,在JavaScript中,这种技术使得编写几乎没有重用性的控件类变得非常令人愉快。此外,API非常有用,因此符合众所周知的字典协议,是自解释的(双关意图)。

你可以在python中做到这一点 - 它看起来不像字典!实际上,您可以在任何范围内使用class关键字(即函数中的类def或类def中的类def),并且它的子代可以是您正在寻找的代码;只要检查一个定义的属性就好像它是一个javascript字典。

例子,如果它是真实的:

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

是实际完成的

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

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

这样你就可以说:

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

并以这种方式,你会得到与“内联”相同的逻辑分组。