Объекты в Python
| Введение | |
| Равенство по значению и по идентичности | |
| Передача аргументов | |
| Всё является объектом | |
| Размер объекта | |
| Встроенные типы данных | |
| Похожие статьи |
Введение
Основной объект в Python, от которого всё наследуется это PyObject
python.org
У него есть два атрибута:
счётчик ссылок
Py_REFCNT
и тип
Py_TYPE
.
Про типы данных в Python можно прочитать много интересного в
официальной документации
Про итерацию, итераторы и итерируемые объекты вы можете прочитать в статье
«Итерация в Python»
, а про типы данных - в статье
«Python collections»
Советую изучть встроенные функции
dir()
и
id()
,
их применение вносит ясность в некоторые особенности питоноских объектов.
| Изменяемые и неизменяемые объекты |
| Итераторы и итерируемые объекты |
| Python collections |
| dir() |
| id() |
Равенство по значению и по идентичности
== сравнивает значения объектов.
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
Не советую злоупотреблять сложными логическими выражениями, поэтому следующий пример, скорее для прохождения специфических собеседований, чем для реального кодинга
Разберём что вернут следующие выражения, а главное, почему они это вернут.
0 == False # True 1 == True # True 2 == True # False 2 == False # False
В Python
0 интерпретируется как False
1 интерпретируется как True
2 не интерпретируется ни как False ни как True
это довольно логично и легко запомнить. Удлинним выражение
Не советую писать что-то похожее, если не хотите запутать тех кто будет читать ваш код.
1 == True is True
True
2 == True is True
False
Результат угадать несложно. Сложнее объяснить. Какие приходят на ум варианты:
# Изначальные выражение 0 == True is True # False 1 == True is True # True 2 == True is True # False # 1 (0 == True) is True # False (1 == True) is True # True (2 == True) is True # False # 2 0 == (True is True) # False 1 == (True is True) # True 2 == (True is True) # False
Оба варианта дают один и тот же результат. Чтобы разобраться есть ли среди них правильный заменим True is True на True is False
# Изначальные выражение 0 == True is False # False 1 == True is False # False 2 == True is False # False # 1 (0 == True) is False # True (1 == True) is False # False (2 == True) is False # True # 2 0 == (True is False) # True 1 == (True is False) # False 2 == (True is False) # False
Оба варианта установки скобок не равносильны изначальному выражению. А всё потому, что Python интерпретирует такое выражение как (0 == True) and (True == False)
# Изначальные выражение 0 == True is True # False 1 == True is True # True 2 == True is True # False 0 == True is False # False 1 == True is False # False 2 == True is False # False (0 == True) and (True is True) # False (1 == True) and (True is True) # True (2 == True) and (True is True) # False (0 == True) and (True is False) # False (1 == True) and (True is False) # False (2 == True) and (True is False) # False
Здесь совпадают значения возвращаемые для всех чисел 0, 1 и 2. Нужно ли знать о такой особенности Python? Возможно. Нужно ли избегать написания кода с такими особенности? Нужно.
Ещё одна причина быть осторожнее с неправильным использованием is кроется в разном поведении Python при запуске скриптов и при использовании интерактивного режима
a = 2 print(a is 2) a = 1234567 print(a is 1234567)
True True C:\demo.py:2: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? print(a is 2) C:\demo.py:4: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? print(a is 1234567)
Теперь в интерактивном режиме
Python 3.12.2 (tags/v3.12.2:6abddd9, Feb 6 2024, 21:26:36) [MSC v.1937 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 2
>>> a is 2
Передача аргументов
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 '
Размер объекта в памяти
Стандартным средством определения размера объекта является
getsizeof() из sys
Этот метод подходит не всем объектам, подробнее
здесь
Автор статьи: Андрей Олегович
| Размер объекта | |
| weakref | |
| Основы Python | |
| Встроенные типы данных | |
| Изменяемые и неизменяемые | |
| Итерация | |
| os | |
| dir() | |
| id() |