1

I'm new in python and using bs4, I try to change attribute name for some list of tags to use this list on different place with different attributes but with same text value

I have this global variable: x = soup.find_all(attrs={"name": "some_name"})

x global variable provide me with list so I can use it in some org_tag.contents = x

In some other new tag.contents = ylist() I want to use function with list with same text values as x have but with different attributes names.

I have this code to do that:

# test.py

x = soup.find_all(attrs={"name": "some_name"})

### x = find this list:
###  <column name="some_name">
###   my text value
###  </column>
###   <column name="some_name">
###   my text value
###  </column>
###
 
def ylist():
    for i in range(len(x)):
        x[i]['name'] = "some_other_name"
    return (x)

# first original tag

org_tag = soup.new_tag("table")
org_tag.name = "table"
org_tag['name'] = "some_table"
org_tag.contents = x
soup.append(org_tag)

# new tag
newtag = soup.new_tag("table")
newtag.name = "table"
newtag['name'] = "some_other_table"
newtag.contents = ylist()
soup.append(newtag)

What happens is that my function ylist() change all global variables to new attribute name, but I want new attribute name only local at new_tag

My understanding is that in python global variables changes only if I use - global x - inside of function.

So my question why my function changes all global variables and how to get only new attribute name only local at new_tag

Edit: Here is solution as is suggested from second answer

## use of deepcopy
def ylist():
    a = copy.deepcopy(x)
    for i in range(len(a)):
        a[i]['name'] = "some_other_name"
    return (a) 

Thank you

Darko
  • 90
  • 11
  • 1
    `new_tag = soup.new_tag("table")` instead `new tag` – Jamiu S. Aug 14 '22 at 08:14
  • new_tag = soup.new_tag("table") is correct, thank you I will edit post. I made spelling mistake in my working code I use medias.name not new tag.name – Darko Aug 14 '22 at 08:25
  • Also I'm working on xml file, does not know if this relevant to question, file is imported `soup = BeautifulSoup(file, features="lxml-xml")` – Darko Aug 14 '22 at 08:37

2 Answers2

1

Because your function is no properly constructed.

def ylist(x):
    x_content = x.copy
    for i in range(len(x)):
        x_content[i]['name'] = "some_other_name":
    return x_content

Now you can fix this part of your code as well:

Change:

newtag.contents = ylist()
soup.append(newtag)

To

my_newtag = ylist(newtag.contents)
soup.append(my_newtag)
Jamiu S.
  • 5,257
  • 5
  • 12
  • 34
  • Hi thank you for answer, I try this and get in console error: ValueError: Cannot insert None into a tag. I was thinking that return statement in function should take care for None error. – Darko Aug 14 '22 at 09:35
  • I think that can be fixed by modifying the `if` statement of the function. by changing `if x_content == "some_other_name":` to `if x_content == "some_other_name" and x_content is not None:` – Jamiu S. Aug 14 '22 at 09:59
  • Not working, is kinda understandable error- None - since `"some_other_name"` don't exist yet, I try to add him this with this function – Darko Aug 14 '22 at 10:57
1

if I understand your question correctly, you could use the copy method of list object to create a new object with the same data as the initial list variable.

def ylist():
    x_copy = x.copy()
    for i in range(len(x_copy)):
        x_copy[i]['name'] = "some_other_name"
    return x_copy

also, you can check the copy module for advanced use of copy objects. you can find more about copying list objects in this link.

  • Thank you for answer. I try this and global variable also change attribute, copy doesn't affect anything – Darko Aug 14 '22 at 11:06
  • I try even more and find that deepcopy does the trick. Thank you sir for pointing me in correct direction. – Darko Aug 14 '22 at 13:28