본문 바로가기
Project/Python_Basic

Python Class Attribution 추가

by sonpang 2022. 1. 26.
반응형

오늘은 Python Study 중 Team member 중 한분이 질문해주신 것에 대해 포스팅해보려 합니다.

 
 
일단 아래의 예제를 풀이하면서 질문을 주셨습니다.
 

1. 해당 질문이 나온 예제

이번 시험 결과에 대한 데이터를 학과 사무실에서 CSV파일로 전달해줬습니다. 우리는 이 파일을 이용해서 데이터 처리를 진행해야 합니다. 파일 입출력을 이용해 파일 데이터를 리스트로 만들어보세요.

  • 파일 입출력에 사용하는 open 함수를 이용해 CSV 파일 내부의 데이터를 읽어보세요
  • merge list를 이용해 리스트 내 데이터의 평균을 출력해보세요.
  • 데이터를 합치기 전 데이터의 자료형을 변경해보세요.
  • 리스트의 데이터를 다루는 함수를 이용해서 구현해보세요.
  • 최종 평균을 구한 후 오름차순으로 정렬해주세요.

질문 주신 팀원분의 code는 아래와 같습니다.

import csv #csv 모듈 사용
class ReadCSV(): #CSV 읽기용 class
    def _init_(self, file_path):
        self.file_path= file_path
    #초기값 설정
    def open_file(self):
        self.f = open(file_path,'r',newline='',encoding='utf-8')
        self.contents=csv.reader(self.f)
        return self.contents
    #file open 후 csv 값으로 반환
    def read_file(self):
        self.open_file()
        line=[]
        for row in self.contents:
            line.append(row)
        self.f.close()
        return line
    # csv 값 읽은 후 list로 반환, for문 관련 line이라는 변수 선언
    def merge_list(self):
        self.open_file()
        line=[]
        row_list=[]
        for row in self.contents:
            for val in row:
                row_list.append(int(val))
            line.append(row_list)
            row_list=[]  
        self.f.close()
        sum_list =[]
        for i in range(len(line)):
            sum_list.append(sum(line[i])/len(line[0]))
        return sorted(sum_list)
    #csv값 읽은 후 int형 list로 반환, 이중 for문 사용 시 첫 for문 끝나기전 변수초기화 필요
    # 각 list의 각 행의 합을 열의 길이로 나눠준 후 솔팅값 반환
file_path = "./data-01-test-score.csv"
read_csv= ReadCSV(file_path)
print(read_csv.read_file())
print(read_csv.merge_list())

 

 

2. 질문

Class에서 self를 붙이는 부분이 좀 많이 헷갈려서 이번 과제할 때 코드가 좀 지저분했습니다. 다시 변수선언을 해야했어서요. 제 생각엔 초기 선언 된 변수들(ex. a = (int)0)을 제외하고, 메소드들 끼리 연결되어 사용할 때는 붙여야 하는 거라고 판단했는데, 혹시 팀원분들의 정리된 자료나 조언 얻을 수 있을까요?

 

 

3. 해당 예제에 대한 제 CODE

해당 문제에 대한 제 code는 아래와 같습니다.

import csv
filepath = "./data-01-test-score.csv"

class ReadCSV():
	def __init__(self, file_path):
		self.file_path = file_path
  
  	def open_file(self):
        try:
            f = open(self.file_path, "r")
        except FileNotFoundError as e:
            print("파일이 없습니다.")
            print(e)
        else:
            return f

  	def read_file(self):
    	f = self.open_file()
    	if(f is None):
      		return
    	read = csv.reader(f)
    	result = []
    	for line in read:
      		result.append(line)
    	f.close()
    	return result

	def merge_list_average(self):
		f = self.open_file()
        if(f is None):
          	return
        read = csv.reader(f)
        result = []
        for line in read:
          	result.append(sum(map(int, line)) / len(line))
        f.close()
        result.sort()
        return result

read_csv = ReadCSV(filepath)
print(read_csv.read_file())
print(read_csv.merge_list_average())

뭐.. 다시보니 제 code도 못마땅해보이는 부분이 있긴 한데요. 뭐 disposable code니까요.

 

 

4. 답변

self = 생성된 instance 그 자체라고 하셨는데 저도 일차적으로는 그렇게 이해하였습니다. Class definition을 구현하는 code에서는 self로 불리고 다른 sections에서는 별도의 변수명을 가지고 접근하는 것 같습니다.


self에 대해 조금 더 깊이 이해하려면 instance의 namespace에 대해 이해할 필요가 있는 것 같은데, self의 id를 화면에 출력해보면 이해하는데 도움이 될 것 같습니다. 

4.1. 팀원님 code

팀원님의 code를 보면 __init__로 초기화하고 있는데 이 method는 생성자가 됩니다. 따라서 ReadCSV라는 붕어빵 틀로 file_path라는 앙금종류를 선택한 것이라고 생각할 수 있겠네요. 이제 다른 method도 보겠습니다.

 

def open_file(self):
        self.f = open(file_path,'r',newline='',encoding='utf-8')  
        # self.f : ReadCSV Class에 f라는 attribution은 없습니다. 
        # 따라서 굳이 self를 사용할 필요는 없을 것 같습니다. 
        # 다만, self를 적는게 정확히 어떤 effect를 내는지는 좀 더 알아봐야겠습니다.
       ...
 def read_file(self):
        self.open_file()    
        # self.open_file() : ReadCSV Class에 open_file이라는 method가 있습니다. 
        # 따라서 self를 적는게 맞습니다.

 

4.2. id 찍어보기

팀원님 code에 id 찍어보는 code를 추가해보았습니다.

def open_file(self):
        self.f1 = open(file_path,'r',newline='',encoding='utf-8')
        f2 = open(file_path,'r',newline='',encoding='utf-8')
        print("f1 : ", id(self.f1))        ...............1
        print("f2 : ", id(f2))             ...............2
print(id(read_csv.f1))                  ...............3
print(id(f2))                             ................4


이렇게 하면 1, 2, 3은 제대로 출력하지만 4출력문은 NameError가 출력됩니다. f1같은 경우 self.f1으로 선언되면서 read_csv의 속성을 추가하는 것으로 동작하였고 f2는 open_file이라는 method내에서만 사용되는 local변수로 사용되었기 때문에 4출력문에서는 f2가 정의되어 있지 않다는 error를 출력하는 것 같습니다.

 

 

4.3. Attribution 출력해보기

Name space와 scope에 대해 이해하셨다면 아래 출력문들이 이해를 조금 더 높일 수 있을 것 같습니다.

 

# __dir__ : class 내부에서 사용 가능한 모든 속성 확인
# __dict__ : instance 내부 속성 확인

print(read_csv.__dir__())

# ['f', 'contents', '__module__',  ...] # 팀원님 결과
# ['file_path', '__module__', '__init__' ...] # 제 code 결과

print(read_csv.__dict__)
# {'f': <_io.TextIOWrapper name='./data-01-test-score.csv' mode='r' encoding='utf-8'>, 'contents': <_csv.reader object at 0x7f227f4efbd0>} # 팀원님 결과
# {'file_path': './data-01-test-score.csv'} # 제 code 결과

 


4.4. Namespace

저도 아직 학부 2학년생이라 잘 모르지만, 굉장히 연구가 활발한 주제라고 알고 있습니다. 특히 network(Container)분야에서요. Namespace를 제가 알고 있는 수준에서 말씀드리자면 프로세스가 무엇을 볼 수 있는지 프로세스가 존재하는 world를 정의한다고 보시면 될것 같습니다.(만약, 어시장에서 namespace가 다르다는 것은 서로 다른 수조를 바라본다는 의미입니다. 즉, 서로 다른 물고기(memory? 변수?)를 보게되겠죠.)

 

 

이정도로 일단 SLACK에 답변을 드렸긴 했습니다. 같이 배우는 팀원 입장에서 이런 질문들을 해주시는 게 정말 좋은 것 같습니다. 물론 제가 정확히 모르는 부분에 대해 섣부른 답변을 드리면 안되겠지만, 제 답변에 오류가 있다면 또 다른 분들이 의견을 주시거나 제 답변을 더 발전시켜 주실테니까요! 어쨋든 이런 Study... 생각보다 많이 얻어갈 수 있는 시간이 될 것 같습니다. 아직 부스트코스 AI Baisc 초기라 비교적 쉬운 내용을 배우는데도 이런 질문들이 나와서 나중에 배울 내용들에 대해선 팀원분들이 어떤 질문들을 해주시고 또 저는 어떤 질문들이 생길까 기대가 됩니다!

반응형

'Project > Python_Basic' 카테고리의 다른 글

부스트코스 코칭스터디 : AI Basic 1기  (6) 2022.01.22
Python Stopped Working on Jupyter  (4) 2022.01.14

댓글