Python:如何用最少的代码扩展一个巨大的 class?
Python: How to extend a huge class with minimum lines of code?
原始问题描述
当我使用 numpy
实现一些机器学习算法时出现问题。我想要一些新的 class ludmo
,其 与 numpy.ndarray
的工作方式相同,但具有更多属性。例如,使用新的 属性 ludmo.foo
。我尝试了以下几种方法,但 none 令人满意。
1。包装
首先,我为 numpy.ndarray
创建了一个包装器 class,因为
import numpy as np
class ludmo(object):
def __init__(self)
self.foo = None
self.data = np.array([])
但是当我使用某些函数(在我无法修改的 scikit-learn
中)来操作 np.ndarray
实例列表时,我必须首先提取每个 data
字段 ludmo
对象并将它们收集到列表中。之后对列表进行排序,我丢失了 data
和原始 ludmo
对象之间的对应关系。
2。继承
然后我试图让 ludmo
成为 numpy.ndarray
的子class,因为
import numpy as np
class ludmo(np.ndarray):
def __init__(self, shape, dtype=float, buffer=None, offset=0, strides=None, order=None)
super().__init__(shape, dtype, buffer, offset, strides, order)
self.foo = None
但是另一个问题出现了:创建numpy.ndarray
对象最常见的方法是numpy.array(some_list)
,returns一个numpy.ndarray
对象,我必须转换它到 ludmo
对象。但是直到现在我还没有找到好的方法来做到这一点;简单地更改 __class__
属性将导致错误。
我是 Python 和 numpy 的新手,所以一定有一些我不知道的优雅方法。任何建议表示赞赏。
谁能给出一个通用的解决方案就更好了,不仅适用于numpy.ndarray
class 也适用于各种class。
既然你问的是通用解决方案,这里有一个你可以使用的通用包装器 class:(来自 http://code.activestate.com/recipes/577555-object-wrapper-class/ )
class Wrapper(object):
'''
Object wrapper class.
This a wrapper for objects. It is initialiesed with the object to wrap
and then proxies the unhandled getattribute methods to it.
Other classes are to inherit from it.
'''
def __init__(self, obj):
'''
Wrapper constructor.
@param obj: object to wrap
'''
# wrap the object
self._wrapped_obj = obj
def __getattr__(self, attr):
# see if this object has attr
# NOTE do not use hasattr, it goes into
# infinite recurrsion
if attr in self.__dict__:
# this object has it
return getattr(self, attr)
# proxy to the wrapped object
return getattr(self._wrapped_obj, attr)
其工作方式是:
当例如skicit 会调用 ludmo.data python 实际上会调用
ludmo.__getattribute__('data')
如果 ludmo 没有 'data' 属性,python 将调用
ludmo.__getattr__('data')
通过重写 __getattr__
函数拦截此调用,检查您的 ludmo 是否具有 data
属性(同样,否则您可能会进入递归),并将调用发送到您的内部对象.因此,您应该涵盖了对内部 numpy 对象的所有可能调用。
更新:
您还必须以相同的方式实施 __setattr__
,否则您会得到这个
>>> class bla(object):
... def __init__(self):
... self.a = 1
... def foo(self):
... print self.a
...
>>> d = Wrapper(bla())
>>> d.a
1
>>> d.foo()
1
>>> d.a = 2
>>> d.a
2
>>> d.foo()
1
并且您可能还想设置一个新的元class来拦截对新样式 classes 的魔术函数的调用(完整的 class 请参阅 https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/wrapper.py
有关信息,请参阅 How can I intercept calls to python's "magic" methods in new style classes?
)
但是,仅当您仍然希望能够访问 x.__name__
或 x.__file__
并从包装的 class 中获取魔法属性时才需要这样做,而不是您的 class.
# create proxies for wrapped object's double-underscore attributes
class __metaclass__(type):
def __init__(cls, name, bases, dct):
def make_proxy(name):
def proxy(self, *args):
return getattr(self._obj, name)
return proxy
type.__init__(cls, name, bases, dct)
if cls.__wraps__:
ignore = set("__%s__" % n for n in cls.__ignore__.split())
for name in dir(cls.__wraps__):
if name.startswith("__"):
if name not in ignore and name not in dct:
setattr(cls, name, property(make_proxy(name)))
作为 explained in the docs,您可以将自己的方法添加到 np.ndarray
中:
import numpy as np
class Ludmo(np.ndarray):
def sumcols(self):
return self.sum(axis=1)
def sumrows(self):
return self.sum(axis=0)
def randomize(self):
self[:] = np.random.rand(*self.shape)
然后使用 the np.ndarray.view()
method:
创建实例
a = np.random.rand(4,5).view(Ludmo)
并使用__array_finalize__()
方法定义新属性:
def __array_finalize__(self, arr):
self.foo = 'foo'
原始问题描述
当我使用 numpy
实现一些机器学习算法时出现问题。我想要一些新的 class ludmo
,其 与 numpy.ndarray
的工作方式相同,但具有更多属性。例如,使用新的 属性 ludmo.foo
。我尝试了以下几种方法,但 none 令人满意。
1。包装
首先,我为 numpy.ndarray
创建了一个包装器 class,因为
import numpy as np
class ludmo(object):
def __init__(self)
self.foo = None
self.data = np.array([])
但是当我使用某些函数(在我无法修改的 scikit-learn
中)来操作 np.ndarray
实例列表时,我必须首先提取每个 data
字段 ludmo
对象并将它们收集到列表中。之后对列表进行排序,我丢失了 data
和原始 ludmo
对象之间的对应关系。
2。继承
然后我试图让 ludmo
成为 numpy.ndarray
的子class,因为
import numpy as np
class ludmo(np.ndarray):
def __init__(self, shape, dtype=float, buffer=None, offset=0, strides=None, order=None)
super().__init__(shape, dtype, buffer, offset, strides, order)
self.foo = None
但是另一个问题出现了:创建numpy.ndarray
对象最常见的方法是numpy.array(some_list)
,returns一个numpy.ndarray
对象,我必须转换它到 ludmo
对象。但是直到现在我还没有找到好的方法来做到这一点;简单地更改 __class__
属性将导致错误。
我是 Python 和 numpy 的新手,所以一定有一些我不知道的优雅方法。任何建议表示赞赏。
谁能给出一个通用的解决方案就更好了,不仅适用于numpy.ndarray
class 也适用于各种class。
既然你问的是通用解决方案,这里有一个你可以使用的通用包装器 class:(来自 http://code.activestate.com/recipes/577555-object-wrapper-class/ )
class Wrapper(object):
'''
Object wrapper class.
This a wrapper for objects. It is initialiesed with the object to wrap
and then proxies the unhandled getattribute methods to it.
Other classes are to inherit from it.
'''
def __init__(self, obj):
'''
Wrapper constructor.
@param obj: object to wrap
'''
# wrap the object
self._wrapped_obj = obj
def __getattr__(self, attr):
# see if this object has attr
# NOTE do not use hasattr, it goes into
# infinite recurrsion
if attr in self.__dict__:
# this object has it
return getattr(self, attr)
# proxy to the wrapped object
return getattr(self._wrapped_obj, attr)
其工作方式是:
当例如skicit 会调用 ludmo.data python 实际上会调用
ludmo.__getattribute__('data')
如果 ludmo 没有 'data' 属性,python 将调用
ludmo.__getattr__('data')
通过重写 __getattr__
函数拦截此调用,检查您的 ludmo 是否具有 data
属性(同样,否则您可能会进入递归),并将调用发送到您的内部对象.因此,您应该涵盖了对内部 numpy 对象的所有可能调用。
更新:
您还必须以相同的方式实施 __setattr__
,否则您会得到这个
>>> class bla(object):
... def __init__(self):
... self.a = 1
... def foo(self):
... print self.a
...
>>> d = Wrapper(bla())
>>> d.a
1
>>> d.foo()
1
>>> d.a = 2
>>> d.a
2
>>> d.foo()
1
并且您可能还想设置一个新的元class来拦截对新样式 classes 的魔术函数的调用(完整的 class 请参阅 https://github.com/hpcugent/vsc-base/blob/master/lib/vsc/utils/wrapper.py
有关信息,请参阅 How can I intercept calls to python's "magic" methods in new style classes?
)
但是,仅当您仍然希望能够访问 x.__name__
或 x.__file__
并从包装的 class 中获取魔法属性时才需要这样做,而不是您的 class.
# create proxies for wrapped object's double-underscore attributes
class __metaclass__(type):
def __init__(cls, name, bases, dct):
def make_proxy(name):
def proxy(self, *args):
return getattr(self._obj, name)
return proxy
type.__init__(cls, name, bases, dct)
if cls.__wraps__:
ignore = set("__%s__" % n for n in cls.__ignore__.split())
for name in dir(cls.__wraps__):
if name.startswith("__"):
if name not in ignore and name not in dct:
setattr(cls, name, property(make_proxy(name)))
作为 explained in the docs,您可以将自己的方法添加到 np.ndarray
中:
import numpy as np
class Ludmo(np.ndarray):
def sumcols(self):
return self.sum(axis=1)
def sumrows(self):
return self.sum(axis=0)
def randomize(self):
self[:] = np.random.rand(*self.shape)
然后使用 the np.ndarray.view()
method:
a = np.random.rand(4,5).view(Ludmo)
并使用__array_finalize__()
方法定义新属性:
def __array_finalize__(self, arr):
self.foo = 'foo'