I understand that all variables in Python are links that refer to one object, and not to a section of memory as in C / C ++.

Is it possible to create a link to one memory section so that the value changes when working with any of the links?

For example (conditionally)

a = 10 b = &a print(a, b) # 10 10 b = 20 print(a, b) # 20 20 a = 15 print(a, b) # 15 15 

I need this to shorten the entry for accessing the internal values ​​of nested dictionaries:

 username = "test" userdata = [10, 2, 30, 15] user = {username:userdata} serveraddr = "127.0.0.1" server = {serveraddr:user} # хочСтся ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΈΠΌΠ΅Π½Π°-сокращСния для этих элСмСнтов joincount = server[serveraddr][username][0] leftcount = server[serveraddr][username][1] gamescount = server[serveraddr][username][2] wincount = server[serveraddr][username][3] # ΠΏΡ€ΠΎΠ±ΡƒΠ΅ΠΌ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΈΡ… значСния joincount = 20 leftcount = 9 gamescount = 10 wincount = 3 # провСряСм, Ρ‡Ρ‚ΠΎ значСния Π² словарС ΠΎΡΡ‚Π°Π»ΠΈΡΡŒ ΠΏΡ€Π΅ΠΆΠ½ΠΈΠΌΠΈ print(server[serveraddr][username][0], server[serveraddr][username][1], server[serveraddr][username][2], server[serveraddr][username][3]) # (10, 2, 30, 15) # хотя значСния ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Ρ… измСнились print joincount, leftcount, gamescount, wincount # (20, 9, 10, 3) 

In the code, server[serveraddr][username][n] constructions are very often used, most of them are in places where all indices are calculated. Therefore, I would like to use server[serveraddr][username][0] instead of server[serveraddr][username][0] - this would improve the readability of the code.

Is it possible to realize this?

  • one
    "Not to save the same memory?" - For safety, though. In theory, a python cannot fall from segmentation errors or become vulnerable to buffer overflows. And yes, references by definition work in the same way as in C ++ (do not confuse references with pointers). - andreymal

2 answers 2

Python has mutable and immutable types. Modifiable differ in that their contents can be changed without changing the link to them. Immutable objects must be recreated to reflect state changes. In this case, all the old links do not see this update, because they point to the old object.

I will explain in practice. Lists, dictionaries, sets are mutable objects:

 l1 = [1, 2, 3] l2 = l1 print(l1, l2, id(l1), id(l2)) # [1, 2, 3] [1, 2, 3] 139917408901064 139917408901064 l1[1] = 10 print(l1, l2, id(l1), id(l2)) # [1, 10, 3] [1, 10, 3] 139917408901064 139917408901064 

Numbers, strings, tuples are immutable objects:

 v1 = 1024 v2 = v1 print(v1, v2, id(v1), id(v2)) # 1024 1024 ...7040 ...7040 v1 = 2048 print(v1, v2, id(v1), id(v2)) # 2048 1024 ...5312 ...7040 t1 = (1, 2, 3) t2 = t1 print(t1, t2, id(t1), id(t2)) # (1, 2, 3) (1, 2, 3) ...6232 ...6232 # t1[1] = 10 # Π½Π΅ сработаСт, Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ ΠΊΠΎΡ€Ρ‚Π΅ΠΆΠΈ нСизмСняСмыС t1 = (1, 10, 3) print(t1, t2, id(t1), id(t2)) # (1, 10, 3) (1, 2, 3) ...7240 ...6232 

In your code, you use mutable data structures such as dictionaries and lists ( user , userdata , server ) and immutable strings and numbers.

Thus, without changing anything in the information storage structure, you can only minimize access to the list of numbers.

 my_userdata = server[serveraddr][username] # ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ my_userdata Π²Π»Π΅Ρ‡Ρ‘Ρ‚ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ server[serveraddr][username], # Ρ‚Π°ΠΊ ΠΊΠ°ΠΊ это ΠΎΠ΄ΠΈΠ½ ΠΈ Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ 

Since the numbers are immutable, saving them to a variable and further changing this variable does not affect the original number (that is, the joincount variable joincount never change when changing server[serveraddr][username][0] and vice versa). changing the numbers in this list will not affect the variables storing these values


But if you try to improve the code a bit, you should create a class UserData , which will store the necessary values ​​in itself and allow them to be changed. The minimum example would be as follows:

 class UserData: def __init__(self, joincount, leftcount, gamescount, wincount): self.joincount = joincount self.leftcount = leftcount self.gamescount = gamescount self.wincount = wincount username = "test" userdata = UserData(10, 2, 30, 15) user = {username:userdata} 

After that, if we get our user from somewhere, we can change the desired values:

 user_data = server[serveraddr][username] user_data.joincount = 20 user_data.leftcount = 9 user_data.gamescount = 10 user_data.wincount = 3 print (server[serveraddr][username].joincount, server[serveraddr][username].leftcount, server[serveraddr][username].gamescount, server[serveraddr][username].wincount) print (user_data.joincount, user_data.leftcount, user_data.gamescount, user_data.wincount) 

Using a similar structure will increase the readability of your code, compared to using list indexes.


If you have access to change the contents of the dictionary, I would recommend that you use the namedtuple from the standard collections module, which allows you to create an object similar in behavior to a tuple, but providing access to the fields like the one above (but only for reading) instead of the samopisny class.

 UserData = collections.namedtuple('UserData', ['joincount', 'leftcount', 'gamescount', 'wincount']) 

In this case, you will have to replace the old UserData object with a new one:

 old_userdata = server[serveraddr][username] new_userdata = UserData(joincount=20, leftcount=9, gamescount=10, wincount=3) server[serveraddr][username] = new_userdata print(new_userdata, old_userdata, server[serveraddr][username]) 

Getting the field to read will be performed in the same way as in the example above:

 print(old_userdata.joincount, old_userdata.gamescount) 
  • Thank! Deployed and easy to understand. - strol
  • one
    Therefore, it is very important to describe your question in detail. Good luck with learning Python! - Timofei Bondarev

You need to read and understand mutable and immutable objects in python. Yes, you can link to the nested list, and fill it through it. For example:

 lst = [[]] sublst = lst[0] sublst.append(1) print(lst) sublst.append(2) print(lst) print(id(lst[0])) print(id(sublst)) sublst[0] = -1 print(lst) 

Conclusion:

 [[1]] [[1, 2]] 139794716732424 139794716732424 [[-1, 2]] 

In this case, the sublst is a link to the nested list in lst , the call to sublst.append equivalent to lst[0].append . Similarly, you can work for example with a dictionary.

  • that is, if I want to change the value of an element, then I need to delete it first? - strol
  • No, you can write like this: sublst [0] = -1. And the value changes in the lst list. - Avernial