파이썬 백엔드 12일차 정보은닉

박재정·2025년 1월 21일

학습정보

목록 보기
12/29

1. 정보은닉이란?

정보은닉의 개념
변수에 값을 다이렉트로 못넣게 만드는 것 = 변수를 최대한 노출 시키지 않는것
C++ JAVA 등은 접근 제한자를 이용해 처리하는데 파이썬은 접근 제한자가 없다.
그래서 instance 변수 이름을 __ 언더바 2개를 붙여 정보 은닉 처리함.

class Person:
    def __init__(self, name, age):
        self.__name = name #변수명에 언더바 설정 
        self.__age = age

    def add_age(self, age):
        if age < 0:
            print('나이는 0보다 커야합니다. 나이 정보 오류')
        else: 
            self.a__ge += age 

    def __str__(self):
        return f'이름은 {self.__name}, 나이는 {self.__age}'
    
p = Person('홍길동', 20)

p.add_age(1)
print(p)

p.add_age(-30)
print(p)

p.__age -= 30 #파이썬에서는 직접 값을 넣어버림 그럼 나이가 -9가 되버리는 오류가 생김 
print(p)

2. 아래의 소스코드에서 에러가 나는 이유와 age 50으로 바꾸어 보시오.

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    # if 문의 해당 함수에서 0이 들어 가지 않도록 막음
    def add_age(self,age):
        if age < 0:
            print('나이는 0보다 커야 합니다. 나이 정보 오류')
        else:
            self.__age += age

    def __str__(self):
        return f'이름은 {self.__name}, 나이는 {self.__age}'


p = Person('홍길동', 20) #객체 생성 
p.add_age(30) # 기존 나이 (20)에 30을 더함
print(p) 
#출력 이름은 홍길동, 나이는 50 

Python에서 __ 언더바 2개로 시작하는 변수는 이름 맹글링(Name Mangling) 규칙에 따라
외부에서 직접 접근할 수 없도록 처리

3. 데코레이터란?

Python에서 Decorator는 기존 함수를 수정하지 않고 그 기능을 확장하는 방법을 제공합니다. 즉, 기존 함수 위에 '장식'을 추가하는 것이라 생각하면 됩니다. Decorator는 '@' 기호를 사용하여 정의되며, 함수나 메소드 앞에 위치합니다.

# decorator를 정의하는 함수. 인자로 함수를 받습니다.
def my_decorator(func):
    def wrapper():
        print("함수 실행 전 무언가를 합니다..")
        func() # 인자로 받은 함수를 실행합니다.
        print("함수 실행 후 무언가를 합니다.")
    return wrapper

# @ + decorator 함수명을 앞에 쓰는 사용할 수 있습니다.
@my_decorator
def say_hello():
    print("Hello!")
    
say_hello()

위 예제에서, my_decorator는 decorator이며 say_hello 함수 앞에 '@' 기호와 함께 위치하고 있습니다. 이를 통해 say_hello 함수는 my_decorator에 인자로 넘겨되며, 함수가 호출 전후에 decorator 내에 정의된 추가 기능이 실행됩니다. 위에서는 func 전후에 print를 실행하겠군요.

위 코드를 한 번 실행해 보겠습니다.

함수 실행 전 무언가를 합니다..
Hello!
함수 실행 후 무언가를 합니다. 

Decorator 사용 시 장단점

코드의 재사용성을 높일 수 있다.
Decorator의 가장 큰 장점은 코드의 재사용성을 높이는 것입니다. 특정 로직을 공통적으로 사용해야 하는 여러 함수에 대해, 이 로직을 decorator로 구현하면 각 함수에 '@' 기호와 함께 decorator를 추가하기만 하면 됩니다. 중복 코드를 최소화하고 코드의 가독성을 높일 수 있습니다.

무분별한 Decorator의 사용은 코드의 복잡도를 높일 수 있다.
Decorator를 사용할 때는 주의해야 할 점도 있습니다. 무분별한 Decorator의 사용은 코드의 복잡도를 높일 수 있습니다. 특히, 다수의 Decorator가 중첩되어 사용될 경우 코드 해석이 어려워지며, 이는 버그 발생의 원인이 될 수 있습니다. 따라서, Decorator는 필요한 경우에만 적절히 사용하는 것이 좋습니다.

4. 아래와 같이 출력이 나오도록 데코레이션 함수를 만들어 보시오.

def smile():
print('^_^')

def confused():
print('@_@')

def deco(fun):

def wrapper():
    print('emotion!')
    fun()
    print('emotion!')

return wrapper

@deco 
def smile():
	print('^_^')
smile()

출력
emotion!
^_^
emotion!

5. 아래와 같이 출력이 나오도록 adder_deco 를 만들어 보시오.

@adder_deco
def adder1(n1,n2):
    return n1 + n2

@adder_deco
def adder2(n1,n2 ,n3):
    return n1 + n2 + n3

@adder_deco
def adder3(n1,n2 ,n3,n4):
    return n1 + n2 + n3 + n4


adder1(3,5) # 8
adder2(1,2,3) # 6
adder3(1,2,3,4) # 6

def adder_deco(func):  
    # 데코레이터 함수 정의 특정 동작을 여러함수에 반복적으로 사용할때 유용
    def wrapper(*args): #가변 인자처리
        result = func(*args)  # 원래 함수 호출
        print(result)  # 결과를 출력
        return result  # 결과 반환
    return wrapper

@adder_deco
def adder1(n1, n2):
    return n1 + n2

@adder_deco
def adder2(n1, n2, n3):
    return n1 + n2 + n3

@adder_deco
def adder3(n1, n2, n3, n4):
    return n1 + n2 + n3 + n4

# 함수 호출 및 출력
adder1(3, 5)  # 출력: 8
adder2(1, 2, 3)  # 출력: 6
adder3(1, 2, 3, 4)  # 출력: 10

6. 아래를 예를 들어 설명하시오.

1. 클래스 변수

클래스 변수는 클래스 자체에 속한 변수로, 모든 인스턴스에서 공유됩니다.
인스턴스가 아니라 클래스 자체에서 선언되며, 모든 인스턴스가 동일한 값을 참조합니다.

  • 특징
    클래스 변수는 메모리 활용성을 높입니다. 인스턴스별로 독립적인 변수를 가지지 않고 공유
    인스턴스에서도 접근할 수 있지만, 주로 클래스 이름을 통해 접근합니다.

    #클래스 변수

class Account:
num_accounts = 0
def init(self, name):
self.name = name
Account.num_accounts += 1
def del(self):
Account.num_accounts -= 1

Account 클래스에는 num_accounts와 self.name이라는 두 종류의 변수가 있습니다. num_accounts처럼 클래스 내부에 선언된 변수를 클래스 변수라고 하며, self.name과 같이 self가 붙어 있는 변수를 인스턴스 변수라고 합니다. 클래스 변수는 Account 클래스의 네임스페이스에 위치하며, self.name과 같은 인스턴스 변수는 인스턴스의 네임스페이스에 위치하게 됩니다.

그렇다면 언제 클래스 변수를 사용해야 하고 언제 인스턴스 변수를 사용해야 할까요? 이에 대한 답은 간단한 코드를 작성해보면서 천천히 설명해 드리겠습니다. 여러분이 은행에 가서 계좌를 개설하면 새로운 계좌가 하나 개설됩니다. 이러한 상황을 파이썬으로 표현하면 다음과 같이 Account 클래스의 인스턴스를 생성하는 것에 해당합니다.

```python
>>> kim = Account("kim")
>>> lee = Account("lee")
>>>

생성된 kim과 lee 인스턴스에 계좌 소유자 정보가 제대로 저장돼 있는지 확인해 봅시다. 각 계좌에 대한 소유자 정보는 인스턴스 변수인 name이 바인딩하고 있습니다.

>>> kim.name
'kim'
>>> lee.name
'lee'
>>>

그렇다면 지금까지 은행에서 개설된 계좌는 총 몇 개일까요? 네, 정답은 'kim'과 'lee'에게 하나씩 개설됐기 때문에 두 개겠죠? kim 인스턴스나 lee 인스턴스를 통해 num_accounts라는 이름에 접근하면 총계좌개설개수가2개로나오는것을알수있습니다.

>>> kim.num_accounts
2
>>> lee.num_accounts
2
>>>

물론 지금까지 공부를 잘 해오신 분들은 kim.num_accounts에서 먼저 인스턴스의 네임스페이스에서 num_accounts를 찾았지만 해당 이름이 없어서 클래스의 네임스페이스로 이동한 후 다시 해당 이름을 찾았고 그 값이 반환된 것임을 아실 것입니다.

이처럼 여러 인스턴스 간에 서로 공유해야 하는 값은 클래스 변수를 통해 바인딩해야 합니다. 왜냐하면 파이썬은 인스턴스의 네임스페이스에 없는 이름은 클래스의 네임스페이스에서 찾아보기 때문에 이러한 특성을 이용하면 클래스 변수가 모든 인스턴스에 공유될 수 있기 때문입니다. 참고로 클래스 변수에 접근할 때 아래와 같이 클래스 이름을 사용할 수도 있습니다.

>>> Account.num_accounts
2
>>>

지금까지 작성한 코드에서 클래스 변수와 인스턴스 변수를 그림으로 나타내면 그림 6.15와 같습니다. 앞으로 클래스 변수와 인스턴스 변수가 헛갈릴 때마다 이 그림을 기억하기 바랍니다.

2.클래스 함수

3.스택틱 함수

#클래스 메소드 = 클래스 변수 컨트롤 하기위해

class Simple:
count = 0 # Private class variable

def init(self):
    self.count2 = 0

@classmethod
def increment(cls):
    cls.count += 1
    return cls.count

@classmethod
def get_count(cls):
    return cls.count

Simple._Simplecount = 42

s = Simple()
s.dict['_Simple__count'] = 100

print(s.increment())
print(s.increment())
print(s.increment())
print(s.get_count())

print(Simple.increment())
print(Simple.increment())
print(Simple.increment())
print(Simple.get_count())

  1. 아래가 에러가 나는 이유를 설명하시오.
    class Calculator:

    @staticmethod # 스태틱 메소드 = 정적 메소드 = 간단한 함수들 = 객체와 상관없는 함수들
    def add(n1, n2):
        return n1 + n2
    
    def add2(self, n1,n2): #인스턴스 메소드
        return n1 + n2
    
    @staticmethod
    def mul(n1, n2):
        return n1 * n2
        

cal = Calculator()
print(Calculator.add2(10,20))

  1. 아래가 에러가 나는 이유와 수정을 하시오.
    class Cirle2:
    PI = 3.12419
    def get_area(cls, radius):
        return cls.PI * radius * radius
    =============================
    print(Cirle2.PI)

result = Cirle2.get_area(5)
print(result)

  1. 프로퍼티 함수에 대하여 설명하시오.(예습)

3줄 요약:
1.정보은닉 이란 변수를 최대한 노출 시키지 않도록 하는것이다.
2.파이썬에서 객체의 변수와 값은는 dict 딕셔너리 객체로 따로 관리 한다.
3. 변수 이름은 dict['_클래스명변수이름'] 으로 접근 가능하다.

3줄요약 두번째:
4. 데코레이터는 함수호출이며 함수의 파라미터로 콜백함수를 넘긴다.
5. 클래스 변수는 공용변수 이며, 각 객체들이 공유 하는 변수이다.
6. 프로퍼티는 쪼매 어렵다.

profile
파이썬, SQL 개발

0개의 댓글