Объекты в Python
Введение | |
id() | |
dir() | |
Равенство по значению и по идентичности | |
Изменяемые и неизменяемые объекты | |
Передача аргументов | |
Всё является объектом | |
Похожие статьи |
Введение
Основной объект в Python, от которого всё наследуется это PyObject
python.org
У него есть два атрибута:
счётчик ссылок
Py_REFCNT
и тип
Py_TYPE
.
Про итерацию, итераторы и итерируемые объекты вы можете прочитать в статье
«Итерация в Python»
id()
Рассмотрим очень полезную для дальнейшего понимания объектом функцию id()
# id() print("# id():\n") a = 1961 print("a = 1961") print(f"id(a) = {id(a)}")
# id(): a = 1961 id(a) = 140042834389712
b = 1065 print("b = 1065") print(f"id(b) = {id(b)}")
b = 1065 id(b) = 140042834389648
b - это новый элемент со своим уникальным id
Если выполнить b = a, то b получит id и значение от a, то есть станет тем же объектом, просто у объекта a появится второе название.
b = a print("b = a") print(f"id(b) = {id(b)}") print(f"id(a) == id(b): {id(a) == id(b)}") print(f"a is b: {a is b}")
b = a id(b) = 140042834389712 id(a) == id(b): True a is b: True
В циклах при увеличении счётчика создаётся новый объект.
i = 0 print("i = 0") print(f"id(i) = {id(i)}") i += 2 print("i += 2") # Создаётся новый объект print(f"id(i) = {id(i)}")
i = 0 id(i) = 140042835400976 i += 2 id(i) = 140042835401008
dir()
Получить все аттрибуты объекта можно с помощью функции
dir()
Рассмотрим обычную
строку
print("l =", l) print("m =", m)
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
А теперь простой список
l = ["l", "m"] print(dir(l))
['__add__', '__class__', '__class_getitem__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Видно, что некоторые атрибуты совпадают, а некоторые нет. Например, у строк нет метода copy а у списков upper.
Равенство по значению и по идентичности
== сравнивает значения объектов.
is проверяет являются ли объекты одним и тем же объектом в памяти. То есть сравнивает ссылки на область в памяти.
# Value vs. Identity Equality print("\n# Value vs. Identity Equality:\n") p = [5, 6, 7] print(f"p = {p}") q = [5, 6, 7] print(f"q = {q}") print(f"p == q: {p == q}") print(f"p is q: {p is q}") print(f"p is p: {p is p}") # Value-equality and identity equality are fundamentally # different concepts. # Comparison by value can be controlled programatically # Identity comparison is unalterable defined # by the language # Value vs. Identity Equality:
p = [5, 6, 7] q = [5, 6, 7] p == q: True p is q: False p is p: True
Изменяемые и неизменяемые объекты
Объекты могут быть изменяемыми (mutable) и неизменяемыми (immutable)
Очень хорошей иллюстрацией разницы в их применении являются
аргументы по умолчанию
Множество (set) , Словарь (dict) и Список (list) это изменяемые объекты.
Строка - это неизменяемый объект
a = "aaa" b = a b = "bbb" print("a =", a) print("b =", b)
a = aaa b = bbb
Список - это изменяемый объект, но в этом примере поведение списка и строки пока что одинаковое потому что и b = "bbb" и m = ["m", "m"] создают новые объекты.
l = ["l", "l"] m = l m = ["m", "m"] print("l =", l) print("m =", m)
l = ['l', 'l'] m = ['m', 'm']
А в следующем примере уже видна разница. Изначальная строка a останется без изменений, а вот список l изменится из-за изменения m
a = "aaa" b = a b += "b" print("a =", a) print("b =", b) l = ["l", "l"] m = l m.append("m") print("l =", l) print("m =", m)
a = aaa b = aaab l = ['l', 'l', 'm'] m = ['l', 'l', 'm']
С помощью функции id() можно убедиться в том, что строка b стала новым объектом после b += "b" а список m и список l остались одним и тем же объектом.
В следующем примере мы изменим список не с помощью append(), а напрямую, но результат будет таким же.
# Mutable Objects print("\n# Mutable Objects:\n") my_list = [0, 1, 2] print(f"my_list = {my_list}") s = my_list print("s = my_list") print(f"s = {s}") # Изменим элемент в s # и увидим, что и изначальный my_list изменится s[1] = 34 print("s[1] = 34") print(f"s = {s}") # Изменился не только s но и my_list print(f"my_list = {my_list}") print(f"s is my_list: {s is my_list}") # Python doesn't have variables in the sense of boxes # holding a value # Python has named references to objects
python objects_example.py
# Mutable Objects: my_list = [0, 1, 2] s = my_list s = [0, 1, 2] s[1] = 34 s = [0, 34, 2] my_list = [0, 34, 2] s is my_list: True
Передача аргументов
m = [0, 1, 2] print(f"m = {m}") def modify(k): k.append(3) print("k =", k) print("\nmodify(m)\n") modify(m) print(f"m = {m}") print("\nNo copy of m is made\n") print("\nmodify(m)\n") modify(m) print(f"m = {m}")
m = [0, 1, 2] modify(m) k = [0, 1, 2, 3] m = [0, 1, 2, 3] No copy of m is made modify(m) k = [0, 1, 2, 3, 3] m = [0, 1, 2, 3, 3]
Функция modify() работает с тем же объектом, поэтому его значения изменяются. Обойти эту особенность можно с помощью функции copy()
Рассмотрим функцию replace() в которой создается новый объект
f = [4, 5, 6] print("f = ", f) def replace(g): g = [7, 8, 9] print("g =", g) print("\nreplace(f)\n") replace(f) print("f = ", f)
python replace.py
f = [4, 5, 6] replace(f) g = [7, 8, 9] f = [4, 5, 6]
Благодаря тому, что ссылка на старый объект не используется (вместо это переменная g указывает на новый объект) значение переменной f не изменилось.
Можно переписать функцию replace() так, чтобы она заменяла исходный объект.
Назовём новую функцию replace_contents()
def replace_contents(g): g[0] = 20 g[1] = 21 g[2] = 22 print("g = ", g) f = [10, 11, 12] print("f = ", f) print("\nreplace_contents(f)\n") replace_contents(f) print("f = ", f) # Function arguments are transferred using # pass-by-object-reference # References to objects are copied, # not the objects themselves.
python replace_contents.py
f = [10, 11, 12] replace_contents(f) g = [20, 21, 22] f = [20, 21, 22]
Убедиться в том, что если не произведено специальных действий, функция вернёт тот же самый объект довольно просто
def f(d): return d c = [0, 1, 2] print("c = ", c) e = f(c) print("e = f(c)") print(f"c is e: {c is e}")
python return_semantics.py
c = [0, 1, 2] e = f(c) c is e: True
Всё является объектом
Рассмотрим скрипт words.py со следюущим содержанием.
"""Retrieve and print words from a URL. Usage: python3 words.py <URL> """ import sys from urllib.request import urlopen def fetch_words(url): """Fetch a list of words from a URL. Args: url: The URL of a UTF-8 text document. Returns: A list of strings containing the words from the document """ # PEP 257 # story = urlopen("http://sixty-north.com/c/t.txt") story = urlopen(url) story_words = [] for line in story: line_words = line.decode("utf8").split() for word in line_words: story_words.append(word) story.close() return story_words def print_items(story_words): """Print items one per line. Args: An iterable series of printable items. """ for word in story_words: print(word) def main(url): words = fetch_words(url) print_items(words) if __name__ == "__main__": main(sys.argv[1])
➭ python
Python 3.9.5 (default, Jun 15 2021, 15:30:04) [GCC 9.3.0] on linux Type "help", "copyright", "credits" or "license" for more information.
>>> import words
>>> type(words)
<class 'module'>
Получить все аттрибуты объекта можно с помощью функции dir()
>>> dir(words)
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'fetch_words', 'main', 'print_items', 'sys', 'urlopen']
>>> type(words.fetch_words)
<class 'function'>
>>> dir(words.fetch_words)
['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']
>>> words.fetch_words.__name__
'fetch_words'
>>> words.fetch_words.__doc__
'Fetch a list of words from a URL.\n \n Args:\n url: The URL of a UTF-8 text document.\n\n Returns:\n A list of strings containing the words from\n the document\n '
Основы Python | |
Python | |
Установка Python | |
ООП в Python | |
Функции | |
docstring | |
#!: Shebang | |
Объекты | |
os | |
pathlib | |
Сложности при работе с Python |