wecode TIL day 8 (Oct 26)

Jae Hoon Shin, 신재훈, Noah·2020년 10월 26일
1

Complex Dictionary

List of Dictionaries

list를 dictionary로 구성하면 손쉽게 여러 dictionary들을 grouping 할 수 있습니다.

그리고 for 구문을 사용하여 각각의 dictionary들을 읽어들이고 원하는 로직을 실행할 수 있습니다.

Nested Dictionary

위의 list of dictionaries에서 특정한 정보만 읽고 싶다면?
하나하나 확인해봐야합니다.

하지만 이렇게 하면 list의 길이가 1억개라면 10억개라면먹고싶다, nested dictionary를 사용합니다.
(위 두그림은 합쳐 진것임)
위처럼 dictionary안에 dictionary를 중첩적으로 사용하면 원하는 데이터를 더 효과적으로 표현할 수 있습니다!

Assignment

다음은 우리나라 K리그 1, 2부의 축구팀 정보입니다.
Parameter로 주어진 축구팀의 다음 정보들을 dictionary로 리턴해주세요.

구단
연고지
리그참가
주 경기장

예를 들어, input으로 "강원 FC"가 주어지면 다음과 같은 dictionary가 리턴 되어야 합니다.

{
    "구단": "강원 FC",
    "리그참가": 2009,
    "연고지": "강원도(춘천시)",   
    "주 경기장": "춘천송암레포츠타운"
}
def get_team_info(team_name):
  ## 이 함수를 구현해주세요
  football = { 
"강원 FC" : {
      "구단" : "강원 FC",
      "리그참가" : 2009,
      "연고지" : "강원도(춘천시)",
      "주 경기장" : "춘천송암레포츠타운"
    },
"광주 FC" : {
      "구단" : "광주 FC",
      "리그참가" : 2011,
      "연고지" : "광주광역시",
      "주 경기장" : "광주월드컵경기장"
    },
"대구 FC" : {
      "구단" : "대구 FC",
      "리그참가" : 2003,
      "연고지" : "대구광역시",
      "주 경기장" : "DGB대구은행 파크"
    }
   }
  return football[team_name]
    

nested의 개념을 이해하고, return의 개념을 이해하고, 어떤식으로 데이터를 불러들려야하는지 특히 기억해야 하는 것

return football[team_name]
이건, football 딕셔너리안에 예) "광주FC" key를 불러오는것..

{
      "구단" : "광주 FC",
      "리그참가" : 2011,
      "연고지" : "광주광역시",
      "주 경기장" : "광주월드컵경기장"
    }

이렇게 나오고
return football[team_name]["리그참가"] 라고 하면
2011 을 반환할 것!!!!

More Complex Function Parameters

함수의 positional argument 와 keyword argument에 대해서 배워봤으니 이제 한단게 더 복잡한 함수 parameter 방식!!

Handling unknown number of arguments

사전에 정확히 필요한 parameter 수와 구조를 알수 없는 경우는 어떻게 해야할까요?

가장 간단한 방법은 다음처럼 dictionary를 parameter로 받아서 사용하는 것입니다. 하지만 옵션을 dictionary로 받아야만 한다는 제약사항이 있습니다. 만일 옵션을 하나도 추가 안하고 기본사양으로 사는 경우에도 비어있는 dictionary를 넘겨줘야하는것이죠. 그리고 dictionary가 아닌 다른 타입의 값(예를 들어 string)을 넘겨주는 오류가 생길 확률도 있습니다.

Keyworded variable length of arguments

Keyworded variable length of arguments는 이름 그대로 keyword arguments 인데 그 수가 정해지지 않고 유동적으로 변할 수 있는 keyword arguments 입니다.

Keyworded variable length of arguments를 선언 하기 위해서는 parameter 이름앞에 두개의 별표 * 두개 로 시작해야 합니다.

함수를 호출할때 일반적인 keyword arguments 처럼 사용하면 됩니다. 일반적인 keyword arugments와의 차이점은:

  1. Argument 수를 0부터 N까지 유동적으로 넘겨줄 수 있습니다.
  2. Keyword가 미리 정해져 있지 않기때문에 원하는 keyword를 유동적으로 사용할 수 있습니다.
  3. Keyworded variable length of arguments는 dictionary 형태로 지정됩니다.

대부분 **kwargs 라고 parameter 이름을 정합니다.


위 코드를 호출 할 때,
그러면 kwargs 파라미터는 다음과 같은 dictionary로 함수에 전해지게 됩니다:

Non-keyworded variable length of arguments

Non-keyworded variable length of arguments 혹은 그냥 variable length of arguments 라고 합니다.

더 간단하게 variable arguments 라고 하기도 합니다.
선언하는 방법은 별표 2개 대신에 1개를 사용해서 선언합니다.

그리고 variable arguments는 tuple로 변환되어 함수에 전달됩니다.

Mixing args and kwargs

둘다 사용하면 어떠한 형태와 수의 argument도 허용 가능한 함수가 됩니다.

Assignment

함수 2개를 구현해주세요. 함수의 이름은 다음과 같아야 합니다.

sum_of_numbers
what_is_my_full_name

함수 sum_of_numbers는 arugment로 주어지는 모든 수를 합한 값을 리턴해야 합니다.

예를 들어, sum_of_numbers(1, 2, 3, 4, 5) 는 15를 리턴해야 하고 sum_of_numbers(1,2)는 3을 리턴해야 합니다.
만일 parameter가 주어지지 않으면 0을 리턴해야 합니다.

what_is_my_full_name 함수는 주어진 parameter중 first_name 과 last_name 이라는 parameter를 조합하여 full name을 리턴해주어야 합니다.

예를 들어, first_name이 "우성" 이고 last_name 이 "정" 이면 "정 우성" 라고 리턴하면 됩니다.
Last name과 first name 사이에 space(빈칸)이 들어가 있어야 합니다.
만일 last_name이 없거나 first_name이 없으면 둘 중하나만 리턴하면 됩니다.
예를 들어, last_name이 없으면 "우성" 이라고 이름만 리턴하면 됩니다,
마지막으로, last_name과 first_name 둘다 없으면 "Nobody" 라고 리턴하면 됩니다.

삐빅 👷🏼‍♂️ 🚧 ⛏ 삽질 구간입니다.

나의 접근:

일단 sum_of_numbers 가 0이 라면 0을 리턴,
나머지는 모두 args parameter안에 있는걸 다 더하고 리턴
1번째는 쉽게 했다.

def sum_of_numbers(*args,):
  if args == 0:
    return 0
  else:
    sum(args)
  return sum(args)
# 통과!      
  
def what_is_my_full_name(first_name, last_name):
  if first_name == False and last_name == False:
    return "Nobody"
  else:
    name = last_name +" "+ first_name 
  return name
 #에러남!! 배운거 안써서 !!!


2번째는 애를 먹고 있는데 kwarg를 써야겠다.
어떻게 딕셔너리를, first nmae = "우성", last_name="정" 이걸
'정 우성'으로 리턴하게 하지? 한시간 삽질하는 과정,

def what_is_my_full_name(first_name, last_name):
일단 이거를 키워드 arg일것 같아서,
def what_is_my_full_name(**kwargs):
로 바꾸고,if문으로 둘다 first_name, last_name 주면 둘다 출력,
first_name, 가 있고 last_name가 없으면 first name만
first_name, 가 없고 last_name가 있으면 last name만
else: Nobody.

다시 ""어떻게 딕셔너리를, first nmae = "우성", last_name="정" 이걸
'정 우성'으로 리턴하게 하지? "",로 돌아가서 생각했다.
f"{first_name}" 문법은 중간에 스페이스를 쉽게 넣을 수있다. 변수도 넣고, 하지만 이제까지 프린트뒤에만 써서 전혀 몰랐는데 구글링을 통해 알아냈다. return도 가능하다는 것을,
그래서 f"{kwargs['last_name']}를 썼다.
kwargs 안에 last_name의 value!!
kwargs 안에 first_name의 value!!

Nested Function

함수 안의 함수를 선언할 수 있습니다.

Why use nested function?

1. 가독성

2. Closure

중첩 함수가 부모 함수의 변수나 정보를 가두어 사용하는 것을 closure라고 합니다.
그리고 부모함수는 중첩 함수를 리턴해줍니다.

  1. 중첩 함수가 부모 함수의 변수나 정보를 중첩 함수 내에서 사용한다.
  2. 부모 함수는 리턴값으로 중첩 함수를 리턴한다.
  3. 부모 함수에서 리턴 했으므로 부모 함수의 변수는 직접적인 접근이 불가능 하지만 부모 함수가 리턴한 중첩 함수를 통해서 사용될 수 있다.

어떠한 정보를 기반으로 연산을 실행하고 싶지만 기반이 되는 정보는 접근을 제한하여 노출이 되거나 수정이 되지 못하게 하고 싶을때 사용합니다.

위 코드는 이제까지 배운걸로 충분히 할수 있는 코드( 특정 숫자 2개 받으면)

이제 주어진 숫자의 승을 구하는게 아니라 특정 숫자의 승을 구하는 함수를 구현한다고 생각해봅시다. 예를 들어, 2의 승을 구하는 함수를 구현한다면 다음과 같습니다.
하지만 위의 함수는 2의 승밖에 구할 수 없습니다.
2뿐만 아니라 설정되는 수의 승을 구하는 함수는 아래 이미지 처럼! This is closure

Decorator 함수 구현 방법

자 그럼 아무 함수나 다 decorator로 장식 할 수 있을까요?

아닙니다. Decorator로 장식할 수 있는 함수는 중첩 함수(nested function)을 리턴하는 함수만 decorator 함수로 사용될 수 있습니다.
그 이유는 decorator의 기능을 다르게 설명 하면 chain of functions, 즉 여러개의 함수가 연속적으로 호출이 자동으로 되게 해주는거죠.

Assignment

Decorator를 구현해보세요.
Decorator는 앞서 배운 closure를 한단계 더 나아가 사용하는 고급 기능입니다.

Decorator는 closure처럼 중첩함수를 리턴하는 함수 이며 다른 함수에 적용해서, 적용된 함수가 실행되기 전에 무조건 실행됩니다. 즉 특정 함수를 실행하기 전에 강제적으로 다른 함수가 먼저 실행된후 실행되도록 하는 강제성을 제공하는 기능입니다.

더 자세한 내용은 아래 링크의 노션 자료를 참조하세요:

https://www.notion.so/wecode/Decorator-8e6eb41d0f95474c94ed0136bcbfc2b1

과제 !!

왼쪽 상단의 greeting 함수에 적용될 decorator 함수를 구현하여 greeting 함수에 적용해주세요.
Greeting 함수가 호출 되었을때 decorator 함수에 parametor 값이 greeting 함수 리턴값의 다음에 붙혀져서 리턴되어야 합니다. Decorator 함수의 이름은 welcome_decorator 여야 합니다.

예를 들어, 다음 처럼 정의 하여 welcome_decorator decorator를 적용하여 greeting을 호출하면:

@welcome_decorator
def greeting():
    return "Hello, "

greeting()

#결과값은  다음과 같아야 합니다.

"Hello, welcome to WECODE!"

접근 방법:
첫 한시간동안 아예 완전 잘못 접근했다.
def welcome_decorator & def greeting 이 2개의 함수로 풀려고 접근했어서 완전 시작부터 꼬였다.
출차: https://www.youtube.com/watch?v=dhRSkpzVXeI

데코레이터의 이해를 돕기 위해 유튜브의 도움을 받았다

첫사진은 데코레이터의 총 코드이며
두 번째 사진은
@trace
def hello(): 를 했을 때 프로세스가 어떻게 되는가 이다.

위 사진을 보니 데코레이터 구성에 대해 감이 잡혀서 바로 코드를 짰다.

def welcome_decorator(func):
  def wrapper():
    func()
    return (f"{func()}welcome to WECODE!")   
  return wrapper
  
@welcome_decorator
def greeting():
    return "Hello, "
greeting()


def welcome_decorator(func):
  def wrapper():
    return (func() + "welcome to WECODE!")
  return wrapper
  
@welcome_decorator
def greeting():
    return "Hello, "
greeting()

자세히 보면 코드가 위 아래로 2개 인데 둘다 pass가 나왔다.
첫 번째 코드를 먼저 쓰고 패스가 되었는데, 코드를 다시 찬찬히 보다보니 왜 이게 패스인지가 궁금했다. 그리고 아래 코드를 적었는데 훨씬 깔끔하고 이게 더 말이 되는 것 같았다. 첫 번째의 코드는 func()이 두번 선언 된게 아닌가?

Scope

Python에서 scope은 항상 객체가 선언된 지점에서 위로는 상위 객체 까지, 아래로는 모든 하위 객체들과 그 안에까지가 범위 입니다.

범위에는 크게 다음 4가지가 있는데,

Local Scope
Enclosed Scope
Global Scope
Built-in Scope

Local Scope


함수 안에서 선언 됬으므로, 함수 안에서만 유효

Enclosing Scope

중첩함수가 있을 때 적용되는 scope입니다.
부모함수에서 선언된 변수는 중첩함수 안에서도 유효한 범위를 가지고 있습니다.

Global Scope

함수 밖에서 선언된 변수나 함수를 이야기 합니다.

Built-in Scope

파이썬안에 내장되어 있는, 파이썬이 제공하는 함수 또는 속성들이 built-in scope를 가지고 있습니다.

그리고 built-in scope는 따로 선언이 없이도 모든 파이썬 파일에서 유효한 범위를 가지고 있습니다.

예를 들어, list등과 같은 자료구조의 element 총 개수를 리턴하는 len 함수가 바로 built-in scope를 가지고 있습니다.

Shadowing

파이썬은 변수나 함수의 정의를 찾을때 다음 순서의 scope들 안에서 찾습니다.

Local => Enclosing => Global => Built-in

즉 가장 좁은 유효범위 부터 시작 해서 넓은 범위로 나아가며 사용되는 변수나 함수의 정의를 찾습니다.

Assignment

왼쪽 상단에 코드를 수정하셔서 scope_test 함수에 parameter 값에 상관 없이 무조건 63이 리턴되도록 수정해주세요.

예를 들어 다음과 같이 되어야 합니다.

scope_test(10) == 63
scope_test(20) == 63
scope_test(333) == 63

주어진 코드:

what_is_my_scope = 7

def scope_test(what_is_my_scope):
  some_number = 9
  
  def inner_scope_test(what_is_my_scope):
    
    return some_number * what_is_my_scope
    
  return inner_scope_test(what_is_my_scope)

여기서 shadow를 줘야하고, 9에 뭘 곱하든 63이 나와야하니까 7을 더 안쪽으로 (로컬로) 넣어준다. 한코드만 더하고 pass 했다.

what_is_my_scope = 7

def scope_test(what_is_my_scope):
  some_number = 9
  
  def inner_scope_test(what_is_my_scope):
    what_is_my_scope = 7
    return some_number * what_is_my_scope
    
  return inner_scope_test(what_is_my_scope)

Class

코딩에서 사용되는 class 라는 단어가 가지는 의미는 "부류" 에 가장 가깝습니다. "동일한 범주에 속하는 대상들을 일정한 기준에 따라 나누어 놓은 갈래" 라는 국어사전의 뜻을 가지고 있습니다.
즉 Comedian 이 class 가 됩니다.
그러나 comedian이라는 것은 개념일 뿐입니다.
Comedian의 실체 (instanace) 는 이영자, 송영이, 양세형, 유병재입니다.
이 실체(instance)들을 object(객체) 라고 합니다.

Class 정의 하기

클래스를 선언하기 위해서는 class 키워드를 사용하면 됩니다.
class 이름은 각 단어의 앞글자를 대문자로 사용합니다.
만일 한단어 이상으로 이루어져 있다면 밑줄(underscore) 없이 모든 단어를 다 붙이되 각 단어의 앞글자는 대문자로 해서 단어를 구분하게 됩니다.
예)
ScotchWishkey
SomeReallyLongClassName

예를들어 Car class는 다음처럼 정의 할 수 있습니다.
class가 정의되면, class로 부터 실체화(instantiate) 할 수 있습니다.

다음과 같이 함수를 호출 하듯이 클래스도 호출 하면 됩니다. Car class를 실체(instance)화 한것이 hyundai와 bmw라는 객체(object) 인것입니다.

Class의 attribute(속성)

class에 정의되는 공통 요소들을 전문어로 class의 attribute(성질 혹은 속성) 이라고 합니다.
예를들어
Maker (현대, BMW 등)
모델명 (BMW305, 제네시스 등)
마력 (horse power)

위 3개의 속성들을 class에서 정의하기 위해서는 다음과 같이 "--init--" 함수를 통해서 정의 해주면 됩니다.
(참고로 class 안에서 정의해주는 함수(function)는 function이라고 하지 않고 method 라고 합니다)앞뒤로 밑줄 2개가 있는 메소드들을 special methods라고 합니다.
이들은 특별 취급을 받습니다.
그 중 --init-- 메소드는 class가 실체화 될 때 사용되는 함수 입니다.

예를들어 위 사진에서 이미 init 메소드가 호출 됐습니다.
init라고 메소드 이름을 명확하게 명시하지 않았지만 클래스가 실체화 될때 자동으로 init 메솓드가 호출 됩니다.

정리를 하자면 ----

--init-- 메소드는 클래스가 실체화 될때 자동으로 호출이 된다.
--init-- 메소드의 self 파라미터는 클래스가 실체화된 객체를 넘겨주어야 하며, 파이썬이 자동으로 넘겨준다.
--init-- 메소드의 self 파라미터는 항상 정의되어야 있어야 하며 맨 처음 파라미터로 정의 되어야 한다 (그래야 파이썬이 알아서 넘겨줄 수 있으므로)

이제 --init-- 메소드 안에 코드를 보겠습니다.

Class Method

Method와 attribute(속성)의 차이는 명사와 동사의 차이라고 생각하시면 됩니다.
속성은 해당 객체의 이름 등의 정해진 성질인 반면에 메소드는 move, eat 등 객체가 행할 수 있는 어떠한 action같은 느낌이라고 생각할 수 있습니다.

honk 메소드에도 self 가 들어가 있는걸 볼 수 있습니다.
모든 메소드에는 self 파라미터가 첫번째 파라미터로 들어가야 합니다.

객체에서 메소드를 사용할때는 dot(.) 을 사용하여 객체를 호출 합니다. 즉

<객체>.<메소드>

이를 dot notation 이라고 합니다. (.append 같은것)

--init-- 메소드에서 self 객체에 해당 정보들을 저장해 놓았기 때문에 다음처럼 사용하면 됩니다.

Class는 어디다 쓰나요?

사실 클래스 없이도 코드를 구현할 수 있습니다. 그럼 안쓰면되지
클래스를 사용하면 코드의 구조를 더 효과적으로 구현할 수 있기 때문입니다.

코드를 클래스 위주로 작성하는 것을 object oriented programming(객체 지향 프로그래밍) 이라고 합니다.

Assignment

Class 를 직접 구현해 보겠습니다.
Database 라는 이름의 class를 구현해 주세요.
Database 클래스 내부에 다음의 속성(attribute)들을 선언해주세요.

name : database의 이름
size : 저장할 수 있는 데이터의 max 사이즈. Size를 넘어서는 데이터를 저장할 수 없다.

Database 클래스 내부에 다음의 메소드들을 구현해주세요.

insert
select
update
delete

각 메소드들에 대한 설명은 아래와 같습니다.

Insert
insert 메소드는 self 외에 2개의 parameter를 받습니다.
field와 value 입니다.
Field 는 저장하고자 하는 데이터의 필드명 이고 value는 값입니다.
Field 와 value는 내부적으로 dictionary에 저장되어야 합니다.
insert 메소드는 다음 처럼 호출 할 수 있습니다.

객체 이름이 db 라는 가정하에
db.insert("name", "정우성")

insert 메소드는 특별한 리턴값은 없습니다.
만일 내부 dictionary의 총 사이즈가 database 클래스의 size 속성보다 크면 더이상 새로운 값들을 저장하지 말아야 합니다.

Select
select 메소드는 self 외에 1개의 parameter를 받습니다.
field 입니다.
Field 는 읽고자 하는 데이터의 필드명 입니다.
내부적으로 데이터를 저장하고 있는 dictionary에서 해당 field에 해당하는 키와 연결되어 있는 값을 리턴해주어야 합니다.

예를 들어, 이미 name이라는 필드명으로 "정우성" 이라는 값을 저장했다고 한다면:

객체 이름이 db 라는 가정하에
db.select("name")
"정우성"

이 되어야 합니다.
만일 해당 필드값으로 저정되어 있는 값이 없다면 None 을 리턴해주세요.

Update
Self 외에 2개의 parameter를 받습니다.
field와 value 입니다.
이름 그대로 이미 저장되어 있는 값을 수정하는 메소드 입니다.

객체 이름이 db 라는 가정하에
db.update("name", "아이유")

만일 field값에 해당하는 데이터가 저장되어 있지 않으면 아무것도 하지 않습니다.
그리고 특별한 리턴 값은 없습니다.

Delete
delete 메소드는 self 외에 1개의 parameter를 받습니다.
field 입니다.
Field 는 지우고자 하는 데이터의 필드명 입니다.

객체 이름이 db 라는 가정하에
db.delete("name")

만일 field값에 해당하는 데이터가 저장되어 있지 않으면 아무것도 하지 않습니다.
그리고 특별한 리턴 값은 없습니다.

삐빅 👷🏼‍♂️ 🚧 ⛏ 삽질 구간입니다.

내가 쓴 코드와 정답 모델코드를 보자
마이 코드:

class Database:
  datagroup= {}

  def __init__(self, name, size):
    self.name = name
    self.size = size

  def insert(self, field, value):
    self.field = field
    self.value = value
    if len(self.datagroup) < self.size:
      if field in self.datagroup:
          self.datagroup[field] = self.datagroup[field] + value
      else:
        self.datagroup[field] = value
    
  def select(self,field):
    if field in self.datagroup:
      return self.datagroup[field]
    else:
      return None  
    
  def update(self,field,value):
    if field in self.datagroup:
      self.datagroup[field]=value
    else:
      return None
    
  def delete(self,field):
    if field in self.datagroup:
      self.datagroup.pop(field)
    else:
      return None

정답 모델코드:

class Database:
  def __init__(self, name, size):
    self.name = name
    self.size = size
    self.db   = { }
    
  def insert(self, field, value):
    if len(self.db) < self.size:
      self.db[field] = value

  def select(self, field):
    if field in self.db:
      return self.db[field]
    else:
      return None
      
  def update(self, field, value):
    if field in self.db:
      self.db[field] = value
  
  def delete(self, field):
    if field in self.db:
      del self.db[field]

다른 점은 빈 딕셔너리를 def --init--(self, name, size): 안에 넣었다.

def insert 아래에
self.field = field
self.value = value 이것도 필요 없었나 보다

def delete 아래에
나는 self.datagroup.pop(field) 라고 했는데
모델 정답은

 def delete(self, field):
    if field in self.db:
      del self.db[field]

데코레이터도 그렇고, 클래스도 아직 확실히 이해 못했다. 어영부영 되긴했는데, 확실히 이해하지 못했다. pass 하기 위해 에러를 고쳤을 뿐
여기서 고민인게, 일단 넘어가고, 나중에 실제로 내가 사용해보면서 이해력을 올릴 것인지, 지금 진도를 멈추고 더 복습하고 시간와 노력을 더 쏟아서 이해를 하고 갈것인가.

Modules & Packages

모듈은 변수나 함수 그리고 클래스 등을 모아놓은 파일입니다.

  1. 다른 파일에서 재사용이 가능하게 하고
  2. 전체 코드가 한 파일에 넣기에는 너무 커졌을때 여러 파일로 나누어서 정리를 하기 위해서. 존재합니다.

For example, List의 총 요소 개수를 알고 싶으면 len 함수를 사용하면 되는걸 이미 보았습니다. 파이썬에서 이미 모듈로 구현해놓았음으로 en 함수를 직접 구현하지않고 그냥 가져다 쓰면 됩니다.

이렇게 모듈은 다른 사람들이 이미 만들어놓은 모듈을 사용할 수도 있고 우리가 직접 만들어서 사용할 수도 있습니다.

Module 만들기

파일을 만든후 그 안에 재사용 하고 싶은 함수나 클래스 혹은 변수등을 구현하면 됩니다.
.py 제회하고 모듈이름만 쓰기!
아래 사진 처럼 원하는 모듈의 변수/함수/클래스를 사용할 수 있습니다.my_module 모듈의 my_module_func함수를 호출하고 싶을때!
이 외 다른 예들
이름의 공간 혹은 영역을 알려주기 때문에 이러한 구조를 "name space" 라고 합니다.

정리:
1. 원하는 모듈을 import 키워드를 사용하여 불러온다. 그럼으로 파이썬이 모듈을 해당 파일과 연결시키게 된다.

2. 그 후 연결된 모듈에서 원하는 변수/함수/클래스 를 사용하면 된다. 다만 해당 모듈 이름과 연결해서 호출을 해줘야 파이썬이 어느 파일에서 해당 변수/함수/클래스 를 찾을 수 있는지 알 수 있게된다.

Alternative ways to import modules

from import 키워드를 사용해서 모듈을 불러들일수 있습니다.

from <모듈 이름> import <함수/변수/클래스1>, <함수/변수/클래스2>

예를 들어, my_module 모듈에서 my_module_func 함수와 my_module_var 변수를 import 하고자 한다면 다음처럼 할 수 있습니다.

from import 키워드를 사용하여 모듈을 불러들이는 경우 모듈 이름을 붙이지 않고 곧바로 원하는 함수나 변수 그리고 클래스를 호출할 수 있습니다.

모듈에서 사용하는 것이 명확할때 from import 를 사용하면 편리합니다.

별표( )를 사용하면 해당 모듈의 모든 요소가 곧바로 import 됩니다 하지만 local scope를 가지고 있는 다른 변수/함수/클래스들과 이름 출돌이 날 수 있는데, 이럴 경우 알기가 쉽지 않다. 별표()는 권장하지 않음.

Import As

별표(*) 와 같은 이유로 이름충돌이 날 수 있기 때문에 Import As 써서 새로운 이름을 주어서 사용할 수 있습니다.module 이름도 as 를 사용하여 새로운 이름을 줄 수 있습니다.

Packages

module과 같은 개념이지만, 차이점은,
module보다 더 크고 복잡한 코드라는 점입니다.
어떠한 module들은 코드의 양이 너무 커서 한 파일에 다 넣기에 비효율적이라서 여러 파일에 나누어서 코드를 관리하는것이 효과적일 것입니다.
이렇게 여러 파일에 나누어져 있는 코드들도 다른 곳에서 하나의 module로 불러와서 사용할 수 있도록 해주는것이 package 입니다.

파일들로 이루어져 있는 디렉토리(directory)가 하나의 package 가 되며 디렉토리 이름 = 팩키지 이름

Package는 일반 모듈 처럼 import 하여 사용할 수 있습니다. 다만 차이점은 클래스 객체를 사용할때 처럼 "dot notation" 으로 해당 package의 원하는 모듈을 import 하면 됩니다.

Package Initialization

가끔은 package가 import 될때 초기 설정을 해줘야 할때가 있는데, --init--.py 파일을 통해 package 초기 설정을 가능하게 해줍니다.
Package 안에 --init--.py 파일이 있으면 package가 import 될때 --init--.py 파일의 코드들이 자동으로 실행되고 아래사항 시행:

= Import 할때 경로의 총 길이 줄여주기
= Package에서 import 할 수 있는 변수/함수/클래스 제한하기
= 그 외 package가 import될때 꼭 먼저 실행되어야 하는 코드들

For example (import할때 경로의 총 길이 줄여주기),
pkg에서 mod1의 func2 라는 함수를 import
func2 함수를 호출 할때마다 매번 모든 경로를 다 타입해줘야 하기때문에 번거롭기 때문에
--init--.py 파일에 먼저 한번 import 해주면됩니다.

--init.py-- 파일을 사용해서 import 할 수 있는 변수/함수/클래스를 제한할 수 있습니다.
내부적으로만 사용되어야 하는 함수가 package 외부에서 import되어 사용되는 것을 막기 위해서는 --all-- 변수를 지정해 줄 수 있습니다.

package를 통해 import 될 수 있는 요소들은 모두 --all-- 변수를 통해 정의 됩니다.
그리고 --all-- 변수의 default 값은 모든 함수/변수/클래스 입니다.
그러므로 --all-- 변수를 따로 정의해줌으로 import 될 수 있는 요소들을 제한할 수 있는 것입니다.
--all-- 변수는 string 값의 요소를 가지고 있는 list 입니다 (list of strings).
그러므로 import 되길 원하는 요소들을 string으로 list에 선언해주면 됩니다.

main.py
from pkg import *
func2()
func3()
func4() ## <== Error. func4 함수는 --all-- 에 정의되지 않았으므로 import 될 수 없음.
func2 와 func3만 정의했으므로

다른 사람의 package 사용하기

터미널 열고 pip install Django 일단 넘어갑니다.

과제 :

my_module 파이썬 파일

def my_func():
  print("importing test")
  
my_variable = 1

main.py 파이썬 파일

from my_module import my_func as f1
from my_module import my_variable
f1()
print(int(my_variable))
profile
🇰🇷🇺🇸 #Back-End Engineer

0개의 댓글