Можно ли просто начать добавлять атрибуты к объектам Skyfield?

Здесь "OK" означает, конечно, AYOR (на ваш страх и риск), но в остальном никаких предсказуемых проблем не возникает, если избегать очевидных конфликтов с именами существующих атрибутов.

Объекты Skyfield, особенно планеты, обычно имеют ограниченное количество атрибутов. Я часто пишу короткие сценарии для извлечения числовых данных, которые я сохраняю в виде текста и использую позже. По сути, это «одноразовые» сценарии, поскольку я редко использую их более одного или двух раз и никогда не делюсь ими.

Когда я пишу более надежный код, я обязательно создаю свои собственные объекты-контейнеры.

Мой вопрос: кажется, что у меня все работает хорошо, поэтому в этом конкретном контексте есть ли что-то, что может пойти не так, помимо конфликта имен атрибутов?

from skyfield.api import load
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

eph   = load('de421.bsp')
earth = eph['earth']
sun   = eph['sun']

ts = load.timescale()

t  = ts.utc(2016, 1, np.linspace(0, 366, 1000))

# SLOPPY WAY: just add them directly
earth.pos  = earth.at(t).position.km
sun.pos    = sun.at(t).position.km
earth.r    = np.sqrt(((earth.pos-sun.pos)**2).sum(axis=0))
earth.peri = earth.r.min()
earth.apo  = earth.r.max()

print earth.peri, earth.apo, earth.pos.shape


# BETTER WAY: tedious but more cautious
uhoh  = dict()
ep    = earth.at(t).position.km
sp    = sun.at(t).position.km
r     = np.sqrt(((ep-sp)**2).sum(axis=0))
uhoh['pos']  = ep
uhoh['r']    = r
uhoh['peri'] = r.min()
uhoh['apo']  = r.max()
earth.uhoh   = uhoh

print earth.uhoh['peri'], earth.uhoh['apo'], earth.uhoh['pos'].shape

возвращает:

147100175.99 152103762.948 (3, 1000)
147100175.99 152103762.948 (3, 1000)

person uhoh    schedule 06.05.2016    source источник
comment
Почти всегда плохая идея добавлять к объекту произвольные элементы, если только класс не был специально разработан для этого. Позже это может сломаться ужасным образом. почему ты хочешь сделать это? Если необходимо, лучшим способом было бы создать собственный класс-контейнер, который обертывает объект небесного поля и включает любые дополнительные атрибуты, связанные с ним, которые вы хотите использовать.   -  person Iguananaut    schedule 06.05.2016
comment
@uhoh Это немного лучше, так как это поможет избежать конфликтов имен (технически вы добавляете только один атрибут). Но я все еще согласен с @Iguananaut; создайте класс-контейнер, который принимает объект skyfield в своем конструкторе, вычисляет и присваивает любые значения, необходимые для переменных экземпляра.   -  person pzp    schedule 06.05.2016
comment
@pzp, тогда мы все согласны с этим, спасибо! Но если я это сделаю, есть ли другие вещи, которые могут пойти не так помимо конфликта в имени атрибута? Что-то немного глубже в питоне, о чем я не знаю? Вот мой вопрос. Я сторонник хорошего программирования, но у меня все еще есть нездоровое любопытство к тому, что может пойти не так.   -  person uhoh    schedule 06.05.2016
comment
С большинством объектов Python ничего. Назначение несуществующих атрибутов — это просто ярлык для obj.__dict__[attr] = val, если только объект не использует слоты или не переопределил __setattr__.   -  person Iguananaut    schedule 06.05.2016
comment
красочное обсуждение слотов   -  person uhoh    schedule 06.05.2016


Ответы (1)


Это действительно шаблон, который иногда встречается в неформальном коде Python. Другая важная вещь, которая может пойти не так, помимо будущего конфликта имен атрибутов, заключается в том, что автор библиотеки по наущению людей, которые хотят более эффективно создавать миллионы объектов, добавляет спецификацию __slots__, и вы начинаете получать ошибку при попытке добавить дополнительные атрибуты.

Защита от __slots__, если она возникнет, заключается в использовании вашего собственного подкласса класса, который вы хотите использовать. Если в подклассе не указано также __slots__ — говоря, по крайней мере, __slots__ = [], даже если у него больше нет атрибутов, которые он хочет добавить — тогда экземпляры подкласса широко открыты и могут иметь любые атрибуты, так что вы всегда можете создать свой собственный подкласс, который «разблокирует» экземпляры и позволяет им иметь любые атрибуты.

Обратите внимание, что такие объекты, как earth, могут быть ключами словаря, поэтому, если у вас есть часть информации, которую вы хотите связать с каждой планетой, вы можете сказать что-то вроде:

positions = {}
positions[earth] = ...

Это один из распространенных шаблонов, когда у вас есть дополнительная информация для запоминания о каждом из набора объектов.

person Brandon Rhodes    schedule 06.05.2016