В двух приведенных ниже self.load_file()
методах первый не имеет аргументов и использует переменные экземпляра self.a
и self.b
, а второй использует a
и b
напрямую в качестве входных аргументов, а load_file
по сути становится статическим методом. Они оба достигают одной и той же цели, какой из них лучше/предпочтительнее и почему?
Во-вторых, если бы у меня были дополнительные переменные экземпляра, которые зависят от предыдущей, например. self.d = self.do_something_with_file()
и self.e = self.do_something_with_d()
, это запах кода, если есть какая-то последовательная зависимость, в которой создаются переменные экземпляра? Например, если во время self.file = self.load_file()
возникнет необработанное исключение, то последовательная цепочка ниже (то есть self.d
и self.e
) также разорвется. Является ли эта «последовательная зависимость» (я не уверен, есть ли для этого термин) экземпляром стиля на практике (особенно в более крупных/производственных программах) обычным явлением?
class SomeClass:
def __init__(self, a, b):
self.a = a
self.b = b
self.file = self.load_file()
def load_file(self):
for file in os.listdir(config.dir):
file_split = file.split("_")
file_a, file_b = file_split[0], file_split[2]
if file_a == self.a and file_b == self.b:
try:
return pickle.load(open(config.dir + '{}'.format(file), 'rb'))
except OSError as e:
raise Exception("pickle.load error.") from e
else:
raise FileNotFoundError('file not found.')
против
class SomeClass:
def __init__(self, a, b):
self.a = a
self.b = b
self.file = self.load_file(a, b)
@staticmethod
def load_file(a, b):
for file in os.listdir(config.dir):
file_split = file.split("_")
file_a, file_b = file_split[0], file_split[2]
if file_a == a and file_b == b:
try:
return pickle.load(open(config.dir + '{}'.format(file), 'rb'))
except OSError as e:
raise Exception("pickle.load error.") from e
else:
raise FileNotFoundError('file not found.')
как уже писалось, это вопрос опыта и личного вкуса, но если у вас, допустим, у вас есть УтилитыКласс, который инкапсулирует эту конкретную функцию (ы), вам будет лучше, если вам нужно что-то изменить в функции, без чтобы позаботиться о том, где эта функция будет использоваться:
class UtilityClass:
@staticmethod
def load_file(a,b):
...
class A:
def __ini__(self, a, b):
self.a = a
self.b = b
self.file = UtilityClass.load_file(a,b)
Удачи :)
Спасибо за ответ! что вы думаете о второй части моего вопроса? имеет ли смысл последовательная зависимость?
Я бы использовал служебный модуль с простой функцией.
# utility.py
from pathlib import Path
import pickle
# default path
default_file = Path("object.foo")
def load_file(file_path: Path = default_file):
with file_path.open("rb") as file:
return pickle.load(file)
# main.py
from utility import load_file
class Foo:
...
try:
f = load_file()
except FileNotFoundError:
f = Foo()
assert isinstance(f, Foo)
поэтому загрузчик файлов можно было легко использовать для любого объекта.
Это чисто дело вкуса. Я бы, вероятно, использовал переменные в
load_file
, особенно если я думаю, что их можно использовать повторно. Но это очень слабое предпочтение. Однако я бы говорю, что имена переменных должны быть лучше, чемa
иb
, которые абсолютно ничего не говорят мне о том, для чего они нужны.