在Java中,您可以使用匿名内部类定义新的内联类。当您只需要重写该类的单个方法时,这非常有用。
假设您要创建OptionParser
的子类,该子类仅覆盖单个方法(例如exit()
)。在Java中,您可以编写如下内容:
new OptionParser () {
public void exit() {
// body of the method
}
};
这段代码创建了一个匿名类,它扩展了OptionParser
并仅覆盖exit()
方法。
Python中有类似的习惯用法吗?在这些情况下使用哪种成语?
您可以使用type(name, bases, dict)
内置函数动态创建类。例如:
op = type("MyOptionParser", (OptionParser,object), {"foo": lambda self: "foo" })
op().foo()
由于OptionParser不是新式类,因此必须在基类列表中明确包含object
。
我通常在内部类中使用python3
class SomeSerializer():
class __Paginator(Paginator):
page_size = 10
# defining it for e.g. Rest:
pagination_class = __Paginator
# you could also be accessing it to e.g. create an instance via method:
def get_paginator(self):
return self.__Paginator()
因为我使用双下划线,这混合了“修改”与内部类的想法,从外部你仍然可以使用SomeSerializer._SomeSerializer__Paginator
和子类访问内部类,但SomeSerializer .__ Paginator将无法工作,这可能会或可能不会是你的如果你想要它更“匿名”。
但是,如果您不需要修改,我建议使用单个下划线的“私有”表示法。
在我的例子中,我需要的是一个快速子类来设置一些类属性,然后将它分配给我的RestSerializer类的class属性,因此双下划线将表示“不再使用它”并且可能会更改为没有下划线,如果我开始在别处重复使用它。
Java主要使用匿名类来模仿闭包或简单地编写代码块。因为在Python中你可以很容易地传递方法,所以不需要像匿名内部类那样笨重的构造:
def printStuff():
print "hello"
def doit(what):
what()
doit(printStuff)
编辑:我知道这不是这个特例所需要的。我刚刚描述了Java中匿名内部类最常见的python解决方案。
那么,类是第一类对象,因此您可以根据需要在方法中创建它们。例如
from optparse import OptionParser
def make_custom_op(i):
class MyOP(OptionParser):
def exit(self):
print 'custom exit called', i
return MyOP
custom_op_class = make_custom_op(3)
custom_op = custom_op_class()
custom_op.exit() # prints 'custom exit called 3'
dir(custom_op) # shows all the regular attributes of an OptionParser
但是,真的,为什么不在正常水平上定义班级呢?如果需要自定义它,请将自定义作为参数放入__init__
。
(编辑:修复代码中的输入错误)
您可以通过三种方式完成此任务:
选项3的示例(已编辑以删除“新”模块的使用 - 它已被弃用,我不知道):
import types
class someclass(object):
val = "Value"
def some_method(self):
print self.val
def some_method_upper(self):
print self.val.upper()
obj = someclass()
obj.some_method()
obj.some_method = types.MethodType(some_method_upper, obj)
obj.some_method()
Python不直接支持这种(匿名类),但由于其简洁的语法,它并不是必需的:
class MyOptionParser(OptionParser):
def exit(self, status=0, msg=None):
# body of method
p = MyOptionParser()
唯一的缺点是你将MyOptionParser添加到命名空间,但正如John Fouhy指出的那样,如果要多次执行此操作,可以将其隐藏在函数内部。
Python可能有更好的方法来解决您的问题。如果您可以提供有关您想要做的更具体的细节,那将有所帮助。
例如,如果需要在代码中的特定点更改被调用的方法,可以通过将函数作为参数传递来实现(函数是python中的第一类对象,可以将它们传递给函数等)。您还可以创建匿名lambda
函数(但它们仅限于单个表达式)。
此外,由于python非常动态,你可以在创建对象object.method1 = alternative_impl1
之后更改它的方法,虽然它实际上有点复杂,请参阅gnud's answer
在python中,您有使用lambda语句声明的匿名函数。我不太喜欢它们 - 它们不那么可读,而且功能有限。
但是,您所谈论的内容可能在python中以完全不同的方式实现:
class a(object):
def meth_a(self):
print "a"
def meth_b(obj):
print "b"
b = a()
b.__class__.meth_a = meth_b
您始终可以按变量隐藏类:
class var(...):
pass
var = var()
代替
var = new ...() {};
这就是你在Python 3.7中所做的
#!/usr/bin/env python3
class ExmapleClass:
def exit(self):
print('this should NOT print since we are going to override')
ExmapleClass= type('', (ExmapleClass,), {'exit': lambda self: print('you should see this printed only')})()
ExmapleClass.exit()