在Java中,您可以使用匿名内部类定义新的内联类。当您只需要重写该类的单个方法时,这非常有用。
假设您要创建OptionParser
的子类,该子类仅覆盖单个方法(例如exit()
)。在Java中,您可以编写如下内容:
new OptionParser () {
public void exit() {
// body of the method
}
};
这段代码创建了一个扩展OptionParser
并仅覆盖exit()
方法的匿名类。
Python中有类似的习惯用法吗?在这些情况下使用哪种成语?
答案 0 :(得分:38)
您可以使用type(name, bases, dict)
内置函数动态创建类。例如:
op = type("MyOptionParser", (OptionParser,object), {"foo": lambda self: "foo" })
op().foo()
由于OptionParser不是新式类,因此必须在基类列表中明确包含object
。
答案 1 :(得分:18)
Java主要使用匿名类来模仿闭包或简单地编写代码块。因为在Python中你可以很容易地传递方法,所以不需要像匿名内部类那样笨重的构造:
def printStuff():
print "hello"
def doit(what):
what()
doit(printStuff)
编辑:我知道这不是这种特殊情况所需要的。我刚刚描述了Java中匿名内部类最常见的python解决方案。
答案 2 :(得分:11)
您可以通过三种方式完成此任务:
选项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()
答案 3 :(得分:11)
嗯,类是第一类对象,因此如果需要,可以在方法中创建它们。 e.g。
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__
。
(编辑:修复代码中的输入错误)
答案 4 :(得分:6)
Python不直接支持这种(匿名类),但由于其简洁的语法,它并非真正必要:
class MyOptionParser(OptionParser):
def exit(self, status=0, msg=None):
# body of method
p = MyOptionParser()
唯一的缺点是你将MyOptionParser添加到你的命名空间,但正如John Fouhy指出的那样,如果要多次执行它,你可以在函数内隐藏它。
答案 5 :(得分:5)
Python可能有更好的方法来解决您的问题。如果你能提供你想要做的更具体的细节,那将会有所帮助。
例如,如果需要更改代码中特定点调用的方法,可以通过将函数作为参数传递来实现(函数是python中的第一类对象,可以将它们传递给函数等) )。您还可以创建匿名lambda
函数(但它们仅限于单个表达式)。
此外,由于python非常动态,你可以在创建对象的方法object.method1 = alternative_impl1
后更改它,虽然它实际上有点复杂,请参阅gnud's answer
答案 6 :(得分:2)
在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
答案 7 :(得分:0)
您始终可以按变量隐藏类:
class var(...):
pass
var = var()
而不是
var = new ...() {};
答案 8 :(得分:0)
这就是您在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()
答案 9 :(得分:0)
我通常在python3中使用内部类完成此操作
for(var i in records){
var data = records[i];
console.log(data.getString("Name"));
}
当我使用双下划线时,这将“ mangling”与内部类混合在一起,从外部您仍然可以使用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 .__ Paginator不起作用,这如果您希望它更“匿名”,则可能是您的愿望,也可能不是。
但是,如果您不需要整形,我建议对单个下划线使用“私有”表示法。
在我的情况下,我只需要一个快速子类来设置一些类属性,然后将其分配给我的RestSerializer类的类属性,因此双下划线将表示“根本不再使用它”和如果我开始在其他地方重新使用它,则可能没有下划线。
答案 10 :(得分:0)
不合常理,你可以使用一次性名称 _
作为派生类名称:
class _(OptionParser):
def exit(self):
pass # your override impl