Oop 子类'pathlib.Path'失败
我想增强类Oop 子类'pathlib.Path'失败,oop,python-3.4,Oop,Python 3.4,我想增强类pathlib.Path,但上面的简单示例不起作用 from pathlib import Path class PPath(Path): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) test = PPath("dir", "test.txt") 这是我收到的错误信息 Traceback (most recent call last): File "/Us
pathlib.Path
,但上面的简单示例不起作用
from pathlib import Path
class PPath(Path):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
test = PPath("dir", "test.txt")
这是我收到的错误信息
Traceback (most recent call last):
File "/Users/projetmbc/test.py", line 14, in <module>
test = PPath("dir", "test.txt")
File "/anaconda/lib/python3.4/pathlib.py", line 907, in __new__
self = cls._from_parts(args, init=False)
File "/anaconda/lib/python3.4/pathlib.py", line 589, in _from_parts
drv, root, parts = self._parse_args(args)
File "/anaconda/lib/python3.4/pathlib.py", line 582, in _parse_args
return cls._flavour.parse_parts(parts)
AttributeError: type object 'PPath' has no attribute '_flavour'
回溯(最近一次呼叫最后一次):
文件“/Users/projetmbc/test.py”,第14行,在
test=PPath(“dir”、“test.txt”)
文件“/anaconda/lib/python3.4/pathlib.py”,第907行,新__
self=cls.\u来自零件(args,init=False)
文件“/anaconda/lib/python3.4/pathlib.py”,第589行,在_from_parts中
drv,root,parts=self.\u parse\u args(args)
文件“/anaconda/lib/python3.4/pathlib.py”,第582行,在参数中
返回cls.\u flavor.parse\u部分(parts)
AttributeError:类型对象“PPath”没有属性“\u”
我做错了什么?是路径
类的定义。它做了一些相当聪明的事情。它不是直接从它的\uuuuu new\uuuuu()
返回路径的实例,而是返回子类的实例,但前提是它是作为路径()
直接调用的(而不是作为子类)
否则,它将通过WindowsPath()
或PosixPath()
调用,这两种方法都通过多重继承提供了\u
类属性。在子类化时,还必须提供此属性。为此,您可能需要实例化和/或子类化该类。API不支持这一部分,因此您的代码可能会在Python的未来版本中中断
TL;DR:下面是一个简单的方法,可以对Kevin的观察结果进行处理
class PPath():
def __init__(self, *args, **kwargs):
self.path = Path(*args, **kwargs)
然后我需要使用一个技巧,以便将所有路径的方法自动绑定到我的PPpath类。我认为这样做会很有趣。注意
在对Python开发列表进行了一点讨论之后,我开始了本文
临时解决办法
很抱歉这个双重回答,但这里有一个方法来实现我想要的。感谢Kevin为我指出了pathlib
的源代码,以及我们这里有构造函数的事实
import pathlib
import os
def _extramethod(cls, n):
print("=== "*n)
class PathPlus(pathlib.Path):
def __new__(cls, *args):
if cls is PathPlus:
cls = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath
setattr(cls, "extramethod", _extramethod)
return cls._from_parts(args)
test = PathPlus("C:", "Users", "projetmbc", "onefile.ext")
print("File ?", test.is_file())
print("Dir ?", test.is_dir())
print("New name:", test.with_name("new.name"))
print("Drive ?", test.drive)
test.extramethod(4)
这将打印以下行
File ? False
Dir ? False
New name: C:/Users/projetmbc/new.name
Drive ?
=== === === ===
您可以对具体实现进行子类化,这样可以:
class Path(type(pathlib.Path())):
下面是我用这个做的:
import pathlib
class Path(type(pathlib.Path())):
def open(self, mode='r', buffering=-1, encoding=None, errors=None, newline=None):
if encoding is None and 'b' not in mode:
encoding = 'utf-8'
return super().open(mode, buffering, encoding, errors, newline)
Path('/tmp/a.txt').write_text("я")
这也是工作
from pathlib import Path
class SystemConfigPath(type(Path())):
def __new__(cls, **kwargs):
path = cls._std_etc()
return super().__new__(cls, path, **kwargs)
@staticmethod
def _std_etc():
return '/etc'
name = SystemConfigPath()
name = name / 'apt'
print(name)
印刷品:
/etc/apt
@staticmethod可以被@classmethod取代,我也一直在努力解决这个问题
下面是我所做的,从pathlib模块学习。
在我看来,这是一种更干净的方法,但是如果pathlib模块更改了它的实现,它可能无法保持
from pathlib import Path
import os
import pathlib
class PPath(Path):
_flavour = pathlib._windows_flavour if os.name == 'nt' else pathlib._posix_flavour
def __new__(cls, *args):
return super(PPath, cls).__new__(cls, *args)
def __init__(self, *args):
super().__init__() #Path.__init__ does not take any arg (all is done in new)
self._some_instance_ppath_value = self.exists() #Path method
def some_ppath_method(self, *args):
pass
test = PPath("dir", "test.txt")
您可能能够简化您的生活,这取决于您想要扩展Path(或PosixPath,或WindowsPath)的原因。在我的例子中,我想实现一个文件类,该类包含所有Path方法和其他一些方法。然而,我实际上并不关心isinstance(File(),Path)是否存在
代表团工作出色:
class File:
def __init__(self, path):
self.path = pathlib.Path(path)
...
def __getattr__(self, attr):
return getattr(self.path, attr)
def foobar(self):
...
现在,如果file=file('/a/b/c'),我可以在file上使用整个路径接口,还可以执行file.foobar()。结合前面的一些答案,您也可以编写:
类MyPath(pathlib.Path):
_味=类型(pathlib.Path())。\u味
对于传统的Python API来说,这是一个多么奇怪的选择。我想我必须照你的建议去做。这需要读取源代码。这不是问题,只是一点无聊的东西。@projetmbc:IMHO这是一个糟糕的设计;超类不应该显示其子类的知识,更不用说以这种方式依赖它们了<代码>路径()
应该是工厂函数。这可能值得一个bug报告,但由于这是一个主观意见的问题,我不确定bug追踪器是最好的开始。您可能会在Python或其他邮件列表上进行更有成效的对话,我想您和我都在Python开发人员邮件列表上发布了一条消息。另一方面,我的答案中的挑战是一件有趣的事情。我不会称之为聪明的自动绑定:尝试覆盖\uuu getattr\uuu
。这不会捕获神奇的方法,因此您还需要覆盖\uuuu div\uuuu
和(可能)覆盖\uu rdiv\uuuu
以获得foo/bar
语法。我的意思是说\uuuu truediv\uuuu
或者\uuu rtruediv\uuuu
。我已经更新了我的代码,以便自动使用dediv
语法。现在,我的主要问题是找到一种自动方法将Path
的所有公共方法(如is\u file
)绑定到我的类。再次,使用\uu getattr\uuuu
将属性访问重定向到Path
对象。这也会影响正常的方法。我会在下周尝试。如果我发现有用的东西,我会把它放在这里。我不确定这是个好主意。基本上,您将额外的方法直接附加到WindowsPath
或PosixPath
类,这意味着它将可用于这些类的所有实例,而不仅仅是通过PathPlus
创建的实例。我想和您一样,但目前我使用的是这个不太完美的解决方案。为什么?如果我使用增强版的类路径,我不关心Windowsäth或PosixPath。事实上,在Python开发人员的邮件列表上,Guido自己说类路径的子类化必须比现在更容易实现。作为结论,我的解决方案是在路径变得更加pythonic之前进行临时修补。谢谢。这个方法很难看,但比我以前的方法要差得多。您可以按照下面的讨论进行操作。也许有一天他们会发布一个我们还没有遇到的解决方案。非常感谢!如果要使用file=file(“a/b/c”)
进行实例化,那么在\uuu init\uuuu
中不需要一个self.path=pathlib.path(path)
,即str
参数到\uu init\uuu
的path
参数吗?当然,self.path需要是一个pathlib.path。好的,你应该在回答中调整它(目前无法正常工作)好的,我修复了init。