Как получить список объектов класса?
Из примера не очень понятно, что всё-таки вам нужно — список объектов, инстанцированных от этого класса? Или список объектов, которые являются аттрибутами класса?
10 ноя 2021 в 7:06
Аттрибутами класса
10 ноя 2021 в 7:36
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Все атрибуты класса можно увидеть с помощью специального метода __dict__ . Правда, туда кроме явно созданных Вами атрибутов попадут и системные атрибуты, но их легко отфильтровать, т.к. их название начинается и заканчивается двойным подчёркиванием:
print( )
UPD на комментарий:
Имея название атрибута, вы всегда можете, как получить его значение
value = getattr(Example, k) print(value)
так и заменить его на новое значение:
setattr(Example, k, new_value_obj)
Что такое метод класса в Python и зачем нужен
Альтернативный конструктор (несколько конструкторов) класса в Python
Сразу начнем с примера простого класса, который содержит обычный метод и метод класса:
class MyClass: def method(self): return 'instance method called', self @classmethod def classmethod(cls): return 'class method called', cls
Как работают методы класса в Python?
В Python, методы класса отмечаются декоратором @classmethod , следовательно в приведенном выше примере, метод класса будет определен в функции classmethod() .
Как можно заметить, метод класса вместо того, чтобы принимать аргумент self , принимает аргумент cls . При вызове метода этот аргумент указывает на сам класс, а не на экземпляр класса.
Поскольку метод класса имеет доступ только к аргументу cls , он не может изменять состояние экземпляра объекта. Для этого потребуется доступ к аргументу self . НО все же методы класса могут изменять состояние класса, которое применяется ко всем экземплярам класса.
MyClass() настроен таким образом, что реализация каждого метода возвращает кортеж для отслеживания, что происходит, и к каким частям класса или объекта метод может получить доступ.
Вот что происходит, когда мы вызываем метод экземпляра:
>>> obj = MyClass() >>> obj.method() # ('instance method called', ) # Можно передать объект `obj` экземпляра вручную, # для получения того же результата >>> MyClass.method(obj) # ('instance method called', )
Этот кусок кода подтвердил, что метод экземпляра класса имеет доступ к экземпляру объекта, напечатанному как через аргумент self .
Кстати, методы экземпляра также могут получить доступ к самому классу через атрибут self.__class__ . Это делает методы экземпляра мощными с точки зрения ограничений доступа — они могут изменять состояние как экземпляра объекта, так и самого класса.
Попробуем вызвать метод класса:
>>> obj.classmethod() # ('class method called', )
Вызов метода класса obj.classmethod() показал, что он не имеет доступа к объекту , а только к объекту , представляющему сам класс (в Python все является объектом, даже сами классы).
Обратите внимание, как Python автоматически передает класс в качестве первого аргумента функции, когда вызывается MyClass.classmethod() . Вызов метода в Python через точечную нотацию запускает это поведение. Параметр self в методах экземпляра работает точно так же.
Теперь посмотрим, что происходит, когда попытаться вызвать эти методы в самом классе — без предварительного создания экземпляра объекта:
>>> MyClass.classmethod() # ('class method called', ) >>> MyClass.method() # Traceback (most recent call last): # File "", line 1, in # TypeError: method() missing 1 required positional argument: 'self'
Из примера видно, что можно нормально вызвать метод класса MyClass.classmethod() , но попытка вызвать метод экземпляра MyClass.method() завершилась ошибкой TypeError . Этого следовало ожидать, ведь экземпляр объекта не создан, что означает, что Python не может заполнить аргумент self и следовательно, вызов не выполняется.
Для чего нужны методы класса в Python?
Следующие примеры кода должны сделать понимание метода класса более ясным. Далее рассмотрим пример класса, имеющего дело с информацией о дате (это будет шаблон):
class Date: def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year def string_to_db(self): return f'self.year>-self.month>-self.day>'
Этот класс, очевидно, можно использовать для хранения информации об определенных датах, без информации о часовом поясе (предположим, что все даты представлены в формате UTC).
Здесь есть конструктор __init__ , типичный инициализатор экземпляров классов Python, который получает аргументы как типичный метод экземпляра, имея первый необязательный аргумент self , который содержит ссылку на вновь созданный экземпляр.
Например есть несколько задач, которые можно решить при помощи будущих методов этого класса, не только определенного для примера метода, банального перевода числовых значений в формат строки с датой для баз данных.
Предположим, что мы хотим создать много экземпляров класса Date() с информацией о дате, поступающей из внешнего источника, в виде строки с форматом dd.mm.yyyy . Предположим, нужно сделать это в разных местах исходного кода проекта.
Итак, что для этого необходимо сделать:
- Выполнить синтаксический анализ строки, получить день, месяц и год как три целочисленные переменные или кортеж из трех элементов, включающий эти переменные.
- Создать экземпляр Date , передав эти значения в конструктор класса при его создании.
Это будет выглядеть так:
>>> string_date = '10.10.2020' >>> day, month, year = map(int, string_date.split('.')) >>> date = Date(day, month, year) >>> date.string_to_db() # '2020-10-10'
Для выполнения этой задачи, например C++ или Java может реализовать такую возможность с перегрузкой метода __init__ , но в Python перегрузка методов отсутствует. Вместо нее необходимо использовать метод класса (декоратор @classmethod).
Создадим еще один «конструктор».
class Date(object): def __init__(self, day=0, month=0, year=0): self.day = day self.month = month self.year = year @classmethod def from_string(cls, date_as_string): day, month, year = map(int, date_as_string.split('.')) date1 = cls(day, month, year) return date1 def string_to_db(self): return f'self.year>-self.month>-self.day>'
Более подробно о перегрузке смотрите в материале «Перегрузка методов в Python».
Обратите внимание, как используется аргумент cls в методе класса from_string() вместо прямого вызова конструктора класса Date() .
Теперь создать новый экземпляр Date , так же, можно следующим образом:
>>> date1 = Date.from_string('30.12.2020') >>> date1.string_to_db() # '2020-12-30' >>> date2 = Date.from_string('01.01.2021') >>> date2.string_to_db() # '2021-1-1'
Рассмотрим приведенную выше реализацию чтобы понять, какие преимущества здесь есть:
- Реализован синтаксический анализ строки даты в одном месте, и теперь его можно использовать повторно.
- Инкапсуляция здесь отлично работает. Если вы думаете, что можете реализовать синтаксический анализ строк как единственную функцию в другом месте, это решение намного лучше соответствует парадигме ООП.
- cls — это объект, который содержит сам класс, а не его экземпляр. Это довольно круто, потому что, если мы наследуем класс Date , для всех дочерних элементов также будет определен метод класса from_string() .
Используя методы класса, можно добавить столько альтернативных конструкторов, сколько необходимо. Такое поведение может сделать интерфейс создаваемых классов самодокументированным (до определенной степени конечно) и упростить их использование.
- ОБЗОРНАЯ СТРАНИЦА РАЗДЕЛА
- Пространство имен и область видимости в классах
- Определение классов
- Объект класса и конструктор класса
- Создание экземпляра класса
- Метод экземпляра класса
- Что такое метод класса и зачем нужен
- Что такое статический метод в классах Python и зачем нужен
- Атрибуты класса и переменные экземпляра класса
- Кэширование методов экземпляра декоратором lru_cache
- Закрытые/приватные методы и переменные класса Python
- Наследование классов
- Множественное наследование классов
- Абстрактные классы
- Перегрузка методов в классе Python
- Перегрузка операторов в классах Python
- Что такое миксины и как их использовать
- Класс Python как структура данных, подобная языку C
- Создание пользовательских типов данных
- Специальные (магические) методы класса Python
- Базовая настройка классов Python магическими методами
- Настройка доступа к атрибутам класса Python
- Дескриптор класса для чайников
- Протокол дескриптора класса
- Практический пример дескриптора
- Использование метода .__new__() в классах Python
- Специальный атрибут __slots__ класса Python
- Специальный метод __init_subclass__ класса Python
- Определение метаклассов metaclass
- Эмуляция контейнерных типов в классах Python
- Другие специальные методы класса
- Как Python ищет специальные методы в классах
- Шаблон проектирования Фабрика и его реализация
Объектно-ориентированное программирование
Python имеет множество встроенных типов, например, int, str и так далее, которые мы можем использовать в программе. Но также Python позволяет определять собственные типы с помощью классов . Класс представляет некоторую сущность. Конкретным воплощением класса является объект.
Можно еще провести следующую аналогию. У нас у всех есть некоторое представление о человеке, у которого есть имя, возраст, какие-то другие характеристики. Человек может выполнять некоторые действия — ходить, бегать, думать и т.д. То есть это представление, которое включает набор характеристик и действий, можно назвать классом. Конкретное воплощение этого шаблона может отличаться, например, одни люди имеют одно имя, другие — другое имя. И реально существующий человек будет представлять объект этого класса.
В языке Python класс определяется с помощью ключевого слова class :
class название_класса: атрибуты_класса методы_класса
Внутри класса определяются его атрибуты, которые хранят различные характеристики класса, и методы — функции класса.
Создадим простейший класс:
class Person: pass
В данном случае определен класс Person, который условно представляет человека. В данном случае в классе не определяется никаких методов или атрибутов. Однако поскольку в нем должно быть что-то определено, то в качестве заменителя функционала класса применяется оператор pass . Этот оператор применяется, когда синтаксически необходимо определить некоторый код, однако исходя из задачи код нам не нужен, и вместо конкретного кода вставляем оператор pass.
После создания класса можно определить объекты этого класса. Например:
class Person: pass tom = Person() # определение объекта tom bob = Person() # определение объекта bob
После определения класса Person создаются два объекта класса Person — tom и bob. Для создания объекта применяется специальная функция — конструктор , которая называется по имени класса и которая возвращает объект класса. То есть в данном случае вызов Person() представляет вызов конструктора. Каждый класс по умолчанию имеет конструктор без параметров:
tom = Person() # Person() - вызов конструктора, который возвращает объект класса Person
Конструкторы
Итак, для создания объекта класса используется конструктор. Так, выше когда мы создавали объекты класса Person, мы использовали конструктор по умолчанию, который не принимает параметров и который неявно имеют все классы. Однако мы можем явным образом определить в классах конструктор с помощью специального метода, который называется __init__() (по два прочерка с каждой стороны). К примеру, изменим класс Person, добавив в него конструктор:
class Person: # конструктор def __init__(self): print("Создание объекта Person") tom = Person() # Создание объекта Person
Итак, здесь в коде класса Person определен конструктор — функция __init__ . Конструктор должен принимать как минимум один параметр ссылку на текущий объект — self . Обычно конструкторы применяются для определения действий, которые должны производиться при создании объекта.
Теперь при создании объекта:
tom = Person()
выполняется вызов конструктора __init__() из класса Person, который выведет на консоль строку «Создание объекта Person».
Стоит отметить, что конструктор фактически представляет обычную функцию, только для вызовы конструктора используется не __init__ , а название класса. Кроме того, при вызове конструктора параметру self явным образом не передается никакого значения. При выполнении программы Python динамически будет определять self .
Атрибуты объекта
Атрибуты хранят состояние объекта. Для определения и установки атрибутов внутри класса можно применять слово self . Например, определим следующий класс Person:
class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) # обращение к атрибутам # получение значений print(tom.name) # Tom print(tom.age) # 22 # изменение значения tom.age = 37 print(tom.age) # 37
Теперь конструктор класса Person принимает еще два параметра — name и age. Через эти параметры в конструктор будут передаваться имя и возраст создаваемого человека.
Внутри конструктора устанавливаются два атрибута — name и age (условно имя и возраст человека):
def __init__(self, name, age): self.name = name self.age = age
Атрибуту self.name присваивается значение переменной name. Атрибут age получает значение параметра age. Название атрибутов не обязательно должно соответствовать названиям параметров.
Если мы определили в классе конструктор __init__ с параметрами (кроме self), то при вызове конструктора этим параметрам надо передать значения:
tom = Person("Tom", 22)
То есть в данном случае параметру name передается строка «Tom», а параметру age — число 22.
Далее по имени объекта мы можем обращаться к атрибутам объекта — получать и изменять их значения:
print(tom.name) # получение значения атрибута name tom.age = 37 # изменение значения атрибута age
Подобным образом мы можем создавать разные объекты класса Person с разным значением для атрибутов:
class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) bob = Person("Bob", 43) print(tom.name) # Tom print(bob.name) # Bob
Здесь создаются два объекта класса Person: tom и bob. Они соответствуют определению класса Person, имеют одинаковый набор атрибутов, однако их состояние будет отличаться. И в каждом случае Python будет динамически определять объект self. Так, в следующем случае
tom = Person("Tom", 22)
Это будет объект tom
bob = Person("Bob", 43)
Это будет объект bob
В принципе нам необязательно определять атрибуты внутри класса — Python позволяет сделать это динамически вне кода:
class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека tom = Person("Tom", 22) tom.company = "Microsoft" print(tom.company) # Microsoft
Здесь динамически устанавливается атрибут company, который хранит место работы человека. И после установки мы также можем получить его значение. В то же время подобное определение чревато ошибками. Например, если мы попытаемся обратиться к атрибуту до его определения, то программа сгенерирует ошибку:
tom = Person("Tom", 22) print(tom.company) # ! Ошибка - AttributeError: Person object has no attribute company
Методы классов
Методы класса фактически представляют функции, которые определенны внутри класса и которые определяют его поведение. Например, определим класс Person с одним методом:
class Person: # определение класса Person def say_hello(self): print("Hello") tom = Person() tom.say_hello() # Hello
Здесь определен метод say_hello() , который условно выполняет приветствие — выводит строку на консоль. При определении методов любого класса, как и конструктора, первый параметр метода представляет ссылку на текущий объект, который согласно условностям называется self . Через эту ссылку внутри класса мы можем обратиться к функциональности текущего объекта. Но при самом вызове метода этот параметр не учитывается.
Используя имя объекта, мы можем обратиться к его методам. Для обращения к методам применяется нотация точки — после имени объекта ставится точка и после нее идет вызов метода:
объект.метод([параметры метода])
Например, обращение к методу say_hello() для вывода приветствия на консоль:
tom.say_hello() # Hello
В итоге данная программа выведет на консоль строку «Hello».
Если метод должен принимать другие параметры, то они определяются после параметра self , и при вызове подобного метода для них необходимо передать значения:
class Person: # определение класса Person def say(self, message): # метод print(message) tom = Person() tom.say("Hello METANIT.COM") # Hello METANIT.COM
Здесь определен метод say() . Он принимает два параметра: self и message. И для второго параметра — message при вызове метода необходимо передать значение.
Для обращения к атрибутам и методам объекта внутри класса в его методах также применяется слово self:
self.атрибут # обращение к атрибуту self.метод # обращение к методу
Например, следующий класс Person:
class Person: def __init__(self, name, age): self.name = name # имя человека self.age = age # возраст человека def display_info(self): print(f"Name: Age: ") tom = Person("Tom", 22) tom.display_info() # Name: Tom Age: 22 bob = Person("Bob", 43) bob.display_info() # Name: Bob Age: 43
Здесь определяется метод display_info(), который выводит информацию на консоль. И для обращения в методе к атрибутам объекта применяется слово self: self.name и self.age
В итоге мы получим следующий консольный вывод:
Name: Tom Age: 22 Name: Bob Age: 43
Деструкторы
Кроме конструкторов классы в Python также могут определять специальные методы — деструкторы , которые вызываются при удалении объекта. Деструктор представляет собой метод __del__(self) , в который, как и в конструктор, передается ссылка на текущий объект. В деструкторе определяются действия, которые надо выполнить при удалении объекта, например, освобождение или удаление каких-то ресурсов, которые использовал объект.
Деструктор вызывается автоматически интерпретатором, нам не нужно его явным образом вызывать. Простейший пример:
class Person: def __init__(self, name): self.name = name print("Создан человек с именем", self.name) def __del__(self): print("Удален человек с именем", self.name) tom = Person("Tom")
Здесь в деструкторе просто выведится уведомление об удалении объекта Person. Программа создает один объект Person и хранит ссылку на него в переменной tom. Создание объекта вызовет выполнение конструктора. При завершении программы автоматически будет выполняться деструктор объекта tom. В итоге консольный вывод программы будет следующим:
Создан человек с именем Tom Удален человек с именем Tom
class Person: def __init__(self, name): self.name = name print("Создан человек с именем", self.name) def __del__(self): print("Удален человек с именем", self.name) def create_person(): tom = Person("Tom") create_person() print("Конец программы")
Здесь объект Person создается и используется внутри функции create_person, поэтому жизнь создаваемого объекта Person ограничена областью этой функции. Соответственно, когда функция завершит свое выполнение, у объекта Person будет вызываться деструктор. В итоге мы получим следующий консольный вывод:
Создан человек с именем Tom Удален человек с именем Tom Конец программы
Ответы на вопросы с PyObject
2. Как получить список всех публичных атрибутов объекта
В Python для обозначения protected атрибутов используют «_», для private — «__» перед названием переменной. Следовательно, для получения списка только публичных атрибутов, список все атрибутов нужно отфильтровать. Сделать это можно или с помощью списковых выражений (list comprehension):
print [arg for arg in dir(Foo) if not arg.startswith('_')]
или воспользоваться функцией filter:
print filter(lambda x: not x.startswith('_'), dir(Foo))
Как по мне, то первый вариант является более предпочтительным по причине большей читабельности.
3. Как получить список методов объекта
Поскольку функции и методы в Python являются объектами первого рода (вроде правильно написал?), то для проверки будем использовать функцию getattr, которая возвращает сам аттрибут объекта и функцию callable, которая и осуществляет проверку.
print [arg for arg in dir(Foo) if callable(getattr(Foo, arg))] # или print filter(lambda arg: callable(getattr(Foo, arg)), dir(Foo))
4. В какой «магической» переменной хранится содержимое help?
В атрибуте __doc__. В данную переменную заносится комментарий сразу после
объявления класса/метода/функции (см. тестовый класс).
print Foo.__doc__
Так же можно воспользоваться функцией help в интерактивном режиме:
>>> help(int)
5. Есть два кортежа, получить третий как конкатенацию первых двух
print (2, 5) + (4, 6)
6. Есть два кортежа, получить третий как объединение уникальных элементов первых двух кортежей
В данном задании я видел 2 подхода:
1. писать циклы для проверки вхождения элемента в кортежи
2. воспользоваться встроенным типом set (по сути — хеш), над которым можно применять логические операции.
Решение с использованием второго подхода (используется XOR):
print tuple(set((2, 3, 4)) ^ set((4, 5)))
7. Почему если в цикле меняется список, то используется for x in lst[:], что означает [:]?
[:] — обозначение среза в питоне. Про них можно почитать, например, тут. В кратце: [:] создает копию lst и изменения в первом никак не влияют на итерацию по исходным значениям.
8. Есть два списка одинаковой длины, в одном ключи, в другом значения. Составить словарь.
Будем использовать функцию zip, которая делает кортежи из пары значений и dict, которая создает словарь из переданных аргументов.
a = ('John', 'Peter') b = (1, 2) print dict(zip(a, b))
9. Есть два списка разной длины, в одном ключи, в другом значения. Составить словарь. Для ключей, для которых нет значений использовать None в качестве значения. Значения, для которых нет ключей игнорировать.
a = ('John', 'Peter', 'Daniel') b = (1, 2) print dict((len(a) > len(b)) and map(None, a, b) or zip(a, b)) # или вариант с if/else, введенный в Python 2.5 print dict(map(None, a, b) if (len(a) > len(b)) else zip(a, b))
В данном случае будем использовать функции zip, map. Особенностью zip является то, что возвращаемый результат ограничен самым коротким итерируемым. То есть это прекрасно подходит нам для случая, когда значений больше чем ключей. Во второй ветке python у map есть одна документированная особенность, а именно — если какое-либо из итерируемых значений короче других, оно дополняется с помощью None. Если вместо функции передано None, выполняется объединение и на выходе мы получаем те же кортежи.
Как вариант, можно рассмотреть использование функции itertools.izip_longest, которая была добавлена в 2.6.
10.Есть словарь. Инвертировать его. Т.е. пары ключ: значение поменять местами — значение: ключ.
a = print dict((val, key) for (key, val) in a.iteritems())
Как вариант — опять использовать функцию zip.
a = print dict(zip(a.itervalues(), a.iterkeys()))
P.S. прошу гуру подсказать, что правильней использовать в данном случае — zip или itertools.izip. Тоже самое относится и к values/itervalues.
11. Есть строка в юникоде, получить 8-битную строку в кодировке utf-8 и cp1251
Писал прямо во время написания статьи, но если правильно понял задание, то:
greeting = u'Привет' print greeting.encode('utf-8') print greeting.encode('cp1251')
12. Есть строка в кодировке cp1251, получить юникодную строку
Аналогично:
greeting = 'Привет' print greeting.decode('cp1251')
Функции
1. Написать функцию, которой можно передавать аргументы либо списком/кортежем, либо по одному. Функция производит суммирование всех аргументов.
Решение вижу следующим: итерация по переданному списку. В случае если элемент списка — имеет атрибут __len__, а значит является итерируемым, разворачиваем его и передаем в нашу функцию.
def sum(*args): """ Returns sum of the args. >>> sum(1) 1 >>> sum(2, 2) 4 >>> sum(1, 2, (3, 4)) 10 >>> sum(1, ()) 1 >>> sum(-1, 1.0) 0.0 """ result = 0 for arg in args: if hasattr(arg, '__len__'): result += sum(*arg) else: result += arg return result
2. Написать функцию-фабрику, которая будет возвращать функцию сложения с аргументом.
Так как функции являются объектами первого рода (если лажать, так по-крупному), то одними из вариантов их использования являются возврат их из других функций или методов и передача в качестве в аргументов. Суть сводится к тому, что мы должны вернуть функцию сложения, один из аргументов
которой задан при ее создании, а второй может варьироваться. Как я понимаю, это — замыкание — доступ к переменным, объявленным вне тела функции.
def addition_inner(val): """ >>> add5 = addition_inner(5) >>> add5(3) 8 >>> add1 = addition_inner(-1) >>> add1(3) 2 >>> add_str = addition_inner('s') >>> add_str(3) Traceback (most recent call last): . TypeError: unsupported operand type(s) for +: 'int' and 'str' """ def func(arg): return arg + val return func def addition_lambda(val): """ >>> add5 = addition_lambda(5) >>> add5(3) 8 >>> add1 = addition_lambda(-1) >>> add1(3) 2 >>> add_str = addition_lambda('s') >>> add_str(3) Traceback (most recent call last): . TypeError: unsupported operand type(s) for +: 'int' and 'str' """ return lambda x: x + val
3. Написать фабрику, аналогичную п.2, но возвращающей список таких функций
В данном случае есть смысл возвращать список функций, которые мы написали выше.
Выглядеть будет примерно так:
def additions(start, end): """ Returns list of addition functions >>> for addition in additions(0, 5): . print addition(1) 1 2 3 4 5 >>> print additions(5, 0) [] >>> print additions(0, 2) # doctest: +ELLIPSIS [, ] """ return [addition_inner(val) for val in range(start, end)]
4. Написать аналог map:
— первым аргументом идет либо функция, либо список функций
— вторым аргументом — список аргументов, которые будут переданы функциям
— полагается, что эти функции — функции одного аргумента
Данное задание я реализовал с использованием встроенного map (как вариант — заменен циклом). Так же, для проверки типа переданного значения использовал функцию isinstance и модуль collections, как аналог hasattr и магическому методу __len__.
def mymap(func, args): """ Applies list of functions for args. >>> add0 = addition_inner(0) >>> add1 = addition_inner(1) >>> add2 = addition_inner(2) >>> add5 = addition_inner(5) >>> print mymap(add5, [1, 2, 3]) [6, 7, 8] >>> print mymap([add0, add1, add2], [1, 2, 3]) [(1, 2, 3), (2, 3, 4), (3, 4, 5)] >>> print mymap([], []) [] >>> print mymap(sum, [(3, 4, 5, 6, (7,))]) [25] """ if isinstance(func, collections.Iterable): return [tuple(map(f, args)) for f in func] # или #return [tuple(f(arg) for arg in args) for f in func] else: return [func(arg) for arg in args]
Итераторы
Маленькое отступление. Я не видел особого смысла писать код итераторов, т.к. их код описан в документации к модулю itertools. Врядли я напишу лучше.
Итераторы основываются на генераторах, о которых есть прекрасная статья.
Модули
1. У нас есть импортированный модуль foo, как узнать физический путь файла, откуда он импортирован?
Путь хранится в аттрибуте __file__ модуля.
2. Из модуля foo вы импортируете модуль feedparser. Версия X feedparser’а есть в общесистемном каталоге site-packages, версия Y — рядом с модулем foo. Определена переменная окружения PYTHONPATH, и там тоже есть feedparser, версии Z. Какая версия будет использоваться?
Будет импортирована версия Y.
Согласно документации (6 раздел туториала), порядок импорта следующий:
1. директория рядом со скриптом, который был запущен
2. PYTHONPATH
3. системный каталог
3. Как посмотреть список каталогов, в которых Python ищет модули?
>>> import sys >>> sys.path
4. У вас есть модуль foo, внутри него импортируется модуль bar. Рядом с модулем foo есть файлы bar.py и bar/__init__.py Какой модуль будет использоваться.
Будет использован второй, т.е. пакет. Как я понял, происходит рекурсивный обход директорий, и пакеты импортируются первыми.
5. Что означает и для чего используется конструкция __name__ == ‘__main__’
Используется для определения был ли файл импортирован или запущен. Если мы его запускаем, то значение будет __main__, если импортируем — имя модуля.
Сегодня — все, спасибо.
P.S. если кому будет интересно — напишу свою версию ответов на последние 2 раздела.