Как инициализировать список, определенный на уровне класса, с помощью общего метода вне класса в Python?

У меня есть список, определенный на уровне класса в Python, и ниже приведен мой код:

class TestStudentReg(unittest.TestCase):
    student_id_list = []  

Я пытаюсь инициализировать список, читая значения из файла csv, и ниже приведен метод, который я использую в том же классе, т. е. TestStudentReg.

@classmethod
def initialise_student_id_list(cls):
    filename = 'input/student_testdata.csv'        
    with open(filename, 'r') as csvfile:
        datareader = (csv.reader(csvfile, delimiter = "|"))
        next(datareader, None)  # skip the headers
        for col in datareader:
            cls.student_id_list.append(col[2])

Теперь, когда этот метод является общим для нескольких классов, я планирую сделать его функцией многократного использования и определить его в отдельном файле Python (utilities.py), который будет выглядеть следующим образом:

import csv
import logging
import time
import timeit

def get_date(dateformat = "%Y-%m-%d", subtract_num_of_days=0):
   getdate = date.today() - timedelta(subtract_num_of_days)
   return getdate.strftime(dateformat)

def initialise_student_id_list(**kwargs):  
    filename = 'input/student_testdata.csv'      
    with open(filename, 'r') as csvfile:
        datareader = (csv.reader(csvfile, delimiter = "|"))
        next(datareader, None)  # skip the headers
        for col in datareader:
            cls.student_id_list.append(col[2])

Я хотел бы понять, как инициализировать Student_id_list из файла утилит.

Один из способов реализовать это заключался в том, чтобы метод возвращал список и инициализировал значение, вызывая этот метод.

def initialise_student_id_list(**kwargs):  
        id_list=[] 
        filename = 'input/student_testdata.csv'     
        with open(filename, 'r') as csvfile:
            datareader = (csv.reader(csvfile, delimiter = "|"))
            next(datareader, None)  # skip the headers
            for col in datareader:
                cls.student_id_list.append(col[2])
        return id_list

Не уверен, что это правильный подход. Отлично, если кто-нибудь сможет мне помочь в этом, пожалуйста.

Откуда взялась переменная filename в вашем методе класса? Пожалуйста, отредактируйте, чтобы показать, где это определено.

Luke L 11.07.2024 06:13

Какой смысл перемещать метод класса из модуля, в котором определен класс, в его собственный модуль? Я понимаю, что вы ожидаете, что его будут использовать несколько классов, но метод, который нужно использовать, заключается в наследовании от класса, в котором определен метод - если вы настаиваете на помещении его в отдельный модуль, поместите класс в этот модуль и создайте TestStudentReg потомок этого класса.

Grismar 11.07.2024 06:21

@Grismar В основном я с тобой согласен. Но в некоторых случаях наследование от класса нецелесообразно. Например, если есть какой-то класс, которому нужна эта функциональность, но он не имеет никакого отношения к тому, что делает TestStudentReg? Я думаю, что метод класса — не лучший выбор, и перенос его в отдельный модуль может быть намного лучше.

Luke L 11.07.2024 06:24

Когда функция ожидает, что класс будет передан в качестве аргумента, а затем начинает изменять содержимое этого класса (что и делает код OP), это полезно только в контексте такого класса, и, конечно, не лучше напишите это как независимую функцию. Конечно, вы могли бы полностью переписать его, чтобы он стал независимой функцией или классом, который можно было бы объединить в другой класс, но тогда мы по сути говорим: «вам нужно вообще что-то другое», и это обменивается мнениями, а не отвечает на вопрос. .

Grismar 11.07.2024 07:09

@Grismar, я согласен. Извините за предыдущий комментарий, но в любом случае я думаю, что смогу ответить на вопрос ОП.

Luke L 11.07.2024 07:11
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
5
63
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть несколько способов решить вашу проблему. Здесь я перечислю три, увеличивающие читабельность и общее качество:

def student_id_list_initialiser(class_obj, **kwargs):
    cls = class_obj   
    filename = 'input/student_testdata.csv'      
    with open(filename, 'r') as csvfile:
        datareader = (csv.reader(csvfile, delimiter = "|"))
        next(datareader, None)  # skip the headers
        for col in datareader:
            cls.student_id_list.append(col[2])

class MyTest():
    student_id_list = []
    
    @classmethod
    def initialise_student_id_list(cls):
        student_id_list_initialiser(cls)

Этот подход работает нормально, но он не самый лучший, поскольку нам приходится вручную передавать объект класса, и код нарушает инкапсуляцию. Однако в сочетании с простым и коротким методом класса, который устанавливает переменную класса student_id_list, это будет лучше:

def student_id_list_creator(**kwargs):
    ret_l = []
    filename = 'input/student_testdata.csv'      
    with open(filename, 'r') as csvfile:
        datareader = (csv.reader(csvfile, delimiter = "|"))
        next(datareader, None)  # skip the headers
        for col in datareader:
            ret_l.append(col[2])
    return ret_l

class MyTest():
    student_id_list = []
    
    @classmethod
    def initialise_student_id_list(cls):
        cls.student_id_list = student_id_list_creator()

Это похоже на то, о чем вы говорили, и да, это действительно хороший подход. Наконец, наследование, пожалуй, лучший вариант здесь, хотя и не прямое наследование от класса TestStudentReg. Вот код:

class StudentInfoHelper():
    @classmethod
    def initialise_student_id_list(cls):
        filename = 'input/student_testdata.csv'        
        with open(filename, 'r') as csvfile:
            datareader = (csv.reader(csvfile, delimiter = "|"))
            next(datareader, None)  # skip the headers
            for col in datareader:
                cls.student_id_list.append(col[2])

class TestStudentReg(StudentInfoHelper):
    student_id_list = []

# outside:
TestStudentReg.initialise_student_id_list()

Этот код не только более читабелен, но и гораздо более гибок и может применяться к любому классу, если этот класс наследуется от StudentInfoHelper. Единственным недостатком этого подхода является то, что

  1. Вы должны назвать переменную класса student_id_list. Но поскольку вы уже выбрали имя переменной, это не будет проблемой.
  2. Это не сработает, если вы определите метод с именем student_id_initialiser. Причина здесь довольно очевидна: если вы это сделаете, исходный метод будет «затмлен» новым. Но иногда это также хорошо, если вы хотите настроить метод или не хотите его.

Это здорово - спасибо. Почему в третьем подходе мы вызываем метод TestStudentReg.initialise_student_id_list() снаружи? Должно ли это быть внутри класса TestStudentReg?

Balaji Venkatachalam 11.07.2024 19:30

@BalajiVenkatachalam Наверное. Если у вас есть метод __init__() или другой инициализатор, поместите его туда. Поскольку я не знаю других частей вашего класса, я просто вынес вызов метода наружу. На практике предполагается, что он находится внутри какого-то метода класса TestStudentReg.

Luke L 11.07.2024 20:51

Другие вопросы по теме