class Foo(object):
pass
foo = Foo()
def bar(self):
print 'bar'
Foo.bar = bar
foo.bar() #bar
来自JavaScript,如果“类”原型增加了某个属性。众所周知,该“类”的所有实例在其原型链中都具有该属性,因此不必对其任何实例或“子类”进行任何修改。
从这个意义上讲,像Python这样的基于类的语言如何实现Monkey修补?
答案 0 :(得分:11)
真正的问题是,怎么能不呢?在Python中,类本身就是一流的对象。通过查找实例上的属性,然后查找类,然后查找父类(按方法解析顺序)来解析对类实例的属性访问。这些查找都是在运行时完成的(就像Python中的所有内容一样)。如果在创建实例后向类添加属性,则实例仍将“看到”新属性,因为没有任何东西阻止它。
换句话说,它起作用是因为Python不缓存属性(除非你的代码有),因为它不使用负缓存或阴影类或任何会阻止它的优化技术(或者,当Python实现时,他们考虑到类可能会改变),因为一切都是运行时。
答案 1 :(得分:10)
我刚刚阅读了大量文档,据我所知,整个故事解决了foo.bar
如何解决,如下:
foo.__getattribute__
吗?如果是,请使用foo.__getattribute__('bar')
的结果。
__getattribute__
不会导致无限递归,但可能会执行它。)__getattribute__
,因为object
中提供了默认实现 - 但该实现属于以下过程。;))__getattribute__
中定义Foo
方法,并且访问foo.__getattribute__
,则会调用foo.__getattribute__('__getattribute__')
!但这样做不暗示无限递归 - 如果你小心;))bar
是Python运行时提供的属性的“特殊”名称(例如__dict__
,__class__
,__bases__
,__mro__
)?如果是这样,请使用它。 (据我所知,__getattribute__
属于这一类,避免了无限递归。)bar
dict中的foo.__dict__
?如果是,请使用foo.__dict__['bar']
。foo.__mro__
是否存在(即,foo
实际上是一个类)?如果是这样,
base
[1:]中的每个基类foo.__mro__
:
foo
本身,我们已经搜索过了。)bar
中有base.__dict__
吗?如果是这样:
x
成为base.__dict__['bar']
。x.__get__
?
x.__get__(foo, foo.__class__)
。bar
本身就是一个对象,Python编译器会自动为函数提供一个__get__
属性,该属性旨在以这种方式使用。)x
。base
的每个基类foo.__class__.__mro__
:
foo.__class__.__mro__[0]
将始终为foo.__class__
,即{{1在我们的示例中。)Foo
存在,我们也会这样做。这是因为类也有一个类:它的名称是foo.__mro__
,它提供了用于计算的方法等等首先是type
个属性。)__mro__
中有bar
吗?如果是这样:
base.__dict__
成为x
。base.__dict__['bar']
?
x.__get__
。x.__get__(foo, foo.__class__)
本身就是一个对象,Python编译器会自动为函数提供一个bar
属性,该属性旨在以这种方式使用。)__get__
。x
吗?如果是,请使用foo.__getattr__
。foo.__getattr__('bar')
。 raise AttributeError
实际上并不是一个函数 - 它是一个“方法包装器” - 但你可以想象它的实现模糊不清:
bar.__get__
顺便说一下,# Somewhere in the Python internals
class __method_wrapper(object):
def __init__(self, func):
self.func = func
def __call__(self, obj, cls):
return lambda *args, **kwargs: func(obj, *args, **kwargs)
# Except it actually returns a "bound method" object
# that uses cls for its __repr__
# and there is a __repr__ for the method_wrapper that I *think*
# uses the hashcode of the underlying function, rather than of itself,
# but I'm not sure.
# Automatically done after compiling bar
bar.__get__ = __method_wrapper(bar)
自动附加到__get__
(称为描述符)中发生的“绑定”或多或少是您拥有的原因为Python方法显式指定bar
参数。在Javascript中,self
本身就是神奇的;在Python中,它只是将事物绑定到this
神奇的过程。 ;)
是的,可以在您自己的对象上显式设置self
方法,并在将类属性设置为对象的实例然后访问它时让它执行特殊操作来自另一个类的实例。 Python 非常反射。 :)但是如果你想学习如何做到这一点,并且对这种情况有一个非常全面的了解,你have a lot阅读to do。 ;)