함수, 메서드를 작성할 때 대부분의 경우 매개변수의 개수를 명확히 지정해준다.

하지만 때로는 내가 작성한 함수의 인자로 몇 개가 입력될지 모를 때가 있다.

그럴 때는 매개변수에 *를 붙이면 여러 개의 입력값(인자)을 하나의 튜플로 받을 수 있다.

이러한 함수를 가변인자함수라고한다.

def print_animal(*args):	
    for name in args:				#for문을 이용해 튜플의 모든 내용 출력
        print(name,end=' ');

    print();

print_animal('dog','cat','lion');	#튜플('dog','cat','lion')를 인자로 전달
print_animal('tiger','cat');		#튜플('tiger','cat')를 인자로 전달

>>dog cat lion 
>>tiger cat 

(*매개변수)를 마지막에만 작성해주면 그 앞에 다른 매개변수를 포함해도 함수는 정상적으로 작동된다.

def print_animal(num,*args):
    print(num,end=' ');
    for name in args:
        print(name,end=' ');

    print();

print_animal(3,'dog','cat','lion');
print_animal(2,'tiger','cat');

>>3 dog cat lion 
>>2 tiger cat 

위의 예제에서는 함수의 인자를 위치 인자(Positional arguments)로 전달했지만 아래와 같이 키워드 인자(keyword arguments)를 전달받는 가변인자함수도 생성이 가능하다.

def print_animal(**kwargs):		# 매개변수의 이름앞에(**)를 붙여준다.
   print(kwargs)			#딕셔너리 형태로 전달받는다.
   for x in kwargs:
       print(kwargs[x])

print_animal(a='cat',b='dog',c='lion')

>>{'a': 'cat', 'b': 'dog', 'c': 'lion'}	#딕셔너리 형태로 전달받는다.
>>cat
>>dog
>>lion

위의 두 예시를 함께 사용할 수도 있다.

단, 위치 인자가 키워드 인자보다 항상 앞에 위치해야 된다.

def print_animal(*args,**kwargs):
    print(args)
    print(kwargs)
  

print_animal('tiger','rabbit',a='cat',b='dog',c='lion')

>>('tiger', 'rabbit')
>>{'a': 'cat', 'b': 'dog', 'c': 'lion'}

'Python' 카테고리의 다른 글

Python - mutable객체, immutable객체  (0) 2020.08.22
Python - 빠른 입력  (0) 2020.08.17
Python - 예외처리  (0) 2020.08.10
Python - 클래스(Class)와 객체(Object)  (0) 2020.08.09
Python - 컬렉션 정리  (0) 2020.08.04

프로그램을 작성하다 보면 수많은 오류가 발생한다.

파이썬에서는 try, except, finally문을 이용해 실행 시 발생할 수 있는 오류들에 대한 예외처리를 할 수 있다.

try:
	오류가 발생할 수 있는 코드
except:
	예외 처리
finally:
	오류와 상관없이 항상 실행되는 코드

 

다른 수를 0으로 나누면 발생하는 오류인 ZeroDivisionError를 예시로 들겠다.

print(1/0);

>>Traceback (most recent call last):
  File ".............................................", line 1, in <module>
    print(1/0);
ZeroDivisionError: division by zero

 

 

예외처리를 하기 위해서는 먼저 오류가 발생할 수 있는 코드를 try 키워드 내에 작성해준다.

이후 해당 오류를 except 뒤에 표시한 뒤 오류를 처리하는 코드를 except 키워드 내에 작성해준다.

try:
    print(1/0);
except ZeroDivisionError:
    print("0으로는 나눌 수 없습니다.");
    
>>0으로는 나눌 수 없습니다.

 

 

파이썬이 생성하는 오류 메시지도 직접 전달받을 수 있다.

try:
    print(1/0);
except ZeroDivisionError as e:
    print(e);
    
>>division by zero

 

 

except문은 여러개 작성 가능하다.

try:
    x=[0];
    print(x[3]);
except ZeroDivisionError as e:
    print(e);
except IndexError as e:			#존재하지않는 인덱스 참조
    print(e);
    
    
>>list index out of range

 

 

finally문 내에 작성한 코드는 오류가 발생하든 발생하지 않든 무조건 실행된다.

try:
    print(1/0);
except ZeroDivisionError:
    print("0으로는 나눌 수 없습니다.");
finally:
    print("finally~");
    
>>0으로는 나눌 수 없습니다.
>>finally~

 

 

오류 발생시키기


파이썬에서는 raise문을 이용해 원하는 타입의 오류를 발생시킬 수 있다.

Ex) 상속받는 클래스에게 메서드 오버라이딩(재정의)를 강제하고 싶을 때.

class A:
    def play(self):
        raise NotImplementedError;		#꼭 작성해야하는 부분을 구현하지 않았을때 발생시키는 오류

class B(A):
    pass;

b=B();
print(b.play());


>>Traceback (most recent call last):
  File "............................................", line 9, in <module>
    print(b.play());
  File "............................................", line 3, in play
    raise NotImplementedError;
NotImplementedError

 

 

에러 클래스를 통해 객체를 생성하면 출력 시에 에러 메시지도 함께 출력할 수 있다.

raise IndexError("인덱스 에러")

>>Traceback (most recent call last):
  File "...................................", line 1, in <module>
    raise IndexError("인덱스 에러")
IndexError: 인덱스 에러

 

 

 

 

 

조건의 참 거짓으로 에러를 발생시키고 싶다면 assert문을 사용할 수도 있다.

x=1
assert x!=1, "x는 1입니다"		#assert <<조건>>, <<에러메시지>>

>>Traceback (most recent call last):
  File "..................................", line 2, in <module>
    assert x!=1, "x는 1입니다"
AssertionError: x는 1입니다

 

조건이 거짓이면 입력받은 에러메시지와 함께 AssertionError를 발생시킨다.

 

클래스란 관련된 함수와 변수의 모음으로써 "객체"의 구조와 행동을 정의하는 틀이다.

클래스는 class 키워드를 사용하여 작성할 수 있다.

class Book:		#클래스의 네이밍 컨벤션은 CamelCase를 사용.
    pass;		#실행할 코드가 없다는 것을 의미
help(Book);

>>Help on class Book in module __main__:	#help함수를 통해 Book이라는 클래스가 생성된걸 알 수 있다.

class Book(builtins.object)
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)


Process finished with exit code 0

 

사용자는 클래스 내부에 함수를 정의해 객체의 "행동"을 정의할 수 있다.

(클래스 내부의 함수를 메서드라고 한다.)

class Book:
    def read_book(self):	#함수와 다르게 메서드는 항상 첫번째 매개변수로 self를 정의. self는 객체 자신을 의미.
        return "reading....";


x = Book();
print(Book.read_book(x));	#Book의 메서드 사용에 객체 x를 인자로 전달해서 사용
print(x.read_book());		#간편하게 x객체와 . 으로 메서드 사용가능

>>reading....
>>reading....

 

클래스가 객체의 구조와 행동을 정의하는 틀이라고 했으니 이제 클래스의 "생성자"통해 객체를 생성해 보겠다.

class Book:
	pass;

x=Book();	#클래스명() 으로 객체 생성 (타 언어와 다르게 new 키워드가 없다.)

print(isinstance(x,Book));	#isinstance(a, b)는 a가 b의 객체이면 True를 반환해주는 함수

>>True

 

※ Python의 모든 타입(사용자가 생성한 클래스 포함)은 Object 클래스를 상속받는다. 
   (모든 타입은 Object 클래스의 모든 속성을 가지고 있고 재정의할 수 있다.)

class Book:
	pass;

print(isinstance(Book,object));
print(isinstance(str,object));

>>True
>>True
class Book:
   pass;
print(dir(Book));
print(dir(object));


>>['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

#Book클래스의 __dict__, __weakref__, __module__을 제외하고 모두 같은 것을 볼 수 있다.

클래스 내의 변수는 객체변수와 클래스 변수로 나뉜다.

객체 변수란 각 객체마다 가지고 있는 고유한 변수로서 다른 객체로부터 영향을 받지 않는 변수이다.

클래스 변수는 클래스로 만든 모든 객체들끼리 공유하는 변수이다.

 

객체 변수를 생성하기 위해서는 object 클래스로부터 상속받은 __init__ 메서드를 재정의 하면 된다.

class Book:
   def __init__(self,name:str,number:int):		#매개변수로 초기화할 값 전달받는다.
       self._name=name;							#self를 이용해 객체변수 생성 및 초기화
       self._number=number;

x=Book("Python Book","1234");
y=Book("C++ Book","5678");
y._name="Java Book";
print(x._name);
print(y._name);

>>Python Book			#y객체를 생성,변경해도 x객체의 객체변수는 바뀌지않는다.
>>Java Book				

 

클래스 변수를 생성하기 위해서는 메서드와 같이 class 키워드 내에 변수를 생성하면 된다.

class Book:
    name="Python Book";

x=Book();
y=Book();
print(x.name);				#모든 객체가 클래스변수를 공유하는 것을 볼 수 있다.
print(y.name,end='\n\n');

Book.name="Java Book";		#<클래스명>.<클래스변수>를 변경(모든 객체의 클래스변수 변경)
print(x.name);				
print(y.name,end='\n\n');

x.name="C++ Book";			#<객체명>.<클래스변수>변경(해당 객체의 클래스변수 변경)
print(x.name);
print(y.name,end='\n\n');



>>Python Book
>>Python Book

>>Java Book
>>Java Book

>>C++ Book
>>Java Book

Python은 생성자로 객체 생성을 호출받으면 먼저 __new__를 호출하여 객체를 생성할당하고, __new__메서드가 __init__메서드를 호출하여 객체에서 사용할 초기값들을 초기화하게 된다.

 

출처: wikidocs.net

 

 

object클래스의 __str__메서드를 재정의하여 print함수를 이용했을 때의 출력 형식을 바꿀 수 있다.

class Book:
   def __init__(self,name:str,number:int):
       self._name=name;
       self._number=number;

x=Book("Python Book","1234");
print(x);

>><__main__.Book object at 0x000001B105CC8A90>

 

class Book:
    def __init__(self,name:str,number:int):
       self._name=name;
       self._number=number;

    def __str__(self):
        return "Name:{}\nNumber:{}".format(self._name,self._number);

x=Book("Python Book","1234");
print(x);

>>Name:Python Book
  Number:1234

위와 같이 생성자와 메서드 정의, 메서드 재정의를 통해 클래스를 정의하고 객체를 생성할 수 있다.

복잡한 구조의 프로그램일수록 클래스를 많이 사용하여 불필요한 코드를 줄이고 가독성을 높이자.

'Python' 카테고리의 다른 글

Python - 함수 인자의 개수를 알 수 없을 때  (0) 2020.08.11
Python - 예외처리  (0) 2020.08.10
Python - 컬렉션 정리  (0) 2020.08.04
Python - 딕셔너리 키(key), 값(value) 도치  (0) 2020.08.04
Python - with 문  (0) 2020.08.01

+ Recent posts