[파이썬]private 변수(private 네임 맹글링)

파이썬은 자바와 다르게 접근제어자가 없다. 사실 클래스 정의 외부에서 접근할 수 있도록 만드는 방법이 있긴한데 접근제어자처럼 완벽하게 통제할 수는 없다.

1
2
3
4
5
6
7
8
class Duck():

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

a = Duck('son')
print(a.__name)
# 'Duck' object has no attribute '__name'

더블 언더스코어를 붙여서 변수를 만들면 된다. 이때에 __name을 직접 접근할 수 없다!! 완벽한 private은 아니지만 외부 코드에서 발견할 수 없도록 이름을 맹글링(뭉게기 - mangling) 했다고 보면 된다. 완벽한 private 변수라고 말할 수 없는 이유는 네임 스페이스를 확인해보면 알 수 있을 것이다.

1
2
3
print(dir(a))
# a._Duck__name
# 기타 등등

아예 접근 불가능한 것이 아니라, 접근할 수 있는 변수의 이름이 달라지는 것이라고 이해할 수 있다!!


[참고]
패스트 캠퍼스 강의

Share

[파이썬]클래스의 getter 메소드와 setter 메소드(+ private 속성)

1
2
3
4
5
6
7
class Student:

def __init__(self, name, age):
self._name = name
self._age = age

stu1 = Student('son', 20)

위와 같이 학생 클래스가 있을때 학생의 나이에 조건이 있어야 된다면 다음과 같은 코드가 필요할 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student:

def __init__(self, name, age):
self._name = name
if age <= 10:
raise ValueError('11살 이상의 학생만 가능합니다')
self._age = age

stu1 = Student('son', 20)
stu1 = Student('son', 8) # ValueError 발생

# __init__함수의 영향을 받지 않으므로 ValueError가 발생하지 않는다
stu1._age = 8

문제 될것 없어보이는 코드지만 객체를 생성하고 나서 값을 변경하게 된다면 더 이상 __init__ 함수의 영향을 받지 않기 때문에 문제가 될 수 있다.

getter 메소드와 setter 메소드를 구현해서 문제를 해결해보자.

getter와 setter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Student:

def __init__(self, name, age):
self.__name = name
if age <= 10:
raise ValueError('11살 이상의 학생만 가능합니다')
self.__age = age

@property
def age(self):
return self.__age

@age.setter
def age(self, age):
if age <= 10:
raise ValueError('11살 이상의 학생만 가능합니다')
self.__age = age

값을 읽기 위해 getter 메소드를, 값을 쓰기 위해 setter를 사용하면 된다.

getter를 만들기 위해 @property 데코레이터를 사용한다. 함수 이름은 변수명과 동일하게 작성하는 관례가 있다. 그리고 setter를 만들기 위해 @변수.setter를 사용한다. 마찬가지로 변수명과 동일한 함수명을 추천한다.

이렇게 클래스 내부의 변수에 __(더블 언더스코어)를 덧붙여서 private 속성을 만들고 값이 필요할때 setter 메소드와 getter 메소드를 사용하는 것이 보편적인 객체지향 프로그래밍 방법 중 하나라고 한다.

@property 데코레이터를 통해 프로퍼티를 만들어 보았는데, 사실 수동으로 만드는 방법도 있다.

수동으로 프로퍼티 만들기

1
2
3
4
5
6
7
8
9
10
11
12
13
class Student:

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

def get_age(self):
return self.__age

def set_age(self, v):
self.__age = v

age = property(get_age, set_age)

age에 대한 getter와 setter 메소드를 만들고 마지막에 age라는 이름으로 프로퍼티에 등록해주었다. 이런 방식의 특징은 get_age 메소드와 set_age 메소드를 직접 사용할 수 있다는 것이다.

1
2
3
4
5
6
a = Student('son', 21)
a.get_age() # 21

a.set_age(12)
a.get_age() # 12
a.age # 12

get_age와 set_age가 네임 스페이스에 존재하는지 확인해보자

1
2
3
4
5
dir(a)

# 'age',
# 'get_age',
# 'set_age'

만약 데코레이터를 통해 프로퍼티를 작성했다면 get_age와 set_age 함수가 없을 것이다.


[참고]
패스트캠퍼스 강의

Share

[파이썬]고차함수

파이썬에서 모든 것은 객체다. 라는 유명한 설명이 있다. 파이썬은 일급 객체를 지원하는 언어이며 아래와 같은 특징을 갖는다.

  • 런타임에서 초기화 가능
  • 변수 등에 할당 가능
  • 함수의 인자로 전달 가능
  • 함수의 결과값으로 사용 가능

위와 같은 일급 객체의 특징을 가진 함수가 있다면 그것을 고차함수(Higher Order Function)이라고 부를 수 있으며 좀 더 특징을 다듬어 보자면

  • 다른 함수를 생산/소비 하는 함수
  • 다른 함수를 인자로 받거나, 결과로 함수를 반환하는 함수

라고 할 수 있다.

정말 모든 것은 객체일까?

간단한 함수를 만들고 타입을 확인하자.

1
2
3
4
5
6
7
8
def func():
pass

class A:
pass

print(type(func), type(A))
# <class 'function'> <class 'type'>

출력된 값을 보면 둘 다 객체라는 것을 알 수 있다.

고차함수 예시

파이썬 빌트인 함수 중에서 대표적인 고차함수로 map이 있다. map 함수는 인자로서 함수순회가능한 객체를 받는다.

1
2
3
4
number_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = list(map(lambda x: x ** 2, number_list))
print(result)
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

[참고]
AskDjango
https://itholic.github.io/etc-higer-order-function/

Share