Изменяет ли существование производного класса базовый класс, даже если производный класс никогда не используется? - PullRequest
0 голосов
/ 29 мая 2020

У меня есть базовый класс Sample и производный класс SignalSample, и код для обоих этих классов обычно находится в одном файле Sample.py.

Я импортирую эти классы в свой main обычным способом: from Sample import Sample, SignalSample

При поиске ошибки в одном из этих классов я заметил необычное поведение: удаление кода для производного класса SignalSample изменило поведение Signal базовый класс.

Итак, мой вопрос: может ли существование производного класса изменить базовый класс, даже если производный класс никогда не создается?

Чтобы быть конкретным, я пробовал следующие комбинации:

  1. Код для Sample и SignalSample находится в Sample.py. from Sample import Sample, SignalSample используется в моем основном скрипте для загрузки этих классов. Созданы экземпляры Sample объектов, экземпляры SignalSample объектов не созданы, код просто существует и не используется. В этом случае я получаю сообщение об ошибке, которое назову «тип 1».
  2. Удалите код для SignalSample внутри Sample.py и удалите оператор ... import SignalSample. В этом случае я получаю другую ошибку, которую я назову "тип 2".

Обратите внимание, что я не думаю, что ошибки исходят от самих классов (хотя они могут быть), Более того, мне показалось интересным, что поведение кода, похоже, изменилось из-за унаследованного класса, хотя этот класс не использовался.

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

# file Sample.py
class Sample:
   def __init__(self):
      self._tfile = None
      self._filepath = None

   def calculate_filepath(self):
      return "my/file/path"

   __calculate_filepath = calculate_filepath # private copy

   def get_histogram(self, histogram_name):
      if not self._filepath:
         self._filepath = self.calculate_filepath()
      if not self._tfile:
         from ROOT import TFile # this is a special filetype 
         self._tfile = TFile.Open(self._filepath, "READ")

      histo = self._tfile.Get(histogram_name)
      histo.SetDirectory(0)
      self._tfile.Close()
      return histo

class SignalSample(Sample):
   def __init__(self):

      # Inherit
      Sample.__init__(self)

      self._filepath = self.calculate_filepath()

   def calculate_filepath(self):
      # Overloaded version of the function in Sample
      return "my/very/special/filepath"

Обратите внимание, что я решил вызвать метод calculate_filepath внутри get_histogram, потому что я хотел избежать возможных конфликтов пространства имен с производным классом. По этой же причине я пытаюсь сделать метод «частным» с изменением пространства имен. Вот почему я открываю специальный файл TFile внутри метода get_histogram, хотя приятно, что я могу затем также Close этот файл внутри той же функции. Возможно, это неправильное использование и, возможно, это связано с источником моей проблемы?

1 Ответ

1 голос
/ 01 июня 2020

get_histogram выглядит потенциально неработающим, если вызывается более одного раза. Вы назначаете открытый файл экземпляру (на self._tfile), но затем закрываете его перед возвратом ... это означает, что при следующем вызове метода not self._tfile, вероятно, (*) будет оцениваться как False, что означает, что вы затем попробуйте вызвать Get для закрытого файла. Если вы используете нормальную библиотеку, это, вероятно, вызовет приятную ошибку, сообщив вам об этом, но я вижу, что вы используете ROOT, так что кто знает, что может случиться :)

Вероятно, самым простым было бы not , чтобы сохранить файл на Sample, и просто открывать файл всякий раз, когда вызывается get_histogram?

(*) Иногда стоит избегать неявной booliness. В частности, когда вы на самом деле хотите проверить, является ли что-то «Нет», лучше писать if x is None: (https://legacy.python.org/dev/peps/pep-0008/#programming -рекомендации )

Кстати, в этом примере , __calculate_filepath = calculate_filepath # private copy ничего не делает, так как вы никогда не используете его.

...