업무에 파이썬 활용할 줄 알기
Day19 | 중급 | 인스턴스, 상태 및 고차함수 본문
Day19 | 중급 | 인스턴스, 상태 및 고차함수
SEO 데이터분석가 2024. 1. 3. 10:4119일차 목표: 오늘의 최종 결과물
More Turtle Graphics, Event Listeners, State and Multiple Instances
파이썬 고차 함수 & 이벤트 리스너
키보드에서 특정 키를 탭핑한다던지 등 유저들이 하는 것을 들을 수 있는 방법이 필요함
이걸 가능하게 하는 코드를 이벤트 리스너(event listeners)라고 부름
we need a way of being able to listen to things the user does,
like when the user taps a specific key on the keyboard. And the code that allows
us to do this are called event listeners.

이벤트를 듣기위해서 screen이라는 객체를 작성하고, listen하라고 작성한다
그리고 나면 특정 키가 눌러졌을 때 발동될 기능을 엮어주어야한다. 이 때 event listener를 사용한다.
Now in order to start listening for events,
we have to get hold of the screen object and then tell it to start listening.
And once it starts listening,
we have to bind a function that will be triggered when a particular key is
pressed on the keyboard.
in order to bind a key stroke to an event in our code,
we have to use an event listener.

screen.onkey를 작성하고, 이 메서드에 어떤 기능을 엮어주어야 한다.
So I'm going to say screen.onkey
and then I have to bind some sort of function to this method.

주의사항:
fun 파라메터에 메서드를 적을 때,
즉 다른 function으로 전해지는 function일 때, () parentheses 기호를 기입하지 않는다
() parentheses는 기능이 발생하도록 발동시키는데
우리가 원하는 건 이 onkey 메서드가 스페이스바가 move_forwards function을 발동시키기위해
발생되는 때를 듣기만을 바라기 때문이다.
Now here's a really important point; when we use a function as a argument,
so something that is going to be passed into another function,
we don't actually add the parentheses at the end.
The parentheses triggers the function to happen there and then.
But what we want is we want this method, onkey, to listen for when the space bar
is pressed and only when that happens to trigger this move_forwards function.

이 onkey 기능은 정확히 어떻게 작동하는 것인가?
But how exactly does this function onkey work?
Because it's kind of crazy to use a function as the input to another function,
또 다른 예

고차함수(Higher Order Functions)는 다른 함수와 함께 작동하는 함수이다.
위 예에서는 calculator가 바로 다른 함수를 input으로 취하여 작동하는 고차함수이다.
But essentially what I'm trying to demonstrate to you is this concept
which is known in Python as Higher Order Functions.
And the idea of a higher order function is a function that can work with other
functions. So in this case,
our calculator is a higher order function because it's actually taking another
function as an input, and then working with it inside the body of the function.
이 고차함수는 특히 이벤트를 듣고, 특정 기능을 발동시킬 때 특히 유용하다
onkey와 같이 우리가 직접 만들지 않은 메서드를 사용할 때는
positional arguments가 아니라 keyword arguments를 사용할 것을 권장한다
.
e.g. Positional Arguments의 예: def my_function(a, b, c): / my_function(1, 2, 3)
e.g. Keyword Aftuments의 예: def my_function(a, b, c): / my_function(c=3, a=1, b=2)
요약: event listner가 어떻게 작동하는지를 설명
과제: Etch A Sketch 앱 만들기
W = Forwards
S = Backwards
A = Counter-Clockwise
D = Clockwise
C = Clear drawing
My solution
from turtle import Turtle, Screen
tim = Turtle()
screen = Screen()
def move_forwards():
tim.forward(10)
def move_backwards():
tim.backward(10)
def counter_clockwise():
tim.circle(100, -10)
def clockwise():
tim.circle(100, 10)
def clear_drawing():
tim.clear()
screen.listen()
screen.onkey(key="w", fun=move_forwards)
screen.onkey(key="s", fun=move_backwards)
screen.onkey(key="a", fun=counter_clockwise)
screen.onkey(key="d", fun=clockwise)
screen.onkey(key="c", fun=clear_drawing)
screen.exitonclick()
And the screen is able to detect it because it's listening for those keyboard
strokes and clicks. Now,
Angela's solution
from turtle import Turtle, Screen
tim = Turtle()
screen = Screen()
def move_forwards():
tim.forward(10)
def move_backwards():
tim.backward(10)
def turn_left():
new_heading = tim.heading() + 10
tim.setheading(new_heading)
def turn_right():
new_heading = tim.heading() - 10
tim.setheading(new_heading)
def clear_drawing():
tim.clear()
tim.penup()
tim.home()
tim.pendown()
screen.listen()
screen.onkey(key="w", fun=move_forwards)
screen.onkey(key="s", fun=move_backwards)
screen.onkey(key="a", fun=turn_left)
screen.onkey(key="d", fun=turn_right)
screen.onkey(key="c", fun=clear_drawing)
screen.exitonclick()
객체 상태 및 인스턴스
각각의 인스턴스들은 서로 다른 attribute를 지닐 수 있고, 다른 method, 즉 동작을 수행할 수도 있다
우리는 클래스라는 청사진을 사용해 터틀의 모양과 동작 방식, 즉 터틀이 어떤 속성을 지니며
어떤 동작을 수행할 수 있는지 정의할 수 있다는 것을 알고 있습니다 그리고
이 클래스를 가져와 실제 터틀 객체를 생성할 수 있습니다
우리가 이 청사진을 사용하는 근본적인 이유 청사진으로 더 많은 객체를 만들 수 있기 때문입니다
timmy와 tommy 모두 터틀 객체이지만 사실 두 객체를 서로 완전히 독립적으로 기능합니다
프로그래밍에서는 이 두 객체를 별개의 인스턴스라고 부릅니다
서로 다른 상태를 지니며 완전히 독립적으로 행동하는 같은 객체의
다른 버전이 각각 존재할 수 있기 때문에 여러 객체가 서로 경쟁할 수 있는 것입니다
터틀 좌표계 이해하기
My solution
for문을 쓰고 싶었는데 object 이름을 반복문으로 어떻게 다르게 변형시켜줘야할지 모르겠어서 못함..!
from turtle import Turtle, Screen
screen = Screen()
screen.setup(width=500, height=400)
user_bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter a color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
tim = Turtle(shape="turtle")
tim.penup()
tim.goto(x=-230, y=-125)
tim.color(colors[0])
tim2 = Turtle(shape="turtle")
tim2.penup()
tim2.goto(x=-230, y=-75)
tim2.color(colors[1])
tim3 = Turtle(shape="turtle")
tim3.penup()
tim3.goto(x=-230, y=-25)
tim3.color(colors[2])
tim4 = Turtle(shape="turtle")
tim4.penup()
tim4.goto(x=-230, y=25)
tim4.color(colors[3])
tim5 = Turtle(shape="turtle")
tim5.penup()
tim5.goto(x=-230, y=75)
tim5.color(colors[4])
tim6 = Turtle(shape="turtle")
tim6.penup()
tim6.goto(x=-230, y=125)
tim6.color(colors[5])
screen.exitonclick()
Angela's solution
객체명을 서로 다르게 지정해주지 않아도 되는거네?
터틀 인스턴스 6개를 만들어주기 위해 단순 for문을 사용함
from turtle import Turtle, Screen
screen = Screen()
screen.setup(width=500, height=400)
user_bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter a color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
y_positions = [-70, -40, -10, 20, 50, 80]
for turtle_index in range(0,6):
tim = Turtle(shape="turtle")
tim.penup()
tim.goto(x=-230, y=y_positions[turtle_index])
tim.color(colors[turtle_index])
screen.exitonclick()
레이싱을 시작합니다!
Angela's solution
from turtle import Turtle, Screen
import random
is_race_on = False
screen = Screen()
screen.setup(width=500, height=400)
user_bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter a color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
y_positions = [-70, -40, -10, 20, 50, 80]
all_turtles = []
for turtle_index in range(0,6):
new_turtle = Turtle(shape="turtle")
new_turtle.penup()
new_turtle.goto(x=-230, y=y_positions[turtle_index])
new_turtle.color(colors[turtle_index])
all_turtles.append(new_turtle)
if user_bet:
is_race_on = True
while is_race_on:
for turtle in all_turtles:
if turtle.xcor() > 230:
is_race_on = False
winning_color = turtle.pencolor()
if winning_color == user_bet:
print(f"You've won! The {winning_color} turtle is the winner!")
else:
print(f"You've lost! The {winning_color} turtle is the winner!")
rand_distance = random.randint(0,10)
turtle.forward(rand_distance)
screen.exitonclick()
#어떻게 거북이들을 서로다른 속도로 움직이게 할 것인가
#1. forward(random_distance)
##이게 게임이 끝날때까지 계속 거북이들한테 적용되어야함
##(반복문이 필요하겠다 while, is_race_on = False)
#2. if user_bet: is_race_on= True (아.. 이렇게 하는 방법을 절대 생각해낼 수 없을 것 같은데..)
##처음부터 is_race_on = True로 두면안되나? 왜 굳이 if user_bet을 써주는거지?
##여기서 설명하기로는 user가 bet하기 전에 결과가나지 않도록 하기위함이라는데..
##코드 순서상 그럴일이있나?
#3. all_turtles 리스트 말들어주고, 각 turtle에 forward 할당해주기 (for문)
#4. 멈추는 조건 반영해주기: 끝에 도달했을 때!
##if turtle.xcor(): 한 다음 print(turtle.color())해보면 2가지 컬러를 반환하는 걸 알 수 있다. pencolor만
Angela's solution을 보고서 angela의 문제해결과정을 1-4번으로 정리를 해보긴했는데
혼자서는 거북이들한테 서로다른 랜덤한 속도를 부여해주고, 게임이 끝나게 만드는 이 과정을
코드로 구현하지 못했을 것 같다. 어렵다..
내가 이해하기 쉬운 방식으로 뺄꺼 빼고 순서 변경한 코드
불필요하다고 생각한 코드를 제외해도 문제없이 작동한다.
from turtle import Turtle, Screen
import random
is_race_on = True
screen = Screen()
screen.setup(width=500, height=400)
user_bet = screen.textinput(title="Make your bet", prompt="Which turtle will win the race? Enter a color: ")
colors = ["red", "orange", "yellow", "green", "blue", "purple"]
y_positions = [-70, -40, -10, 20, 50, 80]
all_turtles = []
for turtle_index in range(0,6):
new_turtle = Turtle(shape="turtle")
new_turtle.penup()
new_turtle.goto(x=-230, y=y_positions[turtle_index])
new_turtle.color(colors[turtle_index])
all_turtles.append(new_turtle)
while is_race_on:
for turtle in all_turtles:
rand_distance = random.randint(0,10)
turtle.forward(rand_distance)
if turtle.xcor() > 230:
is_race_on = False
winning_color = turtle.pencolor()
if winning_color == user_bet:
print(f"You've won! The {winning_color} turtle is the winner!")
else:
print(f"You've lost! The {winning_color} turtle is the winner!")
이번 강의의 핵심
timmy와 tommy는 같은 Turtle 객체이지만 서로 다른 인스턴스이다.
timmy와 tommy는 서로 다른 색깔을, 외모를 가질 수 있고, 서로 다른 속도로 움직일 수도 있다
이것이 Object Oriented Programming이 유용한 이유이다.
'Python > [Udemy] 100개의 프로젝트로 Python 개발 완전 정복' 카테고리의 다른 글
Day21 | 중급 | 뱀 게임 만들기 2편: 클래스 상속 & 리스트 슬라이싱 (2) | 2024.01.08 |
---|---|
Day20 | 중급 | 뱀 게임 만들기 1편: 애니메이션 & 좌표 (0) | 2024.01.04 |
Day 18 | 중급 | 터틀 & 그래픽 사용자 인터페이스 (GUI) (2) | 2024.01.02 |
Day17 | 중급 | 퀴즈 프로젝트와 OOP의 장점 (0) | 2023.12.28 |
Day16 | 중급 | 객체 지향 프로그래밍(OOP) (0) | 2023.12.27 |