52

I found the pathlib syntax - or is it the Python syntax - surprising. I'd like to know how this makes the forward slash / act as a joiner of WindowsPaths etc. Does it override/overload / ? It seems to be in a magical context, the slash is between a WindowsPath type object and a string. If I try between 2 strings it fails to join the 2 strings (e.g. "123" / "123" fails)

p=pathlib.Path(".")

p
Out[66]: WindowsPath('.')

p.cwd()
Out[67]: WindowsPath('C:/Users/user1')

p.cwd() / "mydir"
Out[68]: WindowsPath('C:/Users/user1/mydir')
AbyxDev
  • 1,363
  • 16
  • 30
JoePythonKing
  • 1,080
  • 1
  • 9
  • 18

2 Answers2

57

The Path class has a __truediv__ method that returns another Path. You can do the same with your own classes:

>>> class WeirdThing(object):
        def __truediv__(self, other):
            return 'Division!'

>>> WeirdThing() / WeirdThing()
'Division!'
AbyxDev
  • 1,363
  • 16
  • 30
  • Thanks, the code you mention seems to start on line 894 in pathlib.py ----- def __truediv__(self, key): return self._make_child((key,)) - although I don't think I would ever override '/' to do anything. – JoePythonKing Nov 01 '18 at 10:33
  • 7
    is this considered 'unpythonic' ? It feels to me like predictable behaviour has been neglected here – Ben Jones Sep 30 '19 at 16:42
  • 6
    @BenJones Personally, I would like it if `Path() + Path()` or `Path() + 'path'` concatenated the path strings while `Path() / Path()` or `Path() / 'path'` `os.path.join`ed them, but the way it currently is isn't unpythonic per se IMO. – AbyxDev Oct 02 '19 at 13:22
  • What's going on here though? the class 'object' doesn't have a __truediv__ method that get's overridden. What ties this method to the '/' symbol? – Andrew Feb 11 '22 at 06:54
  • 3
    @Andrew When evaluating `a / b`, Python attempts to call `a.__truediv__(b)` under the hood. If it is not present (or returns `NotImplemented`), then it tries `b.__rtruediv__(a)`. If that fails, it raises a `TypeError`. What ties the method to the `/` operator is Python itself. Whether or not the method is implemented in a parent class has no bearing on whether it can be defined in a subclass. – AbyxDev Feb 11 '22 at 23:59
  • Answering myself, the __truediv__ dunder method is documented in the refence documentation: https://docs.python.org/3/reference/expressions.html#binary-arithmetic-operations as well as other dunder methods for addition, subtraction, multiplication and modulo. – Andrew Feb 15 '22 at 04:33
4

For whoever wants to see the source code briefly:

__truediv__ overload the / operator, and returns self, which is a Path object.

    # this is where the magic begins! (overload the '/' operator)
    def __truediv__(self, key): 
        try:
            return self._make_child((key,))
        except TypeError:
            return NotImplemented


    def _make_child(self, args):
        drv, root, parts = self._parse_args(args)
        drv, root, parts = self._flavour.join_parsed_parts(
            self._drv, self._root, self._parts, drv, root, parts)
        return self._from_parsed_parts(drv, root, parts)


    @classmethod
    def _from_parsed_parts(cls, drv, root, parts):
        self = object.__new__(cls)
        self._drv = drv
        self._root = root
        self._parts = parts
        return self  # finally return 'self', which is a Path object.
starriet
  • 2,565
  • 22
  • 23