有些函数需要"常量"值(例如。不设计用于稍后重新定义),即不进行参数化。虽然每个函数的默认参数只存储一次,但是有些参数作为参数并没有太大的意义(例如。成为签名的一部分)。For (a not very useful)例子:
def foo(bar):
my_map = {"rab": barType,"oof": fooType}
return my_map.get(bar,defaultType)()
为每个调用重新定义这样一个常量会浪费CPU时间和RAM空间。其他一些方法是存储诸如模块级全局变量之类的常量,或者使函数成为可调用类,但是可能还有其他方法?
当执行模块级全局方法时,我在(表示为a)常量变量前面加上一个"_",以表明它不存在,不符合任何人的兴趣。尽管如此,我仍然觉得模块名称空间有点"受污染",更不用说使用像全局变量这样令人沮丧的东西了:
_my_map = {"rab": barType,"oof": fooType}
def foo(bar):
return _my_map.get(bar,defaultType)()
或者把它转换成类的方式。我将__call__作为一个类方法,以避免创建实例:
class foo:
my_map = {"rab": barType,"oof": fooType}
@classmethod
def __call__(cls,bar):
return cls.my_map.get(bar,defaultType)()
这些解够勾股定理吗?
还有其他方法吗?
作为一种实践,使用这样的"常量"可以吗?
注意,在我的示例中,这些对象不一定是实际的常量,但是它们的用途是这样使用的(并且可以这样认为)。
正如在其中一个答案中提到的(我也同意),您可能想要添加一条注释,以使它更加具体,即它是一个全局变量,而且,您希望阅读您的代码的人能够很好地理解Python。虽然我承认我也很好奇一个更优雅的解决方案!
全局常量很好。造成问题的是全球状态。
为什么要链接到xkcdsw而不是xkcd?o_0
将其设置为函数的属性:
def foo(bar):
return foo.my_map.get(bar, defaultType)()
foo.my_map = {"rab": barType,"oof": fooType}
,
在我看来,可调用类或闭包不够简单。
如果这可以在类定义中完成,您能提供一些见解吗?我尝试使用实例、类或静态方法,结果要么是AttributeError,要么是NameError;同样不明显的是,如果可能的话,函数属性是否可以保持"接近"函数定义(以文件中的行数表示)?
这两种方法都有效:gist.github.com/anossov/5411655。
我的错误是,我实际上没有使用实例方法测试它们(我认为我做了——当我尝试使用@staticmethod或classmethod来测试它们时,在某些情况下它会给出"AttributeError: 'instancemethod' object没有属性",这欺骗了我)。所以我真正的问题似乎是使用@classmethod和@staticmethod装饰器。gist.github.com/naxa/5411709
这将工作:gist.github.com/anossov/5411711,但它并不漂亮。
依我之见,模块级常量没有什么问题。
注意,根据PEP8,常数应该都是大写的,就像这样:
_MY_MAP = {"rab": barType,"oof": fooType}
def foo(bar):
return _MY_MAP.get(bar,defaultType)()
标准库中的正则表达式模块使用这种风格,许多已建立的第三方库也使用这种风格。如果你不相信,就去你的site-packages目录和grep:
egrep"^_?[A-Z]+ =" *
如果模块级全局对外部有意义,我还认为在Python中它是有用的。但是像这样的函数helper并不是很好的结构,因为只有它的名称显示了它的位置和用途。
我明白你的意思。我只是想指出,私有模块级常量相对来说比较常见,而且在Python中可能不被认为是反模式。我想这是品味的问题。
使之尽可能独立。您可以创建一个函数对象(又名函子)类,并给它一个__call__()方法或classmethod(但可能不是两者都有):
class bazType(object): pass
class barType(object): pass
class fooType(object): pass
class Foo(object):
_DEFAULT_TYPE = bazType
_MY_MAP = {"rab": barType,"oof": fooType}
def __call__(self, bar):
return self._MY_MAP.get(bar, self._DEFAULT_TYPE)()
@classmethod
def foo(cls, bar):
return cls._MY_MAP.get(bar, cls._DEFAULT_TYPE)()
# using classmethod
print Foo.foo("rab")
# using __call__ method
foo = Foo()
print foo("baz")
# alternative way to use classmethod
foo = Foo.foo
print foo("oof")
另一种方法是定义一个staticmethod,我将不对此进行说明,因为它与其他两个非常相似——但是我希望您能理解我的意思。
你也可以使用闭包:
def make_foo():
my_map = {"rab": barType,"oof": fooType}
def foo(bar):
return my_map.get(bar,defaultType)()
return foo
foo = make_foo()
我还建议将make_foo()改名为foo(),尽管这可能太多了;-)。