특성
1. def 키워드를 사용해서 정의한다.
2. 리턴 타입에 대한 정의가 필요없다.
3. return 이 없으면 None을 반환한다. (= 명시적으로 return 하지 않아도 무조건 None을 반환한다.)
# Function Signatures
# ===================
# The term function signate means the definition of a function.
# That includes the function's name, and the parameters that it defines.
#
# print(*objects, sep='', end='\n', file=sys.stdout, flush=False)
# The name of the function is print.
# The name's followed by parentheses, with the parameters inside the parentheses.
# Not all functions have parameters, but the parentheses are still needed
# when defining and calling a function.
#
# The first parameter for the print functions is defined in a strange way.
# objects has an asterisk before it.
# That means you can provide zero or more values. We've usually only provided
# one value or none, when we wanted to print a blank line.
# Creating meaningful names and using variables
# Reviewing common rules for creating meaningful Python names
# Names
# =====
# - Should be descriptive
# - Not like x
# - Must refer to an actual thing
# - A descriptive name helps eveyone
# While Naming
# ============
# - Separate the problem domain from the solution domain
# - Solution domain must contain the technical details
# - Reader of the code should see the solution
# - It shouldn't require deep explanation
# - The problem domain could be obscured by technical details
# - Make the problem clearly visible.
# Steps to Choose a Name
# ======================
# - Last part of the name must be summary of the thing
# - Use a prefix to narrow the name
# - Put more narrow and specialized prefixes
# - Format the name as per its use in Python
# A Class Name
# ============
# - Summarizes objects
# - Uses CapitalizedCamelCase
# - Its generic
# A Object Name
# =============
# - Uses snake_case
# - Has multiple underscore (_) characters
# - It includes variables, functions, modules, packages, and so on
# Name of Script/Module Files
# ===========================
# - Uses letters
# - (_) characters
# - Ends with .py
# Naming Qualifiers
# =================
# - FinalStatusDocument
# - ReceivedInventoryItemName
# Narrowing Prefix
# ================
# - measured_height_value
# - estimated_weight_value
# - scheduled_delivery_date
# - location_code
# Things to Avoid
# ===============
# - Don't use Hungarian notation
# - Example: f_measured_height
# - Don't force name to look like they belong together
# - Example: SpadesCardSuit, ClubsCardSuit
def largest_word(words: list[str]) -> tuple[str, int]:
current_len = 0
current_largest = ''
for word in words:
if current_len < len(word):
current_largest = word
current_len = len(word)
return (current_largest, current_len)
lst: list[str] = ['apple', 'banana', 'cherry', 'mango']
largest: tuple[str, int] = largest_word(lst)
print(largest)
# 결과
('banana', 6)
# Pass by object reference
# In other programming languages like C/C++, there are different
# terms used to describe how arguments are passed to functions:
# - Pass by reference
# - Pass by value
# However, it's important to clarify that Python uses a different mechanism
# that can be more accurately described as Pass By Object reference.
# When you pass an argument to a function in Python,
# you are passing the reference to the object, not the actual object itself.
# Python objects can be either mutable (e.g., lists) or
# immutable (e.g., int, strings).
# The behaviour of "pass by object reference" can depend on whether
# the object is mutable or immutable.
# Passing immutable objects
def modify_immutables(x):
x = x - 10 # Creates a new int object
a = 10
modify_immutables(a)
print(f"Unchanged immutable: {a}") # Output: 10 (a remains unchanged)
# When you pass immutable objects (like integers, strings) to a function,
# you can't modify the object itself within the function because you're
# working with a copy of the reference.
# If you re-assign the variable inside the function,
# it creates a new local reference, not affecting the original object
# outside the function.
# 결과
Unchanged immutable: 10
# Passing mutable objects
def modify_mutables(lst):
lst.append(0) # This modifies the list in-place
my_list = [1]
modify_mutables(my_list)
print(my_list) # Output: [1, 0] (my_list is modified)
# When you pass mutable objects (like lists, dictionaries) to a function,
# changes mode to the object within the function will persist
# outside the function because you're still working with the same object
# through its reference.
# 결과
[1, 0]
# Area of triangle
# Formula = 1/2 * base * height
def area_of_triangle(base: float, height:float ) -> float:
return 1/2 * base * height
area = area_of_triangle(12.5, 15)
print(f"Area of triangle: {area}")
# check if number is even or not
def check_even(num: int) -> bool:
if num % 2 == 0:
return True
else:
return False
print(f"Is 12 an even number?: {check_even(13)}")
def sum_all_number(nums: list[int]) -> int:
return sum(nums)
nums = [1, 2, 3, 4]
print(f"Sum of {nums} is {sum_all_number(nums)}")
# 결과
Area of triangle: 93.75
Is 12 an even number?: False
Sum of [1, 2, 3, 4] is 10
def multi_add(*args) -> int:
result: int = 0
for n in args:
result += n
return result
res = multi_add(1, 2, 3)
print(f"result of multi_add: {res}")
# 결과
result of multi_add: 6
# Arbitrary Positional Arguments
def greet(*names: str) -> None:
print(names)
greet("Bob", "James", "sally")
names_list = ["Bob", "James", "sally"]
greet(names_list) # list를 넣으면 unpacking을 하지 못한다.
# Arbitrary Keyword Arguments
def display(**info):
for key, value in info.items():
print(f"{key}: {value}")
display(name='Bob', age=30, city="New York", phone="1234567890")
# 결과
('Bob', 'James', 'sally')
(['Bob', 'James', 'sally'],)
name: Bob
age: 30
city: New York
phone: 1234567890
# Anything that contains a value can be considered to be truthy.
# Otherwise, if it's none or false or zero.
users: dict = {1: 'Mario', 2: 'Luigi', 3: 'James'}
if users:
for k, v in users.items():
print(k, v, sep=': ')
else:
print("No data found...")
# 결과
1: Mario
2: Luigi
3: James
# Type Annotation
# This will tell Python that what we wan to get back is an integer.
def get_length(text: str) -> int:
print(f"Getting the length of: {text}...")
return len(text)
name: str = "Mario"
length: int = get_length(name)
print(length)
# This is also a good example of Self-documenting code that explains itself.
def connect_to_internet() -> None:
print("Connecting to internet...")
# Terminology: Parameter vs Argument
# def func(param1, param2, param3)):
# body of function
# that uses param1, param2, param3
# - Parameter: variable name in function signature (top line of function)
# - Argument: actual value passed in to the function
# - func(5, 'pyhton', True)
# Some built-in 'functions' are not functions.
# - bool, int float, str, range, list, tuple, set, dict are types
# - sum, min, max, sorted, print, ord, chr, id, any, all, dir are functions
# Type vs Function
# - Both are callable
# - Types are used to construct an instance (member)
# - Some types have other ways to create members
# local-and-global variables
# One recommendation is avoid referring to global variables
# inside a function definition. Don't do this.
# It's legal Python, but it's not a good idea.
# Make another formal parameter for the function and have
# whatever value you need to get passed in as a parameter
# to the function.
# Returning a value from a function
def get_square(n: int) -> int:
z = n * n
return z
to_square = 10
square_result = get_square(to_square)
print(f"The result of squared is {square_result}")
# 결과
The result of squared is 100
# Functions that explicitly return a value
# - Use return koyword
# - Roll two dice
# - Calculate sum and return it
import random
def roll() -> int:
num = random.randint(1, 6)
return num
def _roll(count: int) -> int:
total = [roll() for i in range(count)]
return sum(total)
# or
# total = []
# for i in range(count):
# total.append(roll())
# return sum(total)
print(_roll(3))
# 결과
12
# Some questions about function parameters.
#
# how many parameters?
# types?
# type of return value
# A function that accumulates (normal accumulator pattern)
def total(nums: list) -> int:
tot = 0
for n in nums:
tot += n
return tot
print(f'total: {total([1, 3, 5])}')
# This is a common process for abstracting from a bit of code
# that works on a particular value,
# you make that value be a formal parameter name of the function,
# you pass specific values in when you invoke the function.
# 결과
total: 9
# return true if any number is even inside a list
# 리스트 안에 짝수가 하나라도 있으면 True, 하나도 없으면 False 반환
def check_even_list(nums):
for n in nums:
if n % 2 == 0:
return True
else:
pass
return False
# 초보자들은 else 문이 if와 짝을 이루어야 한다고 생각하지만
# logic을 잘 생각해 보면 그렇지 않음을 알 수 있다.
# 모든 리턴 값이 들여쓰기 될 필요는 없다.
print(f'[1, 3, 5] -> {check_even_list([1, 3, 5])}')
print(f'[1, 2, 5] -> {check_even_list([1, 2, 5])}')
print(f'[1, 5, 2] -> {check_even_list([1, 5, 2])}')
# 결과
[1, 3, 5] -> False
[1, 2, 5] -> True
[1, 5, 2] -> True
# 3개의 임의 리스트 중 하나를 선택해 맞췄는지 판단
# 함수를 여러 개 만들고 그들을 하나로 상호작용하게 한다.
# game_list = [' ', 'O', ' ']
from random import shuffle
# 1) shuffle 함수는 아무것도 반환하지 않는다.
# 2) 따라서, init_guess가 변경되어 반환하지 않아도 된다.
# 3) 그러나, 명시적인 반환으로 구현하는게 명확하다.
def shuffle_list(init_guess):
shuffle(init_guess)
return init_guess
def player_guess():
guess = ''
while guess not in ['0', '1', '2']:
guess = input('Pick a number: 0, 1 or 2')
return int(guess)
def check_guess(mixed_list, guess_idx):
if mixed_list[guess_idx] == 'O':
print('Correct!')
else:
print('Wrong guess!')
print(mixed_list)
init_guess = [' ', 'O', ' ']
mixed_list = shuffle_list(init_guess)
player_guess = player_guess()
check_guess(mixed_list, player_guess)
# 결과
Pick a number: 0, 1 or 21
Wrong guess!
[' ', ' ', 'O']
## 숫자를 받아 그것이 모두 짝수이면 그중 작은 수를 반환
## 숫자중 홀수가 포함되면 그중 큰 수를 반환
## 쉬운 구현
def lesser_of_two_evens(num1, num2):
if num1 % 2 == 0 and num2 % 2 == 0:
return min(num1, num2)
else:
return max(num1, num2)
print(lesser_of_two_evens(2, 4))
print(lesser_of_two_evens(1, 2))
# 결과
2
2
## 나의 솔루션
def my_lesser_of_two_evens(*args):
is_all_even = False
for n in args:
if n % 2 == 0:
is_all_even = True
else:
is_all_even = False
break
if is_all_even:
return min(args)
else:
return max(args)
print(my_lesser_of_two_evens(2, 4))
print(my_lesser_of_two_evens(1, 2))
print(my_lesser_of_two_evens(1, 2, 3))
# 결과
2
2
3
# PEP 8, de-facto code style guide for Python
# PEP 8에 의거 최상위 함수와 클래스는 다른 코드와 두 줄씩 띄어 쓴다.
# 클래스 내의 메서드는 한 줄씩 띄어 쓴다.
## ANIMAL CRACKERS: Write a function takes a two-word string and
## returns True if both words begin with same letter.
##
## animal_crackers('Levelheaded Llama') --> True
## animal_crackers('Crazy Kangaroo') --> False
## 솔루션 버전
def animal_cracers(strs):
word_list = strs.lower().split()
first_word = word_list[0]
second_word = word_list[1]
return first_word[0] == second_word[0]
print(animal_cracers('Levelheaded Llama'))
print(animal_cracers('Crazy Kangaroo'))
## 나의 버전
## (솔루션 버전의 해법을 보니 이런 식은 나중에 기억하기 어려워서 좋은 구현은 아니다.
def my_animal_crackers(strs):
word_list = strs.split()
if word_list[0][0] == word_list[1][0]:
return True
else:
return False
print(my_animal_crackers('Levelheaded Llama'))
print(my_animal_crackers('Crazy Kangaroo'))
# 결과
True
False
True
False
## Given a list of ints, return True if the array contains a 3 next to a 3 somewhere.
## 3 3이 연달아 존재하면 True 반환
##
## has_33([1, 3, 3) -> True
## has_33([1, 3, 1, 3]) -> False
## has_33([3, 1, 3) -> False
##
## 나는 그냥 같은 숫자가 두 번 연속으로 나오면 True로 구현했다.
def my_has_33(num_list):
for idx in range(0, len(num_list)-1):
current_num = num_list[idx]
next_num = num_list[idx + 1]
if current_num == next_num:
return True
return False
result1 = my_has_33([1, 3, 3])
result2 = my_has_33([1, 3, 1, 3])
result3 = my_has_33([3, 1, 3])
result4 = my_has_33([3, 1, 1, 1, 3])
print(result1, result2, result3, result4)
# 결과
True False False True
## SPY GAME: Write a function that takes in a list of integers and returns
## True if it contains 007 in order.
##
## 0, 0, 7이 이어지지 않아도 순서대로 존재하면 True 반환
## 7, 0, 0은 False 반환
def spy_game(nums):
code = [0, 0, 7, 'x']
# [0, 7, 'x']
# [7, 'x']
# ['x] length = 1
for n in nums:
if n == code[0]:
code.pop(0)
return len(code) == 1
result1 = spy_game([1, 2, 3, 0, 0, 7, 5])
result2 = spy_game([1, 0, 2, 4, 0, 5, 7])
result3 = spy_game([1, 7, 2, 0, 4, 5, 0])
print(result1, result2, result3)
# 결과
True True False
# 대소문자 글자수 카운트
text = 'Hello Mr. Rogers, how are you this fine Tuesday?'
def up_low(text):
uppercase, lowercase = 0, 0
for char in text:
if char.isupper():
uppercase += 1
elif char.islower():
lowercase += 1
else:
pass # is '?' is entered.
return (uppercase, lowercase)
print(f'Original String: {text}')
print(f'No. of Upper case characters: {up_low(text)[0]}')
print(f'No. of Lower case characters: {up_low(text)[1]}')
# 결과
Original String: Hello Mr. Rogers, how are you this fine Tuesday?
No. of Upper case characters: 4
No. of Lower case characters: 33
# 고유한 리스트 요소만 반환
def uniqe_list(lst):
d = dict()
for l in lst:
if d.get(l, None) == None:
d.setdefault(l, 1)
else:
d[l] += 1
return d.items()
sample_list = [1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5]
print(f'Original list: {sample_list}')
print(uniqe_list((sample_list)))
# 결과
Original list: [1, 1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 5]
dict_items([(1, 4), (2, 2), (3, 4), (4, 1), (5, 1)])
# Pyhton 3에서
# Function Type Annotation을 지원한다.
# Function Return Type Annotation을 지원한다.
def calculate_square_area(side: int = 1) -> int:
return side * side
print(calculate_square_area(2))
# 결과
4
# simple function example
def login(username: str, password: str) -> bool:
is_authenticated = False
if username == 'admin' and password == '1234':
is_authenticated = True
return is_authenticated
user = input('Username: ')
passwd = input('Password: ')
logged_in = login(user, passwd)
msg = 'Login failed, check your credentials.'
if logged_in:
msg = 'Login successful.'
print(msg)
# or
# print('Login successful.' if logged_in else 'Login failed, check your credentials.')
# 결과
Username: admin
Password: 1234
Login successful.
# simple login example
def login(username: str, password: str) -> bool:
is_authenticated = False
if username == 'admin' and password == '1234':
is_authenticated = True
return is_authenticated
user = input('Username: ')
passwd = input('Password: ')
is_authenticated = False
for attempt in range(4):
if login(user, passwd) == True:
is_authenticated = True
break
else:
print(f'Attrempt: [{attempt+1}] Login failed, re-enter your credentials')
user = input('Username: ')
passwd = input('Password: ')
print('Login successful' if is_authenticated else 'Your account has been temporarily locked.')
# 결과
Username: 1
Password: 1
Attrempt: [1] Login failed, re-enter your credentials
Username: 1
Password: 1
Attrempt: [2] Login failed, re-enter your credentials
Username: 1
Password: 1
Attrempt: [3] Login failed, re-enter your credentials
Username: 1
Password: 1
Attrempt: [4] Login failed, re-enter your credentials
Username: 1
Password: 1
Your account has been temporarily locked.
# index error를 방지하기 위한 함수 작성
def is_valid_index(index: int, list: list) -> bool:
result = False
if index >= 0 and index < len(list):
result = True
return result
list = [1, 2, 3]
index = 0
print(f'Index {index} is valid.' if is_valid_index(index, list) else f'Index {index} is out of range.')
index = 3
print(f'Index {index} is valid.' if is_valid_index(index, list) else f'Index {index} is out of range.')
# 결과
Index 0 is valid.
Index 3 is out of range.
# Mutable objects and side-effects
# lst를 넘기면 원본도 변경된다.
# There are programming language built around that principle
# of functional programming but Python is more flexible,
# and we will sometimes make use of side effects but
# you should do it sparingly and consciously.
def change_it(lst):
lst[0] = "Michigan"
lst[1] = "Wolverines"
mylst = ['hello', 'world', '!']
change_it(mylst)
print(mylst)
# 값을 함수에 넘겨도 로컬 스코프 변수는 변하지 않는다.
def double(y):
y *= 2
y = 5
double(y)
print(y)
# 결과
['Michigan', 'Wolverines', '!']
5
# Optional Parameters
def f(a, L=[]):
L.append(a)
return L
# 함수를 빠져 나왔는데도 기존 빈 리스트 객체가 유지된다.
print(f(1))
print(f(2))
print(f(3))
# 집어 넣은 개별 리스트 각각의 객체가 유지된다.
print(f(4, ["hello"]))
print(f(5, ["hello"]))
# 결과
[1]
[1, 2]
[1, 2, 3]
['hello', 4]
['hello', 5]
# Args & Kwargs
# args는 positional argument로 입력 받는다.
def greet(greeting: str, *people: str, ending: str) -> None:
for person in people:
print(f"{greeting}, {person}{ending}")
greet('hello', 'Bob', 'James', 'Maria', ending='!')
# **kwargs는 dict로 입력 받는다.
def pin_position(**kwargs: int) -> None:
print(kwargs)
pin_position(x=10, y=20)
# args, kwargs 명시적 파라미터 선언
# (what the slash and asterisk does in a function signature.)
def func(var_a: str, /, var_b: str, *,var_c: str) -> None:
print(var_a, var_b, var_c)
func('a', 'b', var_c='c')
func('a', var_b='b', var_c='c') # middle one can be both or the one that is in between.
# 결과
hello, Bob!
hello, James!
hello, Maria!
{'x': 10, 'y': 20}
a b c
a b c
# 함수의 아규먼트에 디폴트 뮤터블을 사용하는 경우에
# 원치하는 결과가 나오기 때문에
# 다음의 방법으로 처리한다.
# Recommended Way to Use Mutable Default Value
def add_arr(item, arr=None):
if arr is None:
arr = []
arr.append(item)
return arr
# calling the function with one argument
print(add_arr(1))
print(add_arr(2))
print(add_arr(3))
# calling the function with two arguments
print(add_arr(4, [1, 2, 3]))
# 결과
[1]
[2]
[3]
[1, 2, 3, 4]
[100]
from time import sleep
from datetime import datetime
def log(message, when=datetime.now()):
print(f"{when}: {message}")
"""Log a mesage at a certain time.
Args:
message: Message to print.
when: datatime of when the message occurred.
Defaults to the present time.
"""
def log2(message, when=None):
if when is None:
when = datetime.now()
print(f"{when}: {message}")
log("hello")
sleep(1)
log("hello again")
# 여기서의 문제는 명시적인 sleep이 있음에도 now() 호출로 인한
# 시간 변경이 없다는 점이다. 그래서,
log2("hello2")
sleep(1)
log2("hello again2")
# Output:
2024-12-16 10:17:39.034517: hello
2024-12-16 10:17:39.034517: hello again
2024-12-16 10:17:40.035328: hello2
2024-12-16 10:17:41.036390: hello again2
import json
def decode(data, default=None):
# Decode JSON data and return a default if it's bad.
# Args:
# data: Data to decode.
# default: Value to return if decoding fails.
# Defaults to an empty dictionary.
# Returns:
# Value of decoded data or the default.
if default is None:
default = {}
try:
return json.loads(data)
except ValueError:
return default
print(decode('{"hello": "world"}'))
# Output:
{'hello': 'world'}
# Higher-order functions
# ======================
# A function that takes another function as an argument or returns
# another function as an output.
#
# Higher-order functions allows us to treat functions as first-class citizens.
#
# First-class citizens:
# An entity supports being assigned to a variable, passed as an argument, returned
# by a function.
def outer(msg):
def hello_msg(msg):
print(msg)
return hello_msg(msg)
h1 = outer
h2 = outer
h1("hi")
h1("hello")
# Output:
hi
hello
# Closure
def multiplier(factor: int):
def multiply_by(data: list[int]):
return [element * factor for element in data]
return multiply_by
data = [1, 2, 3, 4, 5]
double = multiplier(factor=2)
triple = multiplier(factor=3)
print(f"Original: {data}")
print(f"Double: {double(data)}")
print(f"Triple: {triple(data)}")
# Output:
Original: [1, 2, 3, 4, 5]
Double: [2, 4, 6, 8, 10]
Triple: [3, 6, 9, 12, 15]
# Nested functions create inner scopes. These are called closures:
def multiplier_maker(factor):
def multiply(num):
return num * factor
return multiply
doubler = multiplier_maker(2)
tripler = multiplier_maker(3)
print(doubler(10))
print(doubler(15))
print(tripler(10))
print(tripler(15))
# Output:
20
30
30
45
# Palindrome
# ==========
# A palindrome is a word that reads the same backwards as forwards.
# Palindrome are normally created for fun. There's nothing wrong with having a bit
# but they do have practical applications.
def is_palindrome(string):
end_pos = len(string)
for index in range(end_pos):
if string[index] != string[end_pos - index - 1]:
return False
return True
def is_palindrome2(string):
backward = string[::-1].casefold()
return backward.casefold() == string
def palindrome_sentence(sentence):
string = ""
for char in sentence:
if char.isalpha():
string += char
backward = string[::-1]
return backward.casefold() == string.casefold()
word = input("Please enter a word to check: ")
if palindrome_sentence(word):
print(f"'{word}' is a palindrome")
else:
print(f"'{word}' is not a palindrome")
# print(is_palindrome("anana"))
# print(is_palindrome2("anana"))
# Outptu:
Please enter a word to check: do gees see god!
'do gees see god!' is a palindrome
Please enter a word to check: banana
'banana' is not a palindrome
Please enter a word to check: anana
'anana' is a palindrome
def banner_text(text = " ", screen_width = 80):
if len(text) > screen_width - 4:
raise ValueError(f"String {text} is larger than specified width {screen_width}")
if text == "*":
print("*" * screen_width)
else:
centered_text = text.center(screen_width - 4)
output_string = f"**{centered_text}**"
print(output_string)
banner_text("*")
banner_text("Always look on the bright side of life...")
banner_text("If life seems jolly rotten,")
banner_text("There's something you've forgotten!")
banner_text("And that's to laugh and smile and dance and sing,")
banner_text(" ", 80)
banner_text("When you're feeling in the dumps,", 80)
banner_text("Don't be silly chumps,", 80)
banner_text("Just purse your lips and whistle - that's the thing!", 80)
banner_text("And... always look on the bright side of life...", 80)
banner_text("*", 80)
# Output:
********************************************************************************
** Always look on the bright side of life... **
** If life seems jolly rotten, **
** There's something you've forgotten! **
** And that's to laugh and smile and dance and sing, **
** **
** When you're feeling in the dumps, **
** Don't be silly chumps, **
** Just purse your lips and whistle - that's the thing! **
** And... always look on the bright side of life... **
********************************************************************************
def fibonacci(n):
"""Return the 'n'th Fibonacci number, for positive 'n'."""
if 0 <= n <= 1:
return n
n_minus1, n_minus2 = 1, 0
result = None
for f in range(n - 1):
result = n_minus2 + n_minus1
n_minus2 = n_minus1
n_minus1 = result
return result
print(fibonacci.__doc__)
for i in range(11):
print(i, fibonacci(i))
# Output:
Return the 'n'th Fibonacci number, for positive 'n'.
0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
10 55
댓글 영역