考虑到Python的动态,如果不可能的话,我会感到震惊:
我想更改sys.stdout.write
的实现。
我从这个答案中得到了我的另一个问题的想法:https://stackoverflow.com/a/24492990/901641
我试着写这个:
original_stdoutWrite = sys.stdout.write
def new_stdoutWrite(*a, **kw):
original_stdoutWrite("The new one was called! ")
original_stdoutWrite(*a, **kw)
sys.stdout.write = new_stdoutWrite
但它告诉我AttributeError: 'file' object attribute 'write' is read-only
。
这是一个很好的尝试,让我不要做一些潜在的(可能)愚蠢的事情,但我真的很想继续这样做。我怀疑解释器有一些我可以修改的查找表,但我在Google上找不到类似的东西。 __setattr__
也不起作用 - 它返回了与只读属性完全相同的错误。
我正在寻找一个Python 2.7解决方案,如果这很重要,虽然没有理由拒绝投入适用于其他版本的答案,因为我怀疑未来的其他人会在这里看到与其他版本类似的问题。
答案 0 :(得分:20)
尽管它具有动态性,但它不允许使用猴子修补内置类型,例如file
。它甚至可以通过修改此类型的__dict__
来阻止您这样做 - __dict__
属性返回包含在只读代理中的dict,因此分配给file.write
和{ {1}}失败。并且至少有两个很好的理由:
C代码要求file.__dict__['write']
内置类型与file
类型结构相对应,PyFile
与内部使用的file.write
函数相对应。 / p>
Python实现了对类型的属性访问的缓存,以加速方法查找和实例方法创建。如果允许直接分配到类型dicts,则该缓存将被破坏。
当然,允许使用Python实现的类补丁,它可以很好地处理动态修改。
然而......如果您真的知道自己在做什么,可以使用PyFile_Write()
之类的低级API来挂钩实现并转到类型dict。例如:
ctypes
答案 1 :(得分:3)
尽管Python主要是动态语言,但有str
,file
(包括stdout
),dict
和list
等本机对象类型实际上是在低级别C中实现的,并且完全静态:
>>> a = []
>>> a.append = 'something else'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object attribute 'append' is read-only
>>> a.hello = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute 'hello'
>>> a.__dict__ # normal python classes would have this
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'list' object has no attribute '__dict__'
如果您的对象是本机C代码,那么您唯一的希望是使用实际的常规类。对于您的情况,如上所述,您可以执行以下操作:
class NewOut(type(sys.stdout)):
def write(self, *args, **kwargs):
super(NewOut, self).write('The new one was called! ')
super(NewOut, self).write(*args, **kwargs)
sys.stdout = NewOut()
或者,执行类似于原始代码的操作:
original_stdoutWrite = sys.stdout.write
class MyClass(object):
pass
sys.stdout = MyClass()
def new_stdoutWrite(*a, **kw):
original_stdoutWrite("The new one was called! ")
original_stdoutWrite(*a, **kw)
sys.stdout.write = new_stdoutWrite