말 그래로 기존의 함수에 약간의 첨가를 할 때 사용한다.

 

예를 들어보자.

name을 input으로 받으면, 포매팅 문자열로 넣어서 반환해주는 함수이다.

def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))

output: Hello, Alice

 

그런데 이러한 함수가 100가지가 되고,

모든 함수의 output을 대문자로 바꾼다고 생각해보자.

 

그러면 위의 함수는 다음과 같이 바꿔야한다.

def greet(name):
    return f"HELLO, {name.upper()}!"

print(greet("Alice"))

Hello -> HELLO

name -> name.upper()

 

이렇게 바꾸는 과정을 100번 해야한다.

 

그렇다면, 함수를 만들어서 재정의하는 건 어떨까?

def uppercase(func):
    def wrapper(text):
        result = func(text)
        return result.upper()
    return wrapper


def greet(name):
    return f"Hello, {name}!"

greet = uppercase(greet)

print(greet("Alice"))

이렇게 하면 이전의 방법보다는 편하지만, 결국 재정의 과정을 100번해야한다.

(greet = uppercase(greet))

 

더 편한 방법이 없을까?

이럴때 사용하는 방법이 decorator pattern이다.

def uppercase_decorator(func):
    def wrapper(text):
        result = func(text)
        return result.upper()
    return wrapper

@uppercase_decorator
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))

 

재정의하고자 하는 함수 바로위에, @재정의함수를 사용하면 된다.

 

협업을 진행하려면, 패키지의 버전을 맞춰써야한다.

협업을 한개만 진행한다면 하나의 버전만 쓰면 되겠지만,

다양한 협업을 진행하는 경우, 각각의 프로젝트마다 패키지의 버전이 다를 수 있다.

 

이러한 경우를 위해, 프로젝트는 가상환경 세팅 후 진행한다.

가상환경 세팅을 위해서 venv를 사용한다.

 

venv 사용 방법

1. 가상 환경 생성

python3 -m venv <가상환경명>

 

2. 가상 환경 실행

source venv/bin/activate

3.  가상 환경 종료

deactivate

 

venv안에서 이제 개발된 패키지 버전에 맞춰서 환경을 만들어야한다.

이때는 pip을 사용한다.

pip 사용 방법

1. 설치된 패키지 확인

pip freeze

2. requirements.txt에 설치된 패키지 버전 저장

pip freeze > requirements.txt

3. requirements.txt에 기록된 패키지 설치

pip -r requirements.txt

'섭섭의 공부 > Programming' 카테고리의 다른 글

[Python] decorator pattern  (1) 2024.01.04

Ollivander's Inventory

/*
the minimum number of gold galleons needed to buy each non-evil wand of high power and age.
1. Write a query to print the id, age, coins_needed, and power of the wands that Ron's interested in
2. sorted in order of descending power
3. If more than one wand has same power, sort the result in order of descending age.
*/

select w.id, p.age, w.coins_needed, w.power 
from Wands as w 
    join Wands_Property as p on (w.code = p.code) 
where p.is_evil = 0 and w.coins_needed = 
                                        (select min(coins_needed) 
                                         from Wands as w1 
                                            join Wands_Property as p1 on (w1.code = p1.code) 
                                         where w1.power = w.power and p1.age = p.age) 
order by w.power desc, p.age desc

문제에 1대 1 매핑의 의미를 이해해야 한다.

한 code에 매핑되는 매핑되는 age는 한 개다.

 

서브 쿼리에서 메인 쿼리에서 조인한 테이블의 컬럼을 사용했다.

이러한 방법으로 같은 power와 같은 age일 때의 minimum coins_needed를 구하여, 그것을 다시 where문의 조건으로 사용하였다.

 

문제의 조건이 애매해하여 discussions을 읽어보고 그곳에 있는 해답으로 이해했다.

같은 조건의 power와 age가 존재할 때, minimum coins_needed가 조건인지 몰랐다.

1시간이나 시간을 썼는데 시간이 아깝다.

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

Weather Observation Station 20

with t1 as
(select rank() over (order by lat_n) rnk, lat_n
from station)

select case
            when mod(count(*),2) = 1 then (select round(t1.lat_n,4) from t1 where t1.rnk = count(*)/2 + 0.5)
            when mod(count(*),2) = 0 then (select round(avg(t1.lat_n),4) from t1 where t1.rnk = count(*)/2
                                                                      or t1.rnk = count(*)/2+1)
            else 0
        end    
from t1

 

Top Competitors

/*
1.  print the respective hacker_id and name of hackers who achieved full scores for more than one challenge
2.  Order your output in descending order by the total number of challenges in which the hacker earned a full score.
3.  If more than one hacker received full scores in same number of challenges, then sort them by ascending hacker_id.
*/

with t2 as
(select s.submission_id,
        s.hacker_id,
        s.challenge_id,
        s.score,
        t1.max_score
from submissions as s
left join
(select c.challenge_id, d.score as max_score
from challenges as c
     left join difficulty as d on d.difficulty_level = c.difficulty_level) t1 on s.challenge_id = t1.challenge_id)

select t.hacker_id, h.name
from t2 as t
     left join hackers as h on t.hacker_id = h.hacker_id
where t.score = t.max_score
group by t.hacker_id, h.name
having count(*) > 1
order by count(*) desc, t.hacker_id

hackerrank에서 mysql을 사용하면 with문이 에러가 날 때가 있다.

이때, ms sql server를 사용하면 에러가 안 난다.

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

Japan Population

 

select sum(population)
from city
where Countrycode = 'JPN'

 

The Blunder

select ceil(avg(salary) - (select avg(replace(salary, 0, '')) from employees))
from employees

 

Weather Observation Station 2

select round(sum(lat_n), 2), round(sum(long_w), 2)
from station

 

Weather Observation Station 13

select round(sum(lat_n), 4)
from station
where 38.7880 < lat_n and lat_n < 137.2345

 

Weather Observation Station 14

select round(max(lat_n), 4)
from station
where lat_n < 137.2345

 

Weather Observation Station 16

select round(min(lat_n), 4)
from station
where 38.778 < lat_n

 

Weather Observation Station 17

select round(long_w, 4)
from station
where lat_n = (select min(lat_n)
              from station
              where lat_n > 38.7780)

 

Weather Obseravation Station 18

select round((c-a) + (d-b), 4)
from
(select min(lat_n) as a,
       min(long_w) as b,
       max(lat_n) as c,
       max(long_w) as d
from station) t1

 

Weather Observation Station 19

select round(sqrt(power((b-a),2) + power((d-c),2)),4)
from
(select min(lat_n) as a,
       max(lat_n) as b,
       min(long_w) as c,
       max(long_w) as d
from station) as t1

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

 

New Companies

/*
1. print the company_code, founder name, total number of lead managers, total number of senior managers, total number of managers, and total number of employees
2. Order your output by ascending company_code.
3. The company_code is string
4. The tables may contain duplicate records.
*/

select c.company_code, 
    c.founder, 
    count(distinct e.lead_manager_code), 
    count(distinct e.senior_manager_code), 
    count(distinct e.manager_code), 
    count(distinct e.employee_code)
from company c
    inner join employee e on e.company_code = c.company_code
group by c.company_code, c.founder
order by c.company_code;

중간에 있던 테이블은 쓸 필요가 없다.

중복으로 개수를 세는 것을 피하기 위해 distinct를 사용하고, group by로 묶어 각 회사의 직급별 사원 id의 수를 세준다.

그리고 원래의 company_code와 founder를 select하고 싶음으로 group by에 두 조건 모두 넣는다.

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

Occupations

set @D=0, @A=0, @S=0, @P=0; 

select min(sub.c1),min(sub.c2),min(sub.c3),min(sub.c4)
from
(select
       case when Occupation = 'Doctor' then name end as c1,
       case when Occupation = 'Professor' then name end as c2,
       case when Occupation = 'Singer' then name end as c3,
       case when Occupation = 'Actor' then name end as c4,
       case
            when Occupation = 'Doctor' then (@D:=@D+1)
            when Occupation = 'Actor' then (@A:=@A+1)
            when Occupation = 'Singer' then (@S:=@S+1)
            when Occupation = 'Professor' then (@P:=@P+1)
        end as num
from occupations
order by name) sub
group by sub.num

안 그래도 피봇에 대해서 어려워했는데, 이 문제는 많이 어려웠다.

@로 변수를 만들 수 있는 것도 처음 알았다.

 

서브 쿼리의 Case when Occupation ~ then name end as ~ 에서는 각 직업의 열을 만들고 그 값으로 name을 넣는다.

그리고 그 다음 case문이 중요한데, 문제의 아웃풋을 보면 한 행에 각 직업을 가진 사람들의 이름이 알파벳 순서대로 나온다. 그래서 각 직업별로 (@D:=@D+1)을 사용해서 몇 번째 행에 이 이름이 나올 것인지를 입력한다. 그래서 order by name을 함께 써야 한다.

 

그 이후 바깥 쿼리에서 sub.num으로 각 행의 인덱스에 맞춰서 name을 select 해주면 되는데, group by를 사용하며 이때 select 뒤에는 집계 함수가 들어가야 한다. 그래서 알파벳 순으로 제일 앞에 있는 값을 출력하는 min을 사용한다.

 

피봇을 실무에서 많이 쓰는지는 모르겠는데, 피봇을 쓸 일이 생기면 애를 많이 먹을 것 같다.

기억해둬야겠다.

 

Binary Tree Nodes

select t1.N,
       case when inx = 1 then 'Root'
            when inx = 2 then 'Inner'
            when inx = 3 then 'Leaf'
        end
from(
select N,
       case when P is null then 1
            when N in (select distinct P from BST) then 2
            else 3
            end as inx
from BST) t1
order by t1.N

복잡해 보일수록 쉬운 방법이 존재한다.

간단하게 생각하자.

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

Weather Observation Station 3

select distinct city
from station
where mod(id,2) = 0

mod(a,b) -> a를 b로 나눈 값을 반환

 

The PADS

/*
1. an alphabetically ordered list of all names in OCCUPATIONS
2. immediately followed by the first letter of each profession as a parenthetical 
3. Sort the occurrences in ascending order, and output them in the following format:
4. There are a total of [occupation_count] [occupation]s.
    [occupation_count] is the number of occurrences of an occupation in OCCUPATIONS
    [occupation] is the lowercase occupation name
    the same [occupation_count], they should be ordered alphabetically.
*/

select concat(name,'(', upper(left(occupation,1)),')')
from occupations
order by name ;

select concat('There are a total of ', count(*),' ', lower(occupation),'s.')
from occupations
group by occupation
order by count(*), occupation ;

union을 굳이 쓰지 않아도 ;로 나눠주면 union한 것처럼 된다.

 

(문제 출처 - https://www.hackerrank.com/domains/sql)

 

 

+ Recent posts