일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 |
- 국비지원
- getElementsByClassName
- javascript
- 가변객체 기본값
- 코딩입문자
- folium
- Bootcamp
- 내일배움카드
- 매개변수와 인수
- 코드스테이츠
- TIL
- default_value
- 함수화
- PYTHON
- 비전공자개발자
- 정부지원
- 스파르타코딩클럽
- Dom
- querySelectorAll
- 부트캠프
- 선택자
- 코딩프로젝트
- array
- 프론트엔드
- 자바스크립트
- 개발일지
- 설명회
- 내일배움단
- frontend
- 파이썬
- Today
- Total
끄적 코딩
[파이썬] 함수의 매개변수 선택 입력하려면 : using mutable objects as default parameter value, 인자의 기본 값, 선택적 인수 본문
[파이썬] 함수의 매개변수 선택 입력하려면 : using mutable objects as default parameter value, 인자의 기본 값, 선택적 인수
몽.글렛 2022. 3. 30. 00:21
메이킹 프로젝트 <집근처 전시회>의 함수처리에 대한 문제 해결이다.
같은 로직의 A,B
A의 경우 마지막 조건문에 따라 결과가 달라지는데, 이 조건에 사용할 인자(매개변수)를 하나 더 필요로 한다.
즉, A에는 func(a,b,c) B에는 func(a,b)를 사용해야될 경우이다.
이 경우, 함수를 선언할 때 인자 c의 기본값을 설정하면 해결된다.
def func(a, b, c="내가 설정한 기본값"):
함수 실행부
기본값을 설정하면 a,b만 값을 받아서 사용하고, c는 초기 설정값으로 함수를 실행시킨다.
입력 순서 주의사항!
"Non-default argument follows default argument"
매개변수가 여러개일 때, 필수로 입력해야하는 매개변수를 기본값 변수보다 먼저 사용해야한다.
가변객체일 경우 주의사항!
list, dict, set 과 같은 변하는 객체의 경우 매개변수 기본값을 None으로 작성 후, 함수 내부에서 다시 정의한다.
def func(c = None): if c is None: c = [] 함수 실행부
<참고> 발생하는 문제 자세히 보기 : Using mutable objects as default argument values in python
Programming FAQ — Python 3.10.4 documentation
Self is merely a conventional name for the first argument of a method. A method defined as meth(self, a, b, c) should be called as x.meth(a, b, c) for some instance x of the class in which the definition occurs; the called method will think it is called as
docs.python.org
구글링 키워드 : '선택적 인수' , '인자의 기본값', 'default parameter value'
- 매개변수(Parameters) : 함수 선언시 () 속에 사용되는 변수
- 인자(Arguments) : 함수 호출시 () 속에 사용되는 변수
def sum('Parameters') :
sum("Arguments")
- 가변객체(mutable) tuple, int, float, bool, str 등
- 불변객체(immutable) list, dict, set 등

파란색 부분이 같은 부분이다. 사용전(왼쪽)과 사용후(오른쪽)의 길이가 반이상 줄었다. 더군다나 보라색은 한 화면으로는 다 담기지 않을 정도의 엄청난 차이를 보여준다. 이전 코드와 비교하면 훨씬 깔끔해졌다.
<case 1>
비회원 : 일반 마커 생성
회원 : 북마크 데이터가 있는 경우 북마크용 마커 생성 + 그 외 일반 마커 생성
<case 2>
한장소에 1가지 전시
한장소에 n가지 전시
비회원인 경우는 조건 없이 <case 2>에 따라 다른 for문이 실행된다. 하지만, 회원일 경우는 비회원일 경우와 같은 for문이 실행되지만 북마크라는 조건(userbm_coordinate)에 따라 마커 모양을 다르게 생성 된다.
#회원은 북마크 마커와 일반 마커
if((get_markdata['lt'], get_markdata['lg']) in userbm_coordinate):
folium.Marker(location=[get_markdata['lt'], get_markdata['lg']], popup=popup_html, tooltip=get_markdata['p'], icon=folium.Icon(color='darkblue', icon='bookmark')).add_to(map)
else:
folium.Marker(location=[get_markdata['lt'], get_markdata['lg']], popup=popup_html, tooltip=get_markdata['p'], icon=folium.Icon(color='blue')).add_to(map)
#비회원은 일반 마커
folium.Marker(location=[overlap_markdata['lt'],overlap_markdata['lg']], popup=popup_html, tooltip=overlap_markdata['p'], icon=folium.Icon(color='blue')).add_to(map)
1차로 함수화할 때는 이 방법을 몰라서 위의 조건문 직전에 리턴값을 반환하는 함수를 사용했었다.
folium.Marker(리턴값 사용하는 부분).add_to(map)
#함수 : 전시 폴리움 마커 인자 생성(1종류 전시/ n종류 전시)
def make_args_onexhibit(one_data):
get_markdata = pick_value(one_data)
summary_info = folium.Html(f"""<div class="map_inner">
{p_tag(get_markdata['t'],get_markdata['pr'],get_markdata['lt'],get_markdata['lg'],get_markdata['p'])}
</div>""", script=True)
popup_html = folium.Popup(summary_info, max_width=500)
marker_args= {
"latitude" : get_markdata['lt'],
"longitude" : get_markdata['lg'],
"popup" : popup_html,
"tooltip" : get_markdata['p']
}
return marker_args
def make_args_multiexhibit(overlap_datas):
popup_msg = []
for overlap_one in overlap_datas:
overlap_markdata = pick_value(overlap_one)
target_info = f"""{p_tag(overlap_markdata['t'],overlap_markdata['pr'],overlap_markdata['lt'],overlap_markdata['lg'],overlap_markdata['p'])}"""
popup_msg.append(target_info)
popup_msg = ''.join(popup_msg)
full_text = f"""<div class="map_inner">{popup_msg}</div>"""
summary_info = folium.Html(f"""{full_text}""", script=True)
popup_html = folium.Popup(summary_info, max_width=500)
marker_args= {
"latitude" : overlap_markdata['lt'],
"longitude" : overlap_markdata['lg'],
"popup" : popup_html,
"tooltip" : overlap_markdata['p']
}
return marker_args
# 지도 검색 API
@app.route('/setposition', methods=['POST'])
def set_position():
#지역 좌표 추출
address1_recieve = request.form['address1_give'] # "광주시"
address2_recieve = request.form['address2_give'] # "북구"
set_location = db.region_info.find_one({'address_class1': address1_recieve, 'address_class2': address2_recieve})
#지도 생성
map = make_map(set_location['latitude'], set_location['longitude'])
#DB데이터 추출
total_data = list(db.exhibition_info.find({}, {'_id': False}))
#DB데이터 중복 좌표 모음
overlap_coordSP = overlap_list(total_data)
# 회원 마크 표시
if(request.form['key_give'] != ''):
key_receive = request.form['key_give']
# 회원 북마크
userbm_coordinate = make_bmcoordinate(key_receive)
# 한 장소에 1종류 전시(회원 마크 표시)
for data in total_data:
if "latitude" in data:
if((data['latitude'], data['longitude']) not in overlap_coordSP):
one_markdata_login = make_args_onexhibit(data)
if((one_markdata_login['latitude'], one_markdata_login['longitude']) not in userbm_coordinate):
folium.Marker(location=[one_markdata_login['latitude'], one_markdata_login['longitude']], popup=one_markdata_login['popup'], tooltip=one_markdata_login['tooltip'], icon=folium.Icon(color='blue')).add_to(map)
else:
folium.Marker(location=[one_markdata_login['latitude'], one_markdata_login['longitude']], popup=one_markdata_login['popup'], tooltip=one_markdata_login['tooltip'], icon=folium.Icon(color='darkblue', icon='bookmark')).add_to(map)
# 한 장소에 n종류 전시(회원 마크 표시)
for coordinate in overlap_coordSP:
overlap_datas = list(db.exhibition_info.find(
{'latitude': coordinate[0], 'longitude': coordinate[1]}, {'_id': False}))
multi_markdata_login = make_args_multiexhibit(overlap_datas)
if((multi_markdata_login['latitude'], multi_markdata_login['longitude']) not in userbm_coordinate):
folium.Marker(location=[multi_markdata_login['latitude'], multi_markdata_login['longitude']], popup=multi_markdata_login['popup'], tooltip=multi_markdata_login['tooltip'], icon=folium.Icon(color='blue')).add_to(map)
else:
folium.Marker(location=[multi_markdata_login['latitude'], multi_markdata_login['longitude']], popup=multi_markdata_login['popup'], tooltip=multi_markdata_login['tooltip'], icon=folium.Icon(color='darkblue', icon='bookmark')).add_to(map)
# 비회원 마크 표시
else:
# 한 장소에 1종류 전시(비회원 마크 표시)
for data in total_data:
if "latitude" in data:
if((data['latitude'], data['longitude']) not in overlap_coordSP):
one_markdata = make_args_onexhibit(data)
folium.Marker(location=[one_markdata['latitude'], one_markdata['longitude']], popup=one_markdata['popup'], tooltip=one_markdata['tooltip'], icon=folium.Icon(color='blue')).add_to(map)
# 한 장소에 n종류 전시(비회원 마크 표시)
for coordinate in overlap_coordSP:
overlap_datas = list(db.exhibition_info.find(
{'latitude': coordinate[0], 'longitude': coordinate[1]}, {'_id': False}))
multi_markdata = make_args_multiexhibit(overlap_datas)
folium.Marker(location=[multi_markdata['latitude'], multi_markdata['longitude']], popup=multi_markdata['popup'], tooltip=multi_markdata['tooltip'], icon=folium.Icon(color='blue')).add_to(map)
map.save(r'/home/ubuntu/MakingChallenge11/exhibi-dev/templates/position_map.html')
return jsonify({'result': 'success'})
함수 작업을 했는데도 이렇게나 길고 깔끔하지 못했다. 억지고 리턴값을 만들어서 사용하다보니 folium.Marker(리턴값 사용하는 부분).add_to(map) 부분도 복잡해지고, 반복되는 코드는 여전히 남아있었다. 게다가 지도 관련 API가 3개나 반복되었다. 유지보수하려면 크나큰 손실이었다. 생각보다 많이 거슬렸나보다... 꿈에서 나올 정도였다.
이 문제는 함수의 파라미터값 하나만 처리하면 되는 문제였다. 어디선가 함수 선언시, ( )안의 변수 = False 같은 형태를 본적이 있었는데, 내 코드의 경우에는 적용이 안되었다. def func(변수 = False 혹은 True):
여러가지 방법으로 구글링을 하다가 '선택적 인수'라는 키워드를 발견했다.
북마크 관련한 변수 userbm_coordinate는 리스트 형태의 값으로 표현되어야 함으로 빈 리스트로 초기 선언을 했었다. 하지만, 파이썬에서 매개변수를 None으로 선언 후 함수 내부에서 재정의하는 방식을 권고한다. 나의 경우 빈 리스트로 선언해도 오류가 발생하지 않았지만, 함수를 여러번 사용시 가변객체 부분이 의도하지 않은 값으로 나타날 수 있기 때문에 파이썬 공식 문서에서 권하는 방법으로 함수 내부에서 if userbm_coordinate is None: 을 사용하여 빈 리스트로 변경하였다.
함수 속에 if 조건문까지 포함하여 리턴값 없이 마커를 생성하는 함수로 표현했다. 리턴값을 사용하려고 변수를 만들 필요없이, 함수만으로 결과값을 생성할 수 있었다.
#함수: 전시 폴리움 마커(1종류 전시)
def mark_onexhibit(map, total_data,overlap_coords, userbm_coordinate = None):
#가변객체일때 매개변수 기본값 설정
if userbm_coordinate is None:
userbm_coordinate = []
for data in total_data:
if "latitude" in data:
if((data['latitude'], data['longitude']) not in overlap_coords):
get_markdata = pick_value(data)
summary_info = folium.Html(f"""<div class="map_inner">
{p_tag(get_markdata['t'],get_markdata['pr'],get_markdata['lt'],get_markdata['lg'],get_markdata['p'])}
</div>""", script=True)
popup_html = folium.Popup(summary_info, max_width=500)
if((get_markdata['lt'], get_markdata['lg']) in userbm_coordinate):
folium.Marker(location=[get_markdata['lt'], get_markdata['lg']], popup=popup_html, tooltip=get_markdata['p'], icon=folium.Icon(color='darkblue', icon='bookmark')).add_to(map)
else:
folium.Marker(location=[get_markdata['lt'], get_markdata['lg']], popup=popup_html, tooltip=get_markdata['p'], icon=folium.Icon(color='blue')).add_to(map)
#함수: 전시 폴리움 마커(n종류 전시)
def mark_multiexhibit(map, overlap_coords, userbm_coordinate = None):
#가변객체일때 매개변수 기본값 설정
if userbm_coordinate is None:
userbm_coordinate = []
for coordinate in overlap_coords:
overlap_datas = list(db.exhibition_info.find(
{'latitude': coordinate[0], 'longitude': coordinate[1]}, {'_id': False}))
popup_msg = []
for overlap_one in overlap_datas:
overlap_markdata = pick_value(overlap_one)
target_info = f"""{p_tag(overlap_markdata['t'],overlap_markdata['pr'],overlap_markdata['lt'],overlap_markdata['lg'],overlap_markdata['p'])}"""
popup_msg.append(target_info)
popup_msg = ''.join(popup_msg)
full_text = f"""<div class="map_inner">{popup_msg}</div>"""
summary_info = folium.Html(f"""{full_text}""", script=True)
popup_html = folium.Popup(summary_info, max_width=500)
if((overlap_markdata['lt'],overlap_markdata['lg']) in userbm_coordinate):
folium.Marker(location=[overlap_markdata['lt'],overlap_markdata['lg']], popup=popup_html, tooltip=overlap_markdata['p'], icon=folium.Icon(color='darkblue', icon='bookmark')).add_to(map)
else:
folium.Marker(location=[overlap_markdata['lt'],overlap_markdata['lg']], popup=popup_html, tooltip=overlap_markdata['p'], icon=folium.Icon(color='blue')).add_to(map)
# 지도 검색 API
@app.route('/setposition', methods=['POST'])
def set_position():
#지역 좌표 추출
address1_recieve = request.form['address1_give'] # "광주시"
address2_recieve = request.form['address2_give'] # "북구"
set_location = db.region_info.find_one({'address_class1': address1_recieve, 'address_class2': address2_recieve})
#지도 생성
map_sp = make_map(set_location['latitude'], set_location['longitude'])
#DB 데이터 추출
total_data = list(db.exhibition_info.find({}, {'_id': False}))
#DB데이터 중복 좌표 모음
overlap_coordSP = overlap_list(total_data)
# 회원 마크 표시
if(request.form['key_give'] != ''):
key_receive = request.form['key_give']
#회원 북마크
userbm_coordinate = make_bmcoordinate(key_receive)
mark_onexhibit(map_sp, total_data, overlap_coordSP, userbm_coordinate)
mark_multiexhibit(map_sp, overlap_coordSP, userbm_coordinate)
# 비회원 마크 표시
else:
mark_onexhibit(map_sp, total_data, overlap_coordSP)
mark_multiexhibit(map_sp, overlap_coordSP)
map_sp.save(r'/home/ubuntu/MakingChallenge11/exhibi-dev/templates/position_map.html')
return jsonify({'result': 'success'})