Ruby VS Python 뭐가 다를까? [2부]
안녕하세요! 이번에는 Ruby VS Python 비교 두 번째 포스팅입니다.
이번 포스팅에서는 method, class, exception(예외처리) 등 에 대해 비교해보고 느낀 점을 공유해보겠습니다.
👨💻 문법 비교
1. method (함수)
- Ruby♦️
def test_method(temp = "default")
return "hello world! #{temp}"
end
puts test_method
puts test_method('무야호!')
puts test_method '무야호~'
|
cs |
- Python🐍
def test_method(temp="default"):
return f"hello world! {temp}"
print(test_method())
print(test_method('무야호!'))
|
cs |
일단은 함수의 선언도 크게 다르지는 않은 것 같아요. Ruby는 특이한 게 파라미터를 함수에 전달할 때 괄호를 사용하지 않아도 되더군요. 역시 Ruby는 최대한 간결하게 사용하려는 게 문법에서 많이 드러나는 것 같습니다.
2. class (클래스)
- Ruby♦️
class Company
attr_writer :name # 인스턴스 변수에 수정하기 위해 사용
attr_reader :name # 인스턴스 변수를 접근하기 위해사용
attr_accessor :sector #인스턴스 변수에 접근하고 수정하기 위해 사용
@@count = 0
def initialize(name, sector)
@name = name
@sector = sector
@@count += 1 # 회사 카운트
end
def describe
puts "저희 회사의 이름은 #{@name} 이며, 업종은 #{@sector} 입니다"
end
def self.print_intro # 클래스 메소드 (인스턴스 선언을 하지 않아도 사용가능)
puts "이것은 Company class 입니다"
end
def self.get_company_count
return @@count
end
end
Company.print_intro # 클래스 메소드 호출 (인스턴스 선언 없이 호출 가능)
jay_company = Company.new('jay', 'game')
jay_company.describe
jay_company.name = 'new_jay'
jay_company.describe
zzeri_company = Company.new('jay', 'game')
puts Company.get_company_count
|
cs |
- Python🐍
# Ruby에서도 클래스의 부모 클래스는 object Python에서는 명시해주는 걸 선혼
# class Company(object):
class Company:
count: int = 0 # 클래스 변수
def __init__(self, name, sector): ## __xxx__ 매직 메서드에서 사용되는 컨벤션
self.name = name # 인스턴스 변수(self)
self.sector = sector # 인스턴스 변수(self)
Company.count += 1
def describe(self):
print(f"저희 회사의 이름은 {self.name} 이며, 업종은 {self.sector} 입니다")
@classmethod # 클래스 메소드 선언 데코레이터
def print_intro(cls):
print("이것은 Company class 입니다")
@classmethod
def get_company_count(cls):
return cls.count
Company.print_intro() # 클래스 메소드 호출 (인스턴스 선언 없이 호출 가능)
jay_company = Company('jay', 'game')
jay_company.describe()
jay_company.name = 'new_jay'
jay_company.describe()
zzeri_company = Company('jay', 'game')
print(Company.get_company_count())
|
cs |
class 선언은 두 언어가 많이 다른 것 같습니다. 일단 첫 번째로는 class변수, instance 변수의 선언입니다.
python의 경우 self로 선언한 변수는 인스턴스 변수, class 내부에서 선언된 변수는 class변수입니다.
ruby는 반면에 @변수가 instance 변수, @@변수는 class 변수입니다. 그리고 ruby는 attr_writer, attr_reader, attr_accessor 같은 걸로 인스턴스 변수 접근에 대한 권한을 줄 수도 있습니다.
또 한 가지 다른 점은 class method의 경우 python에서는 @classmethod로 선언을 하게 되는데, ruby는 함수 앞에 self를 붙이는 게 class method의 선언입니다. class method는 별도의 instatnce 생성 없이 사용 가능합니다.
두 언어가 기능은 비슷한데, 선언하는 방법과 문법의 차이가 확실히 다르네요. python만 사용하다가 ruby를 보니까 살짝 헷갈리기도 하네요:D
3. class (클래스) 상속
- Ruby♦️
# 클래스 상속
class Animal
def bark
puts "부모 클래스"
end
private # private 선언하면 외부 접근 불가
def age
end
public # 메소드는 기본적으로 public
def name
end
end
class Dog < Animal
def bark
super()
puts "멍멍"
end
end
dog = Dog.new()
dog.bark
puts Dog.superclass # 부모클래스 확인
dog.name
|
cs |
- Python🐍
from abc import abstractmethod, ABCMeta
class Animal(metaclass=ABCMeta): # 추상 메소드 구현을 강제하기 위해
@abstractmethod # 이 데코레이터를 붙이면, 상속받는 클래스에서 오버라이딩을 꼭 해줘야한다
def bark(self):
print("부모 클래스")
def __age(self): # __(언더스코어 2개)가 private이라는 컨벤션
pass
def name(self):
pass
class Dog(Animal):
def bark(self):
super().bark()
print("멍멍")
dog = Dog()
dog.bark()
print(Dog.__bases__)
dog.name
|
cs |
class의 상속도 두 언어 비슷하나 private, public 선언이 살짝 다릅니다. python은 __(언더스코어 2개)로 private이라는 표현을 컨벤션으로 할 수 있고, ruby의 경우 private이라고 함수 위에 데코레이터(?)처럼 선언을 해줘야 한다. (실제로 이게 데코레이터 같은 역할인지는 좀 더 찾아봐야 할 것 같습니다.)
추가로 python에서는 metaclass=ABCMeta를 선언하고 메서드에 @abstractmethod 데코레이터를 사용하면, 상속받는 자식 클래스에 오버라이등을 강제할 수 있습니다. ruby에도 이런 데코레이터가 있는지 찾아봐야겠네요.
4. 싱클톤 메서드
- Ruby♦️
class Foo
end
new_foo = Foo.new()
new_foo2 = Foo.new()
def new_foo.print_hello
puts "hello!"
end
new_foo.print_hello
new_foo2.print_hello
|
cs |
ruby는 class에서 정의한 메서드 이외에 추가로 인스턴스 고유의 메서드를 가질 수 있습니다.
5. 예외처리
위에서 선언한 Dog 클래스를 사용해서 예외처리에 대해 알아보겠습니다.
- Ruby♦️
dog = Dog.new()
begin
dog.age # private method erroed
rescue => e
# 예외 발생
puts "------------------"
puts "Error : #{e.class}" #standard Error
puts "Error : #{e.message}" # 에러 메세지
puts "Error : #{e.backtrace}" # 콜스택 배열
puts "------------------"
else
# 예외가 발생하지 않은 경우 실행
puts "예외 발생되지 않음"
ensure
# 예외 유무 상관없이 실행
puts "무야호!"
end
|
cs |
- Python🐍
dog = Dog()
try:
dog.age() # private method erroed
except Exception as e:
# 예외 발생
print("------------------")
print(f"Error : {e.__class__}") #standard Error
print(f"Error : {e.__str__()}") # 에러 메세지
print(f"Error : {e.__traceback__.tb_frame}") # 콜스택 배열
print("------------------")
else:
# 예외가 발생하지 않은 경우 실행
print("예외 발생하지 않음")
finally:
# 예외 유무 상관없이 실행
print("무야호!")
|
cs |
python, ruby 두 언어 모두 예외처리를 똑같이 할 수 있습니다. 다만, 문법적 차이는 있습니다. 신기하게 ruby에서는 except를 rescue라고 하더라고요. 예외처리를 구출(?)하라는 의미인가 ㅋㅋㅋ 다른 언어에서도 저렇게 사용하는지 확인해보는 것 도 재밌겠네요.
그 외 다른 점은 ensure, finally가 다르네요.
6. yield
- Ruby♦️
# yield
def check_yield
if block_given?
yield puts "block"
else
puts "no block"
end
end
chekc_yield
chekc_yield {"block"}
puts "------------------------"
#파라미터가 있는 yield
def check_yield_with_param(item)
puts "before yield"
yield(item)
puts "after yield"
end
check_yield_with_param("block") { |item| puts "#{item}" }
|
cs |
- Python🐍
def check_yield():
yield print("block")
return '더이상 호출 할게 없음'
try:
check_yield = check_yield()
next(check_yield)
next(check_yield)
except StopIteration as e:
print(e)
|
cs |
yield 키워드를 python을 사용하면서 많이 사용해보진 않았는데요. 제너레이터를 만들 때 사용합니다. 둘 다 비슷하긴 한데 ruby의 경우 내부에 yield가 있는 경우 block을 공급해야 한다고 합니다. 그리고 block_given? 메서드로 block이 공급되었는지도 확인 가능합니다.
# yield
def check_yield
if block_given?
yield puts "block"
end
yield
end
check_yield
|
cs |
block을 전달하지 않고 yield를 만나게 되면 이렇게 오류가 나옵니다.
👋 마치며
이번 포스팅에서는 python, ruby의 함수, 클래스, 상속, 예외처리 등에 대해 비교해봤습니다. 좀 더 깊게 파고들면 더 많은 내용을 알아야 하지만, 일단 가볍게 비교해 보기만 했습니다.
python, ruby를 비교해보면서 두 언어가 비슷한 점도 많고 다른 점도 있다고 느꼈습니다. 가장 크게 느낀 점은 python도 매우 간결하고 읽기 쉬운 코드를 지향하지만 ruby는 좀 더 간결한 문법을 지향하는 것 같습니다.
특히 user_score.select { |k| k.size == 4 }와 같은 select와 익명 함수를 이용한 문법은 python보다 더 간결하게 로직을 구현할 수 있다는 점이 인상 깊었습니다.
그럼 오늘도 좋은 하루 보내시길 바랍니다!