为啥从 Python 中的对象继承,在不指定父对象时更改 __dict__ 的类型不会? [复制]

Posted

技术标签:

【中文标题】为啥从 Python 中的对象继承,在不指定父对象时更改 __dict__ 的类型不会? [复制]【英文标题】:Why does inherting from object in Python, change they type of the __dict__ when not specifying a parent does not? [duplicate]为什么从 Python 中的对象继承,在不指定父对象时更改 __dict__ 的类型不会? [复制] 【发布时间】:2013-10-04 20:16:37 【问题描述】:

我有一段简单的代码试图在 Python 中为file 提供便利。

class File:
    def __init__(this, *args):
        this._file = file(*args)

    def __del__(this):
        this._file.close()

def createCallForwarder(method):
    return lambda obj,*args: method(obj._file, *args)

_dict = file.__dict__
for (k,v) in zip(_dict.keys(), _dict.values()):
    if not (k.startswith('__') and k.endswith('__')):
        if v.__class__.__name__ == 'method_descriptor':
            File.__dict__[k] = createCallForwarder(v)

# get the repr method
File.__repr__ = createCallForwarder(dict_proxy['__repr__'])

如果我将File 更改为从object 继承,它不会让我分配方法。

为什么不一样?

【问题讨论】:

天哪,你想用你的代码实现什么?为什么不使用file 的子类,或者使用__getattr__ 挂钩来代理方法? 如果您想在新样式类中做同样的事情,请使用 setattrsetattr(File, k, createCallForwarder(v)) 谢谢!这正是我所需要的。我对 Python 没有太多经验。我只是想获得一个自行关闭的 File 对象,所以我不必关心。我不想泄露文件对象。 只是一个风格提示:按照惯例,Python 使用 self 而不是 this @AadityaKalsi:Python 文件对象已经这样做了。他们拥有自己的__del__处理程序。 【参考方案1】:

您根本不应该直接访问__dict__

改为使用__getattr__ method 代理对底层self._file 对象的调用:

class File(object):
    def __init__(self, *args):
        self._file = open(*args)

    def __getattr__(self, name):
        return getattr(self._file, name)

我还将代码切换为最佳实践;使用self 代替this 并使用open() 代替file()

对于新式对象(继承自object),使用setattr() 设置任意属性。但是,不需要使用呼叫转发器包装器。您也可以采用self._file绑定 方法并将它们直接设置在self 上:

class File(object):
    def __init__(self, *args):
        self._file = open(*args)
        for name in dir(self._file):
            setattr(self, name, getattr(self._file, name))

如果你想要的只是一个在垃圾收集时自动关闭的文件对象,那么你就白费了很多麻烦。 Python 文件对象已经有一个__del__ 处理程序正是这样做的。它只是没有作为显式的 __del__ 函数公开,而是 C 实现使用 deallocation function 在释放时调用 close_the_file(f)

然而,最佳实践是使用文件对象作为上下文管理器,使用with statement:

with open(somefilename) as fileobj:
    # do all sorts with fileobj

# here, fileobj will have been closed automatically.

引用file.close() documentation:

从 Python 2.5 开始,如果使用 with 语句,您可以避免显式调用此方法。例如,下面的代码会在with块退出时自动关闭f

from __future__ import with_statement # This isn't required in Python 2.6

with open("hello.txt") as f:
    for line in f:
        print line,

【讨论】:

谢谢!这很有帮助,我更喜​​欢 getattr 方式。我唯一遇到的问题是它不能很好地与 readline 一起用于自动完成。我有这个实现的原因是因为我有其他对象可能多次写入同一个文件,并且 open 多次是昂贵的。 @AadityaKalsi:在这种情况下,代理文件对象不会为您买任何任何东西。文件对象已经在 CPython 中自动关闭。 @AadityaKalsi:您可以实现 __dir__ method 或许有助于自动完成。【参考方案2】:

我只是想获得一个会自行关闭的 File 对象

使用with statement 将(除其他外)为您关闭文件:

with open('somefile.txt') as the_file:
   for line in the_file:
      # do something with line

# Once outside the with block, the file is automatically closed
print('somefile.txt is closed here') 

【讨论】:

以上是关于为啥从 Python 中的对象继承,在不指定父对象时更改 __dict__ 的类型不会? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

《Python》 面向对象三大特性之多态封装

Python中的面向对象(高级)之私有方法、多继承、多态

Python入门-6面向对象编程:08多重继承-mro()-super()获得父类的定义

JAVA中,子类将继承父类的所有属性和方法吗?为啥?

面向对象进阶

面向对象之继承——python篇