1

I am analyzing the source code for BeautifulSoup, and within the @string.setter property, I noticed a cryptic string assignment, and I am wondering if there is something gained by this that I am unaware of?

From BeautilfulSoup's element.py Tag-class:

@property
def string(self):
    """Convenience property to get the single string within this tag.
    :Return: If this tag has a single string child, return value
    is that string. If this tag has no children, or more than one
    child, return value is None. If this tag has one child tag,
    return value is the 'string' attribute of the child tag,
    recursively.
    """
    if len(self.contents) != 1: return None
    child = self.contents[0]
    if isinstance(child, NavigableString): return child
    return child.string

@string.setter
def string(self, string):
    self.clear()
    self.append(string.__class__(string))

My question is with the last line. There is not check on type(...) so couldn't they just use: self.append(string)?

I have ran my own bit of code to see what this last line is doing, and it just seems the value of the variable is being set...

>>> x = "my-string"
>>> x.__class__
<class 'str'>
>>> x.__class__(x)
'my-string'
>>> type(x.__class__(x))
<class 'str'>
>>> 

So I wonder what the reasoning for this is? Is there something gained our is this just a preference from the developer?

sbaby171
  • 68
  • 7
  • 1
    Seems that it's for making a copy of the string. Why the copy is being made and why this method for making the copy is being used, I don't know – Iain Shelvington Sep 07 '19 at 22:51
  • 1
    I don't really know anything about this, so not answer, but you can bisect the line [back to where it was committed](https://bazaar.launchpad.net/~leonardr/beautifulsoup/bs4/revision/221/bs4/element.py) and a [related bug post](https://bugs.launchpad.net/beautifulsoup/+bug/988905). – walnut Sep 07 '19 at 23:00
  • @IainShelvington I think you are correct. It seems to simply be a way of creating a copy. – sbaby171 Sep 07 '19 at 23:15
  • related: https://stackoverflow.com/a/14209708/2823755 – wwii Sep 07 '19 at 23:31
  • another: https://stackoverflow.com/a/10633356/2823755 and its third comment. – wwii Sep 07 '19 at 23:48

1 Answers1

1

Calling the constructor of a basic type on an object of the same type in python is an idiomatic way to create a copy of it, like list(a_local_list).

The .string object in beautifulsoup appears to not just be a str object. https://stackoverflow.com/a/25328374/447599 This means that the .string object may be mutable. Making a copy of a str object in python would be pointless, as they aren't mutable.

Jules G.M.
  • 3,624
  • 1
  • 21
  • 35
  • Correct the `string` is a property of the Tag object. Do you think I should add that bit of code to the original example? I think I should because it may be more clear that `string` is actually an attribute of the Tag object. – sbaby171 Sep 07 '19 at 23:11
  • I think your example is confusing because you are testing what happens on a non-mutable object (`str`) which is useless because copying a non-mutable object is useless (the object pointed to by the original reference never changes). – Jules G.M. Sep 07 '19 at 23:20
  • what do you still not understand? – Jules G.M. Sep 07 '19 at 23:20
  • I understand the main concept - creating a copy from the input value. I guess the details lie in the fact that `def string` allows various return types... – sbaby171 Sep 07 '19 at 23:34
  • I don't know that `list(lst)` is especially idiomatic these days. `list.copy()` (in Python 3) is much clearer and is the "one obvious way to do it". – Hatshepsut Sep 07 '19 at 23:42
  • Trying to track down this copying idiom with no success - but finding interesting explanations for `x.__class__(x)`. – wwii Sep 08 '19 at 00:01