enumerate

  • 리스트가 있는 경우 순서와 리스트의 값을 전달하는 기능을 하는 파이썬 내장함수
  • 순서가 있는 자료형(list, set, tuple, dictionary, string)을 입력으로 받아 인덱스 값을 포함하는 enumerate 객체를 리턴

enumerate 예제

names = ['철수', '영희', '영수']
for i, name in enumerate(names):
    print('{}번: {}'.format(i + 1, name))
결과값
1번: 철수
2번: 영희
3번: 영수

 

'Python' 카테고리의 다른 글

파이썬 소켓 프로그램 만들기  (0) 2022.04.20
Python - Virtual Environments and Packages  (0) 2022.01.06
Python - 표준라이브러리 II  (0) 2022.01.06
Python - 오류 및 예외  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06

 

 

소켓과 소켓 API는 네트워크를 통해 메시지를 보내는 데 사용됩니다. IPC(프로세스 간 통신) 형식을 제공합니다 . 네트워크는 컴퓨터에 대한 논리적 로컬 네트워크이거나 다른 네트워크에 대한 자체 연결을 통해 외부 네트워크에 물리적으로 연결된 네트워크일 수 있습니다. ISP를 통해 연결하는 인터넷을 생각하면 됩니다.

 

본 문서에서는 다음을 만듭니다.

  • 간단한 소켓 서버 및 클라이언트
  • 여러 연결 을 동시에 처리하는 개선된 버전
  • 완전한 소켓 애플리케이션 처럼 작동하는 서버-클라이언트 애플리케이션

본 문서의 예제에는 Python 3.6 이상이 필요하며 Python 3.10을 사용하여 테스트되었습니다.

소스 코드 가져오기: 여기를 클릭 하여 이 자습서의 예제에 사용할 소스 코드를 다운로드합니다 .

배경

소켓은 오랜 역사를 가지고 있습니다. 1971년 ARPANET 에서 시작되었으며 나중에 Berkeley 소켓 이라고 하는 1983년에 출시된 BSD(Berkeley Software Distribution) 운영 체제의 API가 되었습니다 .

가장 일반적인 유형의 소켓 응용 프로그램은 한쪽이 서버 역할을 하고 클라이언트의 연결을 기다리는 클라이언트-서버 응용 프로그램입니다. 

 

소켓 API 개요

Python의 소켓 모듈은 Berkeley 소켓 API 에 대한 인터페이스를 제공합니다.

이 모듈의 기본 소켓 API 함수 및 메서드는 다음과 같습니다.

  • socket()
  • .bind()
  • .listen()
  • .accept()
  • .connect()
  • .connect_ex()
  • .send()
  • .recv()
  • .close()

Python은 C 대응 시스템인 시스템 호출에 직접 매핑되는 편리하고 일관된 API를 제공합니다.

표준 라이브러리의 일부로 Python에는 이러한 저수준 소켓 기능을 더 쉽게 사용할 수 있는 클래스도 있습니다.또한 HTTP 및 SMTP와 같은 상위 수준 인터넷 프로토콜을 구현하는 많은 모듈이 있습니다.

TCP 소켓

소켓 유형을 socket.SOCK_STREAM로 지정 하여 socket.socket()를 사용하여 소켓 객체를 생성합니다. 이 때 사용되는 기본 프로토콜은 TCP(Transmission Control Protocol) 입니다.

왜 TCP를 사용해야 합니까? 전송 제어 프로토콜(TCP):

  • 신뢰할 수 있음: 네트워크에 드롭된 패킷이 발신자에 의해 감지되고 재전송됩니다.
  • 순서대로 데이터 전달 있음: 데이터는 발신자가 작성한 순서대로 애플리케이션에서 읽습니다.

대조적으로 로 생성된 UDP(사용자 데이터그램 프로토콜) 소켓 socket.SOCK_DGRAM은 신뢰할 수 없으며 수신자가 읽는 데이터는 보낸 사람의 쓰기 순서가 다를 수 있습니다.

 

TCP에 대한 소켓 API 호출 및 데이터 흐름의 순서

클라이언트 .connect()는 서버에 대한 연결을 설정하고 3방향 핸드셰이크를 시작하기 위해 호출합니다. 핸드셰이크 단계는 네트워크에서 연결의 각 측면에 도달할 수 있도록 하기 때문에 중요합니다. 즉, 클라이언트가 서버에 도달할 수 있고 그 반대의 경우도 마찬가지입니다. 하나의 호스트, 클라이언트 또는 서버만 다른 호스트에 연결할 수 있습니다.

.send() 와 .recv()에 대한 호출을 사용하여 클라이언트 와 서버 간에 데이터가 교환되는 왕복 섹션이 있습니다.

맨 아래에서 클라이언트와 서버는 각각의 소켓을 닫습니다.

 

 

Echo Client and Server

클라이언트와 서버 프로그램을 작성합니다.

클라이언트에게 수신한 내용을 출력하는 서버 프로그램을 작성합니다.

 

Echo Server

서버 프로그램

# echo-server.py

import socket

HOST = "127.0.0.1"  # Standard loopback interface address (localhost)
PORT = 65432  # Port to listen on (non-privileged ports are > 1023)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((HOST, PORT))
    s.listen()
    conn, addr = s.accept()
    with conn:
        print(f"Connected by {addr}")
        while True:
            data = conn.recv(1024)
            if not data:
                break
            conn.sendall(data)

socket.socket()는 컨텍스트 관리자 유형을 지원하는 소켓을 생성하므로 with명령문 에서 사용할 수 있습니다.

s.close() 를 호출할 필요가 없습니다.

 

.bind()메서드는 소켓을 특정 네트워크 인터페이스 및 포트번호와 연결하는 데 사용됩니다.

서버 예에서 .listen()서버가 연결을 수락할 수 있도록 합니다. 서버를 "수신" 소켓으로 만듭니다.

 

.accept(). 는 클라이언트와 통신하는 데 사용할 소켓입니다. 서버가 새 연결을 수락하는 데 사용하는 수신 소켓과 다릅니다.

 

에코 클라이언트

이제 클라이언트를 살펴보겠습니다.

# echo-client.py

import socket

HOST = "127.0.0.1"  # The server's hostname or IP address
PORT = 65432  # The port used by the server

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((HOST, PORT))
    s.sendall(b"Hello, world")
    data = s.recv(1024)

print(f"Received {data!r}")

.connect()는 소켓 개체를 만들고 서버에 연결하는 데 사용하고, s.sendall()는메시지를 보내기 위해 호출합니다. 마지막으로 s.recv()는 서버의 응답을 읽고 출력하도록 호출합니다 .

 

에코 클라이언트 및 서버 실행

새로운 터미널 또는 명령 프롬프트를 열고 echo-server.py 스크립트가 포함된 디렉터리로 이동하여 서버를 실행합니다.

$ python echo-server.py

클라이언트 연결을 기다리고 있습니다. 이제 다른 터미널 창이나 명령 프롬프트를 열고 클라이언트를 실행합니다.

$ python echo-client.py 
Received b'Hello, world'

서버 창에서 아래 내용을 확인할 수 있습니다.

$ python echo-server.py 
Connected by ('127.0.0.1', 64623)

소켓 상태 보기

호스트에서 소켓의 현재 상태를 보려면 netstat를 사용합니다,

다음은 netstat 출력입니다.

$ netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q  Local Address          Foreign Address        (state)
tcp4       0      0  127.0.0.1.65432        *.*                    LISTEN

 

 

'Python' 카테고리의 다른 글

파이썬 - enumerate  (0) 2023.03.29
Python - Virtual Environments and Packages  (0) 2022.01.06
Python - 표준라이브러리 II  (0) 2022.01.06
Python - 오류 및 예외  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06

 

12. Virtual Environments and Packages

12.1. Introduction

Python applications will often use packages and modules that don’t come as part of the standard library. Applications will sometimes need a specific version of a library, because the application may require that a particular bug has been fixed or the application may be written using an obsolete version of the library’s interface.

This means it may not be possible for one Python installation to meet the requirements of every application. If application A needs version 1.0 of a particular module but application B needs version 2.0, then the requirements are in conflict and installing either version 1.0 or 2.0 will leave one application unable to run.

The solution for this problem is to create a virtual environment, a self-contained directory tree that contains a Python installation for a particular version of Python, plus a number of additional packages.

Different applications can then use different virtual environments. To resolve the earlier example of conflicting requirements, application A can have its own virtual environment with version 1.0 installed while application B has another virtual environment with version 2.0. If application B requires a library be upgraded to version 3.0, this will not affect application A’s environment.

12.2. Creating Virtual Environments

The module used to create and manage virtual environments is called venvvenv will usually install the most recent version of Python that you have available. If you have multiple versions of Python on your system, you can select a specific Python version by running python3 or whichever version you want.

To create a virtual environment, decide upon a directory where you want to place it, and run the venv module as a script with the directory path:

python3 -m venv tutorial-env

This will create the tutorial-env directory if it doesn’t exist, and also create directories inside it containing a copy of the Python interpreter and various supporting files.

A common directory location for a virtual environment is .venv. This name keeps the directory typically hidden in your shell and thus out of the way while giving it a name that explains why the directory exists. It also prevents clashing with .env environment variable definition files that some tooling supports.

Once you’ve created a virtual environment, you may activate it.

On Windows, run:

tutorial-env\Scripts\activate.bat

On Unix or MacOS, run:

source tutorial-env/bin/activate

(This script is written for the bash shell. If you use the csh or fish shells, there are alternate activate.csh and activate.fish scripts you should use instead.)

Activating the virtual environment will change your shell’s prompt to show what virtual environment you’re using, and modify the environment so that running python will get you that particular version and installation of Python. For example:

$ source ~/envs/tutorial-env/bin/activate
(tutorial-env) $ python
Python 3.5.1 (default, May  6 2016, 10:59:36)
  ...
>>> import sys
>>> sys.path
['', '/usr/local/lib/python35.zip', ...,
'~/envs/tutorial-env/lib/python3.5/site-packages']
>>>

12.3. Managing Packages with pip

You can install, upgrade, and remove packages using a program called pip. By default pip will install packages from the Python Package Index, <https://pypi.org>. You can browse the Python Package Index by going to it in your web browser.

pip has a number of subcommands: “install”, “uninstall”, “freeze”, etc. (Consult the Installing Python Modules guide for complete documentation for pip.)

You can install the latest version of a package by specifying a package’s name:

(tutorial-env) $ python -m pip install novas
Collecting novas
  Downloading novas-3.1.1.3.tar.gz (136kB)
Installing collected packages: novas
  Running setup.py install for novas
Successfully installed novas-3.1.1.3

You can also install a specific version of a package by giving the package name followed by == and the version number:

(tutorial-env) $ python -m pip install requests==2.6.0
Collecting requests==2.6.0
  Using cached requests-2.6.0-py2.py3-none-any.whl
Installing collected packages: requests
Successfully installed requests-2.6.0

If you re-run this command, pip will notice that the requested version is already installed and do nothing. You can supply a different version number to get that version, or you can run pip install --upgrade to upgrade the package to the latest version:

(tutorial-env) $ python -m pip install --upgrade requests
Collecting requests
Installing collected packages: requests
  Found existing installation: requests 2.6.0
    Uninstalling requests-2.6.0:
      Successfully uninstalled requests-2.6.0
Successfully installed requests-2.7.0

pip uninstall followed by one or more package names will remove the packages from the virtual environment.

pip show will display information about a particular package:

(tutorial-env) $ pip show requests
---
Metadata-Version: 2.0
Name: requests
Version: 2.7.0
Summary: Python HTTP for Humans.
Home-page: http://python-requests.org
Author: Kenneth Reitz
Author-email: me@kennethreitz.com
License: Apache 2.0
Location: /Users/akuchling/envs/tutorial-env/lib/python3.4/site-packages
Requires:

pip list will display all of the packages installed in the virtual environment:

(tutorial-env) $ pip list
novas (3.1.1.3)
numpy (1.9.2)
pip (7.0.3)
requests (2.7.0)
setuptools (16.0)

pip freeze will produce a similar list of the installed packages, but the output uses the format that pip install expects. A common convention is to put this list in a requirements.txt file:

(tutorial-env) $ pip freeze > requirements.txt
(tutorial-env) $ cat requirements.txt
novas==3.1.1.3
numpy==1.9.2
requests==2.7.0

The requirements.txt can then be committed to version control and shipped as part of an application. Users can then install all the necessary packages with install -r:

(tutorial-env) $ python -m pip install -r requirements.txt
Collecting novas==3.1.1.3 (from -r requirements.txt (line 1))
  ...
Collecting numpy==1.9.2 (from -r requirements.txt (line 2))
  ...
Collecting requests==2.7.0 (from -r requirements.txt (line 3))
  ...
Installing collected packages: novas, numpy, requests
  Running setup.py install for novas
Successfully installed novas-3.1.1.3 numpy-1.9.2 requests-2.7.0

pip has many more options. Consult the Installing Python Modules guide for complete documentation for pip. When you’ve written a package and want to make it available on the Python Package Index, consult the Distributing Python Modules guide.

'Python' 카테고리의 다른 글

파이썬 - enumerate  (0) 2023.03.29
파이썬 소켓 프로그램 만들기  (0) 2022.04.20
Python - 표준라이브러리 II  (0) 2022.01.06
Python - 오류 및 예외  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06

참고 : https://docs.python.org/3/tutorial/stdlib2.html

This second tour covers more advanced modules that support professional programming needs. These modules rarely occur in small scripts.

11.1. Output Formatting

The reprlib module provides a version of repr() customized for abbreviated displays of large or deeply nested containers:

>>>
>>> import reprlib
>>> reprlib.repr(set('supercalifragilisticexpialidocious'))
"{'a', 'c', 'd', 'e', 'f', 'g', ...}"

The pprint module offers more sophisticated control over printing both built-in and user defined objects in a way that is readable by the interpreter. When the result is longer than one line, the “pretty printer” adds line breaks and indentation to more clearly reveal data structure:

>>>
>>> import pprint
>>> t = [[[['black', 'cyan'], 'white', ['green', 'red']], [['magenta',
...     'yellow'], 'blue']]]
...
>>> pprint.pprint(t, width=30)
[[[['black', 'cyan'],
   'white',
   ['green', 'red']],
  [['magenta', 'yellow'],
   'blue']]]

The textwrap module formats paragraphs of text to fit a given screen width:

>>>
>>> import textwrap
>>> doc = """The wrap() method is just like fill() except that it returns
... a list of strings instead of one big string with newlines to separate
... the wrapped lines."""
...
>>> print(textwrap.fill(doc, width=40))
The wrap() method is just like fill()
except that it returns a list of strings
instead of one big string with newlines
to separate the wrapped lines.

The locale module accesses a database of culture specific data formats. The grouping attribute of locale’s format function provides a direct way of formatting numbers with group separators:

>>>
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'English_United States.1252')
'English_United States.1252'
>>> conv = locale.localeconv()          # get a mapping of conventions
>>> x = 1234567.8
>>> locale.format("%d", x, grouping=True)
'1,234,567'
>>> locale.format_string("%s%.*f", (conv['currency_symbol'],
...                      conv['frac_digits'], x), grouping=True)
'$1,234,567.80'

11.2. Templating

The string module includes a versatile Template class with a simplified syntax suitable for editing by end-users. This allows users to customize their applications without having to alter the application.

The format uses placeholder names formed by $ with valid Python identifiers (alphanumeric characters and underscores). Surrounding the placeholder with braces allows it to be followed by more alphanumeric letters with no intervening spaces. Writing $$ creates a single escaped $:

>>>
>>> from string import Template
>>> t = Template('${village}folk send $$10 to $cause.')
>>> t.substitute(village='Nottingham', cause='the ditch fund')
'Nottinghamfolk send $10 to the ditch fund.'

The substitute() method raises a KeyError when a placeholder is not supplied in a dictionary or a keyword argument. For mail-merge style applications, user supplied data may be incomplete and the safe_substitute() method may be more appropriate — it will leave placeholders unchanged if data is missing:

>>>
>>> t = Template('Return the $item to $owner.')
>>> d = dict(item='unladen swallow')
>>> t.substitute(d)
Traceback (most recent call last):
  ...
KeyError: 'owner'
>>> t.safe_substitute(d)
'Return the unladen swallow to $owner.'

Template subclasses can specify a custom delimiter. For example, a batch renaming utility for a photo browser may elect to use percent signs for placeholders such as the current date, image sequence number, or file format:

>>>
>>> import time, os.path
>>> photofiles = ['img_1074.jpg', 'img_1076.jpg', 'img_1077.jpg']
>>> class BatchRename(Template):
...     delimiter = '%'
>>> fmt = input('Enter rename style (%d-date %n-seqnum %f-format):  ')
Enter rename style (%d-date %n-seqnum %f-format):  Ashley_%n%f

>>> t = BatchRename(fmt)
>>> date = time.strftime('%d%b%y')
>>> for i, filename in enumerate(photofiles):
...     base, ext = os.path.splitext(filename)
...     newname = t.substitute(d=date, n=i, f=ext)
...     print('{0} --> {1}'.format(filename, newname))

img_1074.jpg --> Ashley_0.jpg
img_1076.jpg --> Ashley_1.jpg
img_1077.jpg --> Ashley_2.jpg

Another application for templating is separating program logic from the details of multiple output formats. This makes it possible to substitute custom templates for XML files, plain text reports, and HTML web reports.

11.3. Working with Binary Data Record Layouts

The struct module provides pack() and unpack() functions for working with variable length binary record formats. The following example shows how to loop through header information in a ZIP file without using the zipfile module. Pack codes "H" and "I" represent two and four byte unsigned numbers respectively. The "<" indicates that they are standard size and in little-endian byte order:

import struct

with open('myfile.zip', 'rb') as f:
    data = f.read()

start = 0
for i in range(3):                      # show the first 3 file headers
    start += 14
    fields = struct.unpack('<IIIHH', data[start:start+16])
    crc32, comp_size, uncomp_size, filenamesize, extra_size = fields

    start += 16
    filename = data[start:start+filenamesize]
    start += filenamesize
    extra = data[start:start+extra_size]
    print(filename, hex(crc32), comp_size, uncomp_size)

    start += extra_size + comp_size     # skip to the next header

11.4. Multi-threading

Threading is a technique for decoupling tasks which are not sequentially dependent. Threads can be used to improve the responsiveness of applications that accept user input while other tasks run in the background. A related use case is running I/O in parallel with computations in another thread.

The following code shows how the high level threading module can run tasks in background while the main program continues to run:

import threading, zipfile

class AsyncZip(threading.Thread):
    def __init__(self, infile, outfile):
        threading.Thread.__init__(self)
        self.infile = infile
        self.outfile = outfile

    def run(self):
        f = zipfile.ZipFile(self.outfile, 'w', zipfile.ZIP_DEFLATED)
        f.write(self.infile)
        f.close()
        print('Finished background zip of:', self.infile)

background = AsyncZip('mydata.txt', 'myarchive.zip')
background.start()
print('The main program continues to run in foreground.')

background.join()    # Wait for the background task to finish
print('Main program waited until background was done.')

The principal challenge of multi-threaded applications is coordinating threads that share data or other resources. To that end, the threading module provides a number of synchronization primitives including locks, events, condition variables, and semaphores.

While those tools are powerful, minor design errors can result in problems that are difficult to reproduce. So, the preferred approach to task coordination is to concentrate all access to a resource in a single thread and then use the queue module to feed that thread with requests from other threads. Applications using Queue objects for inter-thread communication and coordination are easier to design, more readable, and more reliable.

11.5. Logging

The logging module offers a full featured and flexible logging system. At its simplest, log messages are sent to a file or to sys.stderr:

import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found', 'server.conf')
logging.error('Error occurred')
logging.critical('Critical error -- shutting down')

This produces the following output:

WARNING:root:Warning:config file server.conf not found
ERROR:root:Error occurred
CRITICAL:root:Critical error -- shutting down

By default, informational and debugging messages are suppressed and the output is sent to standard error. Other output options include routing messages through email, datagrams, sockets, or to an HTTP Server. New filters can select different routing based on message priority: DEBUG, INFO, WARNING, ERROR, and CRITICAL.

The logging system can be configured directly from Python or can be loaded from a user editable configuration file for customized logging without altering the application.

11.6. Weak References

Python does automatic memory management (reference counting for most objects and garbage collection to eliminate cycles). The memory is freed shortly after the last reference to it has been eliminated.

This approach works fine for most applications but occasionally there is a need to track objects only as long as they are being used by something else. Unfortunately, just tracking them creates a reference that makes them permanent. The weakref module provides tools for tracking objects without creating a reference. When the object is no longer needed, it is automatically removed from a weakref table and a callback is triggered for weakref objects. Typical applications include caching objects that are expensive to create:

>>>
>>> import weakref, gc
>>> class A:
...     def __init__(self, value):
...         self.value = value
...     def __repr__(self):
...         return str(self.value)
...
>>> a = A(10)                   # create a reference
>>> d = weakref.WeakValueDictionary()
>>> d['primary'] = a            # does not create a reference
>>> d['primary']                # fetch the object if it is still alive
10
>>> del a                       # remove the one reference
>>> gc.collect()                # run garbage collection right away
0
>>> d['primary']                # entry was automatically removed
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
    d['primary']                # entry was automatically removed
  File "C:/python310/lib/weakref.py", line 46, in __getitem__
    o = self.data[key]()
KeyError: 'primary'

11.7. Tools for Working with Lists

Many data structure needs can be met with the built-in list type. However, sometimes there is a need for alternative implementations with different performance trade-offs.

The array module provides an array() object that is like a list that stores only homogeneous data and stores it more compactly. The following example shows an array of numbers stored as two byte unsigned binary numbers (typecode "H") rather than the usual 16 bytes per entry for regular lists of Python int objects:

>>>
>>> from array import array
>>> a = array('H', [4000, 10, 700, 22222])
>>> sum(a)
26932
>>> a[1:3]
array('H', [10, 700])

The collections module provides a deque() object that is like a list with faster appends and pops from the left side but slower lookups in the middle. These objects are well suited for implementing queues and breadth first tree searches:

>>>
>>> from collections import deque
>>> d = deque(["task1", "task2", "task3"])
>>> d.append("task4")
>>> print("Handling", d.popleft())
Handling task1
unsearched = deque([starting_node])
def breadth_first_search(unsearched):
    node = unsearched.popleft()
    for m in gen_moves(node):
        if is_goal(m):
            return m
        unsearched.append(m)

In addition to alternative list implementations, the library also offers other tools such as the bisect module with functions for manipulating sorted lists:

>>>
>>> import bisect
>>> scores = [(100, 'perl'), (200, 'tcl'), (400, 'lua'), (500, 'python')]
>>> bisect.insort(scores, (300, 'ruby'))
>>> scores
[(100, 'perl'), (200, 'tcl'), (300, 'ruby'), (400, 'lua'), (500, 'python')]

The heapq module provides functions for implementing heaps based on regular lists. The lowest valued entry is always kept at position zero. This is useful for applications which repeatedly access the smallest element but do not want to run a full list sort:

>>>
>>> from heapq import heapify, heappop, heappush
>>> data = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0]
>>> heapify(data)                      # rearrange the list into heap order
>>> heappush(data, -5)                 # add a new entry
>>> [heappop(data) for i in range(3)]  # fetch the three smallest entries
[-5, 0, 1]

11.8. Decimal Floating Point Arithmetic

The decimal module offers a Decimal datatype for decimal floating point arithmetic. Compared to the built-in float implementation of binary floating point, the class is especially helpful for

  • financial applications and other uses which require exact decimal representation,
  • control over precision,
  • control over rounding to meet legal or regulatory requirements,
  • tracking of significant decimal places, or
  • applications where the user expects the results to match calculations done by hand.

For example, calculating a 5% tax on a 70 cent phone charge gives different results in decimal floating point and binary floating point. The difference becomes significant if the results are rounded to the nearest cent:

>>>
>>> from decimal import *
>>> round(Decimal('0.70') * Decimal('1.05'), 2)
Decimal('0.74')
>>> round(.70 * 1.05, 2)
0.73

The Decimal result keeps a trailing zero, automatically inferring four place significance from multiplicands with two place significance. Decimal reproduces mathematics as done by hand and avoids issues that can arise when binary floating point cannot exactly represent decimal quantities.

Exact representation enables the Decimal class to perform modulo calculations and equality tests that are unsuitable for binary floating point:

>>>
>>> Decimal('1.00') % Decimal('.10')
Decimal('0.00')
>>> 1.00 % 0.10
0.09999999999999995

>>> sum([Decimal('0.1')]*10) == Decimal('1.0')
True
>>> sum([0.1]*10) == 1.0
False

The decimal module provides arithmetic with as much precision as needed:

>>>
>>> getcontext().prec = 36
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857')

'Python' 카테고리의 다른 글

파이썬 소켓 프로그램 만들기  (0) 2022.04.20
Python - Virtual Environments and Packages  (0) 2022.01.06
Python - 오류 및 예외  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06
Python - module  (0) 2022.01.06

오류 메시지는 두 종류의 오류 즉, 구문 오류  예외가 있습니다

8.1. 구문 오류 

구문 분석 오류라고도 하는 구문 오류는 Python을 다루는 동안 발생하는 가장 일반적인 유형입니다.

>>>
while True print('Hello world')

  File "hello.py", line 1
    while True print('Hello world')
               ^^^^^
SyntaxError: invalid syntax

파서는 문제가 되는 줄을 감지하고 오류를 가리키는 작은 '화살표'를 표시합니다. 오류는 화살표 앞 의 토큰에 의해 발생합니다(또는 적어도 감지됨). 예제에서 오류는 while 구문에 콜론( ':')이 없기 때문에 오류가 감지됩니다 . 파일 이름과 줄 번호가 출력되어 어디를 봐야 하는지 알 수 있습니다.

8.2. Exceptions

문장이나 표현이 문법적으로 올바르더라도 실행을 면 오류가 발생할 수 있습니다. 실행 중에 감지된 오류를 예외 라고 합니다. 대부분의 예외는 프로그램에서 처리되지 않으며 다음과 같은 오류 메시지가 표시됩니다.

>>>
>>> 10 * (1/0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "int") to str

오류 메시지의 마지막 줄은 무슨 일이 일어났는지 나타냅니다. 예외는 다양한 유형으로 제공되며 유형은 메시지의 일부로 출력됩니다. 예제의 유형은 ZeroDivisionErrorNameError및 TypeError입니다. 예외 유형으로 인쇄된 문자열은 발생한 내장 예외의 이름입니다. 표준 예외 이름은 기본 제공 식별자(예약 키워드 아님)입니다.

행의 나머지 부분은 예외 유형과 원인에 따라 세부 정보를 보여줍니다.

오류 메시지의 앞부분은 예외가 발생한 컨텍스트를 스택 역추적 형태로 보여줍니다. 일반적으로 소스 라인을 나열하는 스택 역추적을 포함합니다. 그러나 표준 입력에서 읽은 행은 표시하지 않습니다.

기본 제공 예외 는 기본 제공 예외와 해당 의미를 나열합니다.

8.3. 예외 처리 

선택된 예외를 처리하는 프로그램을 작성할 수 있습니다. 유효한 정수가 입력될 때까지 사용자에게 입력을 요청하지만 사용자가 프로그램을 중단할 수 있도록 허용하는 다음 예를 보십시오. 사용자 중단(Control-C)은 예외를 발생시켜 신호(KeyboardInterrupt)를 보냅니다.

Control-C  :  KeyboardInterrupt

>>>
while True:
     try:
         x = int(input("Please enter a number: "))
         break
     except ValueError:
         print("Oops!  That was no valid number.  Try again...")

try다음과 같이 문은 작동합니다.

  • 먼저 try 절 ( try및 except키워드 사이의 문 )이 실행됩니다.
  • 예외가 발생하지 않으면 예외 절 을 건너뛰고 try명령문의 실행 이 종료됩니다.
  • try절을 실행하는 동안 예외가 발생 하면 나머지 절은 건너뜁니다. 그런 다음 해당 유형이 except키워드 이름과 명명된 예외와 일치하면 예외 절이 실행되고 except 블록을 실행합니다.
  • 예외 절에 명명된 예외와 일치하지 않는 예외가 발생 하면 외부 try문으로 전달됩니다 . 핸들러가 발견 되지 않으면 처리되지 않은 예외 이며 위와 같은 메시지와 함께 실행이 중지됩니다.

try문은 하나 이상있을 수 있습니다. try절을 제외한 다른 예외 핸들러를 지정합니다. 최대 하나의 핸들러가 실행됩니다. 핸들러는 동일한 문의 다른 핸들러가 아닌 해당하는 try 절에서 발생하는 예외만 처리합니다. t괄호 안에 여러 예외를 지정할 수있습니다.

... except (RuntimeError, TypeError, NameError):
...     pass

다음 코드는 B, C, D를 순서대로 인쇄합니다.

class B(Exception):
    pass

class C(B):
    pass

class D(C):
    pass

for cls in [B, C, D]:
    try:
        raise cls()
    except D:
        print("D")
    except C:
        print("C")
    except B:
        print("B")

경우주의 조항을 제외하고는 (와 반전 된 첫번째)가 B, B, B를 인쇄 한 것 - 일치하는 첫 번째 절을 제외하고는 트리거됩니다.except B

모든 예외는 에서 상속 BaseException되므로 와일드카드로 사용할 수 있습니다. 이런 식으로 실제 프로그래밍 오류를 마스킹하기 쉽기 때문에 주의해서 사용하십시오! 또한 오류 메시지를 인쇄한 다음 예외를 다시 발생시키는 데 사용할 수도 있습니다(호출자도 예외를 처리할 수 있음).

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except OSError as err:
    print("OS error: {0}".format(err))
except ValueError:
    print("Could not convert data to an integer.")
except BaseException as err:
    print(f"Unexpected {err=}, {type(err)=}")
    raise

또는 마지막 예외 절에서 예외 이름을 생략할 수 있지만 예외 값은 ys.exc_info()에서 검색해야 합니다.

try... except문은 선택이 다른 절 현재, 모두를 따라야합니다, except 절을 . try 절 에서 예외가 발생하지 않는 경우 실행해야 하는 코드에 유용합니다 . 예를 들어:

for arg in sys.argv[1:]:
    try:
        f = open(arg, 'r')
    except OSError:
        print('cannot open', arg)
    else:
        print(arg, 'has', len(f.readlines()), 'lines')
        f.close()

else절을 사용하면 try… except문 으로 보호되는 코드에 의해 발생하지 않은 예외를 실수로 catch하지 않는 경우를 예방합니다

예외가 발생하면 예외의 인수라고 하는 값이 있을 수 있습니다 . 인수의 존재와 유형은 예외 유형에 따라 다릅니다.

절을 제외하고는 예외 이름 뒤에 변수를 지정할 수 있습니다. 변수는 instance.args에 저장된 인수를 사용하여 예외 인스턴스에 바인딩됩니다. 편의를 위해 예외 인스턴스는 __str__()참조하지 않고도 인수를 직접 인쇄할 수 있도록 정의합니다 .args. 예외를 발생시키기 전에 먼저 예외를 인스턴스화하고 원하는 대로 속성을 추가할 수도 있습니다.

>>>
>>> try:
...     raise Exception('spam', 'eggs')
... except Exception as inst:
...     print(type(inst))    # the exception instance
...     print(inst.args)     # arguments stored in .args
...     print(inst)          # __str__ allows args to be printed directly,
...                          # but may be overridden in exception subclasses
...     x, y = inst.args     # unpack args
...     print('x =', x)
...     print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs

예외에 인수가 있는 경우 처리되지 않은 예외에 대한 메시지의 마지막 부분('detail')으로 인쇄됩니다.

예외가 즉시 발생하는 경우 예외 핸들러는 예외를 처리하지 않는 시도 절 뿐만 아니라 그들이에서 (심지어 간접적으로)라고 내부 기능 발생하는 경우, 시도 절을 . 예를 들어:

>>>
>>> def this_fails():
...     x = 1/0
...
>>> try:
...     this_fails()
... except ZeroDivisionError as err:
...     print('Handling run-time error:', err)
...
Handling run-time error: division by zero

8.4. 예외 발생 

이 raise명령문을 사용하면 프로그래머가 지정된 예외가 발생하도록 강제할 수 있습니다. 예를 들어:

>>>
raise NameError('HiThere')

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: HiThere

유일한 인수는 발생할 raise예외 를 나타냅니다. 이것은 예외 인스턴스 또는 예외 클래스에서 파생된 클래스여야 합니다. 예외 클래스가 전달되면 인수 없이 생성자를 호출하여 암시적으로 인스턴스화됩니다.

raise ValueError  # shorthand for 'raise ValueError()'

예외가 발생했는지 여부를 확인해야 하지만 처리할 의사가 없는 경우 더 간단한 형식의 raise명령문을 사용하여 예외를 다시 발생시킬 수 있습니다.

>>>
try:
     raise NameError('HiThere')
except NameError:
     print('An exception flew by!')
     raise

An exception flew by!
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
NameError: HiThere

8.5. 예외 체이닝 

이 raise문 from은 연결 예외를 활성화 하는 선택 사항 을 허용합니다 . 예를 들어:

# exc must be exception instance or None.
raise RuntimeError from exc

이것은 예외를 변환할 때 유용할 수 있습니다. 예를 들어:

>>>
>>> def func():
...     raise ConnectionError
...
>>> try:
...     func()
... except ConnectionError as exc:
...     raise RuntimeError('Failed to open database') from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 2, in func
ConnectionError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Failed to open database

except또는 finally섹션 내에서 예외가 발생하면 예외 연결이 자동으로 발생합니다. .from None 관용구를 사용하여 비활성화할 수 있습니다 

>>>
>>> try:
...     open('database.sqlite')
... except OSError:
...     raise RuntimeError from None
...
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError

연결 메커니즘에 대한 자세한 내용은 기본 제공 예외를 참조하세요 .

8.6. 사용자 정의 예외 

프로그램은 새로운 예외 클래스를 생성하여 자체 예외의 이름을 지정할 수 있습니다( Python 클래스에 대한 자세한 내용 은 클래스 참조 ). 예외는 일반적으로 Exception직접 또는 간접적으로 클래스에서 파생되어야 합니다 .

다른 클래스가 할 수 있는 모든 작업을 수행하는 예외 클래스를 정의할 수 있지만 일반적으로 단순하게 유지되며 종종 예외 처리기가 오류에 대한 정보를 추출할 수 있도록 하는 많은 속성만 제공합니다.

대부분의 예외는 표준 예외의 이름 지정과 유사하게 "오류"로 끝나는 이름으로 정의됩니다.

많은 표준 모듈은 정의한 기능에서 발생할 수 있는 오류를 보고하기 위해 자체 예외를 정의합니다. 

8.7. 정리 작업 정의 

try문은 모든 상황에서 실행해야합니다 청소 작업을 정의하기위한 것입니다. 예를 들어:

>>>
try:
     raise KeyboardInterrupt
finally:
     print('Goodbye, world!')

Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>

finally절이 있는 경우 해당 절은 try문이 완료 되기 전에 마지막 작업으로 실행됩니다. 이 finally절은 try명령문이 예외를 생성하는지 여부에 관계없이 실행됩니다 . 다음 사항은 예외가 발생하는 더 복잡한 경우에 대해 설명합니다.

  • try 절 실행 중 예외가 발생하면 절에서 예외를 처리할 수 있습니다. 예외가 except 절에 의해 처리되지 않으면 finally 절이 실행 된 후 예외가 다시 발생합니다 .
  • except or else절을 실행하는 동안 예외가 발생할 수 있습니다 . 다시, finally절이 실행 된 후에 예외가 다시 발생합니다 .
  • if finally절이 실행될 때 breakcontinue또는 return문은 예외가 다시 발생하지 않습니다.
  • IF try문이 도달 breakcontinue또는 return문을의 finally절은 직전에 실행됩니다 .
  • finally절이 포함 return 문을 반환 값의 하나가 될 것입니다 finally조항의 return문이 아닌의 값 try조항의 return 문.

예를 들어:

>>>
>>> def bool_return():
...     try:
...         return True
...     finally:
...         return False
...
>>> bool_return()
False

더 복잡한 예:

>>>
>>> def divide(x, y):
...     try:
...         result = x / y
...     except ZeroDivisionError:
...         print("division by zero!")
...     else:
...         print("result is", result)
...     finally:
...         print("executing finally clause")
...
>>> divide(2, 1)
result is 2.0
executing finally clause
>>> divide(2, 0)
division by zero!
executing finally clause
>>> divide("2", "1")
executing finally clause
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in divide
TypeError: unsupported operand type(s) for /: 'str' and 'str'

보시다시피 finally절은 모든 이벤트에서 실행됩니다. TypeError개의 스트링을 분할함으로써 발생은 처리되지 except절과 후 따라서 레이즈 다시 finally 절 실행되었다.

실제 응용 프로그램에서 이 finally절은 리소스 사용의 성공 여부와 상관없이 외부 리소스(예: 파일 또는 네트워크 연결)를 해제하는 데 유용합니다.

8.8. 사전 정의된 정리 작업 

일부 개체는 개체를 사용한 작업의 성공 여부에 관계없이 개체가 더 이상 필요하지 않을 때 수행할 표준 정리 작업을 정의합니다. 파일을 열고 그 내용을 화면에 인쇄하려고 시도하는 다음 예를 보십시오.

for line in open("myfile.txt"):
    print(line, end="")

이 코드의 문제는 코드의 이 부분이 실행을 완료한 후 불확실한 시간 동안 파일을 열어 둡니다. 이것은 단순한 스크립트에서는 문제가 되지 않지만 더 큰 응용 프로그램에서는 문제가 될 수 있습니다. 이 with명령문을 사용하면 파일과 같은 개체를 항상 신속하고 정확하게 정리할 수 있는 방식으로 사용할 수 있습니다.

with open("myfile.txt") as f:
    for line in f:
        print(line, end="")

명령문이 실행된 후 파일 f 는 라인을 처리하는 동안 문제가 발생하더라도 항상 닫힙니다. 파일과 같이 미리 정의된 정리 작업을 제공하는 개체는 문서에서 이를 나타냅니다.

'Python' 카테고리의 다른 글

Python - Virtual Environments and Packages  (0) 2022.01.06
Python - 표준라이브러리 II  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06
Python - module  (0) 2022.01.06
Python - class  (0) 2022.01.06

프로그램의 출력 표현 방법에는 여러 가지가 있습니다. 사람이 보기에 적합한 형태로 데이터를 인쇄할 수도 있고, 나중에 사용하기 위해 파일에 쓸 수도 있습니다.

7.1. 출력 포매팅

지금까지 우리는 값을 쓰는 두 가지 방법을 만났습니다: 표현식 문장 과 print() 함수입니다. (세 번째 방법은 파일 객체의 write() 메서드를 사용하는 것입니다; 표준 출력 파일은 sys.stdout 로 참조할 수 있습니다. 이것에 대한 자세한 정보는 라이브러리 레퍼런스를 보세요.)

종종 단순히 스페이스로 구분된 값을 인쇄하는 것보다 출력 형식을 더 많이 제어해야 하는 경우가 있습니다. 출력을 포맷하는 데는 여러 가지 방법이 있습니다.

  • 포맷 문자열 리터럴을 사용하려면, 시작 인용 부호 또는 삼중 인용 부호 앞에 f 또는 F 를 붙여 문자열을 시작하십시오. 이 문자열 안에서, { 및 } 문자 사이에, 변수 또는 리터럴 값을 참조할 수 있는 파이썬 표현식을 작성할 수 있습니다.
  • >>>
    year = 2016
    event = 'Referendum'
    
    print(f'Results of the {year} {event}')
    print('Results of the {year} {event}')
    
    ## 실행결과
    Results of the 2016 Referendum
    Results of the {year} {event}
  • 문자열의 str.format() 메서드는 더 많은 수작업을 요구합니다. 변수가 대체 될 위치를 표시하기 위해 { 및 }를 사용하고, 자세한 포매팅 디렉티브를 제공할 수 있지만, 포맷할 정보도 제공해야 합니다.
  • >>>
    yes_votes = 42_572_654
    no_votes = 43_132_495
    percentage = yes_votes / (yes_votes + no_votes)
    
    print('{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage))
    
    ## 실행결과
     42572654 YES votes  49.67%
  • 마지막으로, 문자열 슬라이싱 및 이어붙이기 연산을 사용하여 상상할 수 있는 모든 배치를 만듦으로써, 모든 문자열 처리를 수행할 수 있습니다. 문자열형에는 주어진 열 너비로 문자열을 채우는 데 유용한 연산을 수행하는 몇 가지 메서드가 있습니다.

보기좋은 출력이 필요하지 않고 단지 디버깅을 위해 일부 변수를 빠르게 표시하려면, repr() 또는 str() 함수를 사용하여 모든 값을 문자열로 변환할 수 있습니다.

str() 함수는 어느 정도 사람이 읽기에 적합한 형태로 값의 표현을 돌려주게 되어있습니다. 반면에 repr() 은 인터프리터에 의해 읽힐 수 있는 형태를 만들게 되어있습니다 (또는 그렇게 표현할 수 있는 문법이 없으면 SyntaxError 를 일으키도록 구성됩니다). 사람이 소비하기 위한 특별한 표현이 없는 객체의 경우, str() 는 repr() 과 같은 값을 돌려줍니다. 많은 값, 숫자들이나 리스트와 딕셔너리와 같은 구조들, 은 두 함수를 쓸 때 같은 표현을 합니다. 특별히, 문자열은 두 가지 표현을 합니다.

몇 가지 예를 듭니다:

>>>
>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"

string 모듈에는 문자열에 값을 치환하는 또 다른 방법을 제공하는 Template 클래스가 포함되어 있습니다. $x와 같은 자리 표시자를 사용하고 이것들을 딕셔너리에서 오는 값으로 치환하지만, 포매팅에 기능이 적습니다.

7.1.1. 포맷 문자열 리터럴

포맷 문자열 리터럴(간단히 f-문자열이라고도 합니다)은 문자열에 f 또는 F 접두어를 붙이고 표현식을 {expression}로 작성하여 문자열에 파이썬 표현식의 값을 삽입할 수 있게 합니다.

선택적인 포맷 지정자가 표현식 뒤에 올 수 있습니다. 이것으로 값이 포맷되는 방식을 더 정교하게 제어할 수 있습니다. 다음 예는 원주율을 소수점 이하 세 자리로 반올림합니다.

>>>
import math
print(f'The value of pi is approximately {math.pi:.3f}.')

## 실행결과
The value of pi is approximately 3.142.

':' 뒤에 정수는 해당 필드의 최소 문자 폭이 됩니다. 줄 맞춤할 때 편리합니다.

>>>
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
for name, phone in table.items():
	print(f'{name:10} ==> {phone:10d}')

## 실행결과
Sjoerd     ==>       4127
Jack       ==>       4098
Dcab       ==>       7678

다른 수정자를 사용하면 포맷되기 전에 값을 변환할 수 있습니다. '!a'는 ascii()를, '!s'는 str()을, '!r'는 repr()을 적용합니다.:

>>>
animals = 'eels'
print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.

print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.

이러한 포맷 사양에 대한 레퍼런스는 포맷 명세 미니 언어에 대한 레퍼런스 지침서를 참조하십시오.

7.1.2. 문자열 format() 메서드

str.format() 메서드의 기본적인 사용법은 이런 식입니다:

>>>
print('We are the {} who say "{}!"'.format('knights', 'Ni'))

## 실행결과
We are the knights who say "Ni!"

중괄호와 그 안에 있는 문자들 (포맷 필드라고 부른다) 은 str.format() 메서드로 전달된 객체들로 치환됩니다. 중괄호 안의 숫자는 str.format() 메서드로 전달된 객체들의 위치를 가리키는데 사용될 수 있습니다.

>>>
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam

str.format() 메서드에 키워드 인자가 사용되면, 그 값들은 인자의 이름을 사용해서 지정할 수 있습니다.

>>>
print('This {food} is {adjective}.'.format(food='spam', adjective='absolutely horrible'))

This spam is absolutely horrible.

위치와 키워드 인자를 자유롭게 조합할 수 있습니다:

>>>
print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',other='Georg'))

The story of Bill, Manfred, and Georg.

나누고 싶지 않은 정말 긴 포맷 문자열이 있을 때, 포맷할 변수들을 위치 대신에 이름으로 지정할 수 있다면 좋을 것입니다. 간단히 딕셔너리를 넘기고 키를 액세스하는데 대괄호 '[]' 를 사용하면 됩니다.

>>>
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '	'Dcab: {0[Dcab]:d}'.format(table))

Jack: 4098; Sjoerd: 4127; Dcab: 8637678

〈**〉 표기법을 사용해서 table을 키워드 인자로 전달해도 같은 결과를 얻을 수 있습니다.

>>>
table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))

Jack: 4098; Sjoerd: 4127; Dcab: 8637678

이 방법은 모든 지역 변수들을 담은 딕셔너리를 돌려주는 내장 함수 vars() 와 함께 사용할 때 특히 쓸모가 있습니다.

예를 들어, 다음 줄은 정수와 그 제곱과 세제곱을 제공하는 빽빽하게 정렬된 열 집합을 생성합니다:

>>>
for x in range(1, 11):
	print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))

 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

str.format() 를 사용한 문자열 포매팅의 완전한 개요는 포맷 문자열 문법 을 보세요.

7.1.3. 수동 문자열 포매팅

여기 같은 제곱수와 세제곱수 표를 수동으로 포매팅했습니다:

>>>
for x in range(1, 11):
	print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
	# Note use of 'end' on previous line
	print(repr(x*x*x).rjust(4))

 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(print() 의 동작 방식으로 인해 각 칼럼 사이에 스페이스 하나가 추가되었음에 유의하세요: 항상 인자들 사이에 스페이스를 추가합니다.)

문자열 객체의 str.rjust() 메서드는 왼쪽에 스페이스를 채워서 주어진 폭으로 문자열을 우측 줄 맞춤합니다. 비슷한 메서드 str.ljust() 와 str.center() 도 있습니다. 이 메서드들은 어떤 것도 출력하지 않습니다, 단지 새 문자열을 돌려줍니다. 입력 문자열이 너무 길면, 자르지 않고, 변경 없이 그냥 돌려줍니다; 이것이 열 배치를 엉망으로 만들겠지만, 보통 값에 대해 거짓말을 하게 될 대안보다는 낫습니다. (정말로 잘라내기를 원한다면, 항상 슬라이스 연산을 추가할 수 있습니다, x.ljust(n)[:n] 처럼.)

다른 메서드도 있습니다, str.zfill(). 숫자 문자열의 왼쪽에 0을 채웁니다. 플러스와 마이너스 부호도 이해합니다:

>>>
print('12'.zfill(5))
'00012'

print('-3.14'.zfill(7))
'-003.14'

print('3.14159265359'.zfill(5))
'3.14159265359'

 

7.1.4. 예전의 문자열 포매팅

% 연산자(모듈로)는 문자열 포매팅에도 사용할 수 있습니다. 'string' % values가 주어지면, string에 있는 % 인스턴스는 0개 이상의 values 요소로 대체됩니다. 이 연산을 흔히 문자열 보간(interpolation)이라고 합니다. 예를 들면:

>>>
import math
print('The value of pi is approximately %5.3f.' % math.pi)

The value of pi is approximately 3.142.

더 자세한 내용은 printf 스타일 문자열 포매팅 섹션에 나옵니다.

 

7.2. 파일을 읽고 쓰기

open() 은 파일 객체 를 리턴합니다.

Syntax : open(filename, mode)

텍스트 파일을 열 때에는 open 명령어를 사용한다. 기본적으로 '변수(개체이름) = open("파일명")' 형태로 코딩한다. 파일의 특정 위치(폴더)를 지정하지 않으면 python을 실행한 폴더에서 찾습니다.

mode는 쓰기모드 'w', 읽기모든 'r', 읽기쓰기모드 'r+', binary 모드는 'b' 로 표기합니다. 값을 주지않으면 디폴트는 'r'입니다.

>>>
>>> f = open('workfile', 'w')

첫 번째 인자는 파일 이름의 문자열입니다. 두 번째 인자는 파일이 사용될 방식의 문자열입니다. mode 는 파일을 읽기만 하면 'r', 쓰기만 하면 'w' (같은 이름의 이미 존재하는 파일은 삭제됩니다) 가 되고, 'a' 는 파일을 덧붙이기 위해 엽니다; 파일에 기록되는 모든 데이터는 자동으로 끝에 붙습니다. 'r+' 는 파일을 읽고 쓰기 위해 엽니다. mode 인자는 선택적인데, 생략하면 'r' 이 가정됩니다.

보통, 파일은 텍스트 모드 (text mode) 로 열리는데, 이 뜻은, 파일에 문자열을 읽고 쓰고, 파일에는 특정한 인코딩으로 저장된다는 것입니다. 인코딩이 지정되지 않으면 기본값은 플랫폼 의존적입니다. mode 에 'b' 는 파일을 바이너리 모드 (binary mode)로 엽니다. 데이터는 바이트열 객체의 형태로 읽고 쓰입니다. 텍스트를 포함하지 않는 모든 파일에는 이 모드를 사용해야 합니다.

텍스트 모드에서, 읽을 때의 기본 동작은 플랫폼 의존적인 줄 종료 (유닉스에서 \n, 윈도우에서 \r\n) 를 \n 로 변경하는 것입니다. 텍스트 모드로 쓸 때, 기본 동작은 \n 를 다시 플랫폼 의존적인 줄 종료로 변환합니다. 텍스트 파일의 경우는 문제가 안 되지만, JPEG 이나 EXE 파일과 같은 바이너리 데이터가 깨지게 됩니다. 그런 파일을 읽고 쓸 때 바이너리 모드를 사용합니다.

파일 객체를 다룰 때 with 키워드를 사용하는 것이 좋은 습관입니다. with를 쓰면 도중 예외가 발생하더라도 파일이 올바르게 닫힙니다. with 를 사용하는 것은 try-finally 블록을 쓰는 것에 비교해 훨씬 간결합니다.

>>>
with open('workfile') as f:
	read_data = f.read()

# We can check that the file has been automatically closed.
f.closed
True

with 키워드를 사용하지 않으면, f.close() 를 호출해서 파일을 닫고 사용된 시스템 자원을 즉시 반납해야 합니다.

with 키워드를 사용하거나 f.close()를 호출하지 않고 f.write()를 호출하면 프로그램이 성공적으로 종료되더라도 f.write()의 인자가 디스크에 완전히 기록되지 않을  있습니다.

파일 객체가 닫힌 후에 with 문이나 f.close() 를 호출하는 경우에 파일 객체를 사용하려면 실패합니다.

>>>
f.close()
f.read()

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

7.2.1. 파일 객체의 매소드

이 섹션의 나머지 예들은 f 라는 파일 객체가 이미 만들어졌다고 가정합니다.

파일의 내용을 읽으려면, f.read(size) 를 호출하는데, 일정량의 데이터를 읽고 문자열 (텍스트 모드 에서) 이나 바이트열 (바이너리 모드에서) 로 돌려줍니다. size 는 선택적인 숫자 인자입니다. size 가 생략되거나 음수면 파일의 내용 전체를 읽어서 돌려줍니다; 파일의 크기가 기계의 메모리보다 크다면 시스템에 문제가 발생할 수 있습니다. 그렇지 않으면 최대 size 문자(텍스트 모드에서)나 size 바이트(바이너리 모드에서)를 읽고 돌려줍니다. 파일의 끝에 도달하면, f.read() 는 빈 문자열 ('') 을 돌려줍니다.

>>>
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline() 은 파일에서 한 줄을 읽습니다; 개행 문자 (\n) 는 문자열의 끝에 보존되고, 파일이 개행문자로 끝나지 않는 때에만 파일의 마지막 줄에서만 생략됩니다. 이렇게 반환 값을 모호하지 않게 만듭니다; f.readline() 가 빈 문자열을 돌려주면, 파일의 끝에 도달한 것이지만, 빈 줄은 '\n', 즉 하나의 개행문자만을 포함하는 문자열로 표현됩니다.

>>>
f.readline()
'This is the first line of the file.\n'

f.readline()
'Second line of the file\n'

f.readline()

파일에서 줄들을 읽으려면, 파일 객체에 대해 루핑할 수 있습니다. 이것은 메모리 효율적이고, 빠르며 간단한 코드로 이어집니다:

>>>
for line in f:
	print(line, end='')

This is the first line of the file.
Second line of the file

파일의 모든 줄을 리스트로 읽어 들이려면 list(f) 나 f.readlines() 를 쓸 수 있습니다.

f.write(string) 은 string 의 내용을 파일에 쓰고, 쓴 문자들의 개수를 돌려줍니다.

>>>
f.write('This is a test\n')

15

다른 형의 객체들은 문자열 (텍스트 모드에서) 이나 바이트열 객체 (바이너리 모드에서) 로 쓰기 전에 변환될 필요가 있습니다

>>>
value = ('the answer', 42)
s = str(value)  # convert the tuple to string
f.write(s)

18

f.tell() 은 파일의 현재 위치를 가리키는 정수를 돌려주는데, 바이너리 모드의 경우 파일의 처음부터의 바이트 수로 표현되고 텍스트 모드의 경우는 불투명한 숫자입니다.

파일 객체의 위치를 바꾸려면, f.seek(offset, whence) 를 사용합니다. 위치는 기준점에 offset 을 더해서 계산됩니다; 기준점은 whence 인자로 선택합니다. whence 값이 0이면 파일의 처음부터 측정하고, 1이면 현재 파일 위치를 사용하고, 2 는 파일의 끝을 기준점으로 사용합니다. whence 는 생략될 수 있고, 기본값은 0이라서 파일의 처음을 기준점으로 사용합니다.

>>>
f = open('workfile', 'rb+')
f.write(b'0123456789abcdef')
16

f.seek(5)      # Go to the 6th byte in the file
5

f.read(1)
b'5'

f.seek(-3, 2)  # Go to the 3rd byte before the end
13

f.read(1)
b'd'

텍스트 파일에서는 파일 시작에 상대적인 위치 변경만 허락되고 (예외는 seek(0, 2) 를 사용해서 파일의 끝으로 위치를 변경하는 경우입니다), 올바른 offset 값은 f.tell() 이 돌려준 값과 0뿐입니다. 그 밖의 다른 offset 값은 정의되지 않은 결과를 낳습니다.

파일 객체는 isatty() 나 truncate() 같은 몇 가지 메서드가 더 있습니다. 파일 객체에 대한 완전한 안내는 라이브러리 레퍼런스를 참조하세요.

 

7.2.2. json 으로 구조적인 데이터를 저장하기

문자열은 파일에 쉽게 읽고 쓸 수 있습니다. 숫자는 약간의 변형을 해야 하는데, read() 메서드가 문자열만을 돌려주기 때문입니다. 이 문자열을 int() 같은 함수로 전달해야만 하는데, '123' 같은 문자열을 받고 숫자 값 123을 돌려줍니다. 중첩된 리스트나 딕셔너리 같은 더 복잡한 데이터를 저장하려고 할 때, 수작업으로 파싱하고 직렬화하는 것이 까다로울 수 있습니다.

사용자가 반복적으로 복잡한 데이터형을 파일에 저장하는 코드를 작성하고 디버깅하도록 하는 대신, 파이썬은 JSON (JavaScript Object Notation) 이라는 널리 쓰이는 데이터 교환 형식을 사용할 수 있게 합니다. json 이라는 표준 모듈은 파이썬 데이터 계층을 받아서 문자열 표현으로 바꿔줍니다; 이 절차를 직렬화 (serializing) 라고 부릅니다. 문자열 표현으로부터 데이터를 재구성하는 것은 역 직렬화 (deserializing) 라고 부릅니다. 직렬화와 역 직렬화 사이에서, 객체를 표현하는 문자열은 파일이나 데이터에 저장되거나 네트워크 연결을 통해 원격 기계로 전송될 수 있습니다.

참고

 

JSON 형식은 데이터 교환을 위해 응용 프로그램들이 자주 사용합니다. 많은 프로그래머가 이미 이것에 익숙하므로, 연동성을 위한 좋은 선택이 됩니다.

객체 x 가 있을 때, 간단한 한 줄의 코드로 JSON 문자열 표현을 볼 수 있습니다:

>>>
import json

x = [1, 'simple', 'list']
print(json.dumps(x))

## 실행결과
[1, "simple", "list"]

dump()함수는 dumps() 함수의 변형이고 객체를 텍스트 파일 로 직렬화합니다. 그래서 f 가 쓰기를 위해 열린 텍스트 파일 이면, 다음과 같이 할 수 있습니다.

json.dump(x, f)

객체를 다시 디코드하려면, f 가 읽기를 위해 열린 텍스트 파일 객체일 때:

x = json.load(f)

직렬화로 리스트와 딕셔너리를 다룰 수 있지만, 임의의 클래스 인스턴스를 JSON 으로 직렬화하기 위해서는 약간의 수고가 더 필요합니다. json 모듈의 레퍼런스는 이 방법에 대한 설명을 담고 있습니다.

 

pickle - 피클 모듈

JSON 에 반해, pickle 은 임의의 복잡한 파이썬 객체들을 직렬화할 수 있는 프로토콜입니다. 파이썬에 국한되고 다른 언어로 작성된 응용 프로그램들과 통신하는데 사용될 수 없습니다. 기본적으로 안전하지 않기도 합니다: 믿을 수 없는 소스에서 온 데이터를 역 직렬화할 때, 숙련된 공격자에 의해 데이터가 조작되었다면 임의의 코드가 실행될 수 있습니다.

 

3 입력

 

3.1. input 함수

Python에서는 표준 입력 함수로 input 함수를 지원합니다.
일단 도움말을 통해서 input 함수의 사용법을 알아보도록 하겠습니다.

Ex12_input0.py

# 표준 입력
# input함수의 도움말을 확인해 보자
help(input)

실행 결과

Help on built-in function input in module builtins:

input(prompt=None, /)
    Read a string from standard input.  The trailing newline is stripped.

    The prompt string, if given, is printed to standard output without a
    trailing newline before reading input.

    If the user hits EOF (*nix: Ctrl-D, Windows: Ctrl-Z+Return), raise EOFError.
    On *nix systems, readline is used if available.

위의 도움말을 보면 input함수의 사용법은 다음과 같습니다.

  • 표준 입력에서 문자열을 읽습니다. 후행 줄 바꿈이 제거됩니다.
  • 프롬프트 문자열이 주어진 경우, 입력을 읽기 전에 후행 개행 표시 없이 표준 출력으로 인쇄됩니다.
  • 사용자가 EOF(*nix: Ctrl-D, Windows: Ctrl-Z+Return)를 누르면 EOFError를 발생시킵니다.
     
  • *nix 시스템에서 사용 가능한 경우 readline이 사용됩니다.

Ex13_input1.py

# 표준 입력
print('이름을 입력하세요', end="")
name = input();
print("이름 : {0}, type : {1}".format(name,type(name)))
name = input('이름을 입력하세요 ');
print("이름 : {0}, type : {1}".format(name,type(name)))
name = input('아무것도 입력하지 말고 EOF(Ctrl+D 또는 Ctrl+Z+Enter)를 입력해보세요');

실행 결과

이름을 입력하세요 한사람
이름 : 한사람, type : <class 'str'>
이름을 입력하세요 두사람
이름 : 두사람, type : <class 'str'>
아무것도 입력하지 말고 EOF(Ctrl+D 또는 Ctrl+Z+Enter)를 입력해보세요^D
Traceback (most recent call last):
  File "C:/PyThonProjects/Ex01/basic03/Ex13_input1.py", line 7, in <module>
    name = input('아무것도 입력하지 말고 EOF(Ctrl+D 또는 Ctrl+Z+Enter)를 입력해보세요');
EOFError: EOF when reading a line

"이름을 입력하세요"라고 나오면 "한사람"을 입력하세요
"이름을 입력하세요"라고 나오면 "두사람"을 입력하세요
"아무것도 입력하지 말고 EOF(Ctrl+D 또는 Ctrl+Z+Enter)를 입력해보세요"라고 나오면 윈도우인 경우 Ctrl키와 Z키를 같이 눌러 보세요

2. 정수 입력

기본적으로 input함수는 문자열로 입력됩니다.
그래서 입력받은 값을 정수형으로 변환해서 사용해야 합니다.

  • eval() 함수 : 인수를 유효한 파이썬 표현식으로 리턴 합니다.
  • int() 클래스 : class int(x=0), class int(x,base=10)
    숫자나 문자열 x 로 부터 만들어진 정수 객체를 돌려줍니다.
    인자가 주어지지 않으면 0 을 돌려줍니다.
    base는 진법을 나타내며 주로 2, 8, 10, 16을 사용합니다. 10이 기본값입니다.

Ex14_input2.py

# 표준 입력
data = input("정수를 입력하시오 : ")
print(data, type(data))
# print(data, type(data), data + 1) 에러 문자열과 정수를 +(더하기)할 수 없습니다.

data = eval(input("정수를 입력하시오 : "))
print(data, type(data), data + 1)

data = int(input("정수를 입력하시오 : "))
print(data, type(data), data + 1)

data = int(input("2진수를 입력하시오 : "), 2)
print(data, type(data), data + 1)

data = int(input("8진수를 입력하시오 : "), 8)
print(data, type(data), data + 1)

data = int(input("10진수를 입력하시오 : "), 10)
print(data, type(data), data + 1)

data = int(input("16진수를 입력하시오 : "), 16)
print(data, type(data), data + 1)

실행 결과

정수를 입력하시오 : 1
1 <class 'str'>
정수를 입력하시오 : 2
2 <class 'int'> 3
정수를 입력하시오 : 3
3 <class 'int'> 4
2진수를 입력하시오 : 1010
10 <class 'int'> 11
8진수를 입력하시오 : 10
8 <class 'int'> 9
10진수를 입력하시오 : 10
10 <class 'int'> 11
16진수를 입력하시오 : 1a
26 <class 'int'> 27

실행할 때 차례대로 1, 2, 3, 1010, 10, 10, 1a를 입력해보세요

3. 실수 입력

기본적으로 input함수는 문자열로 입력됩니다.
그래서 입력받은 값을 실수형으로 변환해서 사용해야 합니다.

  • eval() 함수 : 인수를 유효한 파이썬 표현식으로 리턴 합니다.
  • float() 클래스 : class float(x)
    숫자나 문자열 x 로 부터 만들어진 실수 객체를 돌려줍니다.
    인자가 주어지지 않으면 0 을 돌려줍니다.

Ex15_input3.py

# 표준 입력
data = input("실수를 입력하시오 : ")
print(data, type(data))
# 에러 문자열과 실수를 +(더하기)할 수 없습니다.
# print(data, type(data), data + 1.2)

data = eval(input("실수를 입력하시오 : "))
print(data, type(data), data + 1.2)

data = float(input("정수를 입력하시오 : "))
print(data, type(data), data + 1.2)

실행 결과

실수를 입력하시오 : 3.14
3.14 <class 'str'>
실수를 입력하시오 : 3.14
3.14 <class 'float'> 4.34
정수를 입력하시오 : 3.14
3.14 <class 'float'> 4.34

4. 튜플(tuple), 리스트(list)로 입력받기

기본적으로 input함수는 문자열로 입력됩니다.

  • eval() 함수 : 인수를 유효한 파이썬 표현식으로 리턴 합니다.

Ex16_input4.py

# 표준 입력
string = input("(1,2) 처럼입력하시오 ")
print(string, type(string))

string = eval( input("(1,2) 처럼입력하시오 "))
print(string, type(string))

string = input("[1,2,3,4,5,6] 처럼입력하시오 ")
print(string, type(string))

string = eval( input("[1,2,3,4,5,6] 처럼입력하시오 "))
print(string, type(string))

실행 결과

(1,2) 처럼입력하시오 (1,2)
(1,2) <class 'str'>
(1,2) 처럼입력하시오 (1,2)
(1, 2) <class 'tuple'>
[1,2,3,4,5,6] 처럼입력하시오 [1,2,3]
[1,2,3] <class 'str'>
[1,2,3,4,5,6] 처럼입력하시오 [1,2,3]
[1, 2, 3] <class 'list'>

 

'Python' 카테고리의 다른 글

Python - 표준라이브러리 II  (0) 2022.01.06
Python - 오류 및 예외  (0) 2022.01.06
Python - module  (0) 2022.01.06
Python - class  (0) 2022.01.06
python - decorator  (0) 2022.01.05

파이썬 모듈은 전역변수, 함수등 을 모아둔 파일 입니다.

파이썬 인터프리터를 종료한 후에 다시 들어가면, 여러분이 만들었던 정의들이 사라집니다 (함수나 변수들). 그래서 파일로 따로 만들어서 재사용하면 좋습니다. 이렇게 하는 것을 스크립트를 만든다고 합니다. 프로그램이 길어짐에 따라, 유지관리를 쉽게 하려고 여러 개의 파일로 나눌 수 있습니다. 여러 프로그램에서 썼던 편리한 함수를 각 프로그램에 정의를 복사하지 않고 사용할 수 있습니다.

 

이런 것을 지원하기 위해, 파이썬은 정의들을 파일에 저장하고 스크립트나 인터프리터의 대화형 모드에서 사용할 수 있는 방법을 제공합니다. 그런 파일을 모듈 이라고 부릅니다.

 

모듈의 정의들은 다른 모듈이나 메인 모듈로 임포트 될 수 있습니다.

(메인 모듈은 최상위 수준에서 실행되는 스크립트나 계산기 모드에서 액세스하는 변수들의 컬렉션입니다).

모듈은 파이썬 정의와 문장들을 담고 있는 파일입니다. 파일의 이름은 모듈 이름에 확장자 .py 를 붙입니다. 모듈 내에서, 모듈의 이름은 전역 변수 __name__ 으로 제공됩니다.

 

예제) 편집기로 fibo.py 라는 이름의 파일을 아래 내용으로 만듭니다.

# Fibonacci numbers module

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()

def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

VSCode에서 이 모듈을 다음과 같은 명령으로 임포트 합니다:

import fibo

단, fibo 에 정의된 함수들은 현재 심볼 테이블에 직접 들어가지는 않습니다. 오직 모듈 이름 fibo 만 들어갑니다. 이 모듈 이름을 사용해서 함수들을 액세스할 수 있습니다:

import fibo

fibo.fib(1000)
print(fibo.fib2(100))
print(fibo.__name__)

## 실행결과
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
fibo

함수를 자주 사용할 거면 지역 이름으로 지정하여 사용할 수도 있습니다.

import fibo

fib = fibo.fib
fib(500)

## 실행결과
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

6.1. 모듈 더 보기

모듈은 함수 정의뿐만 아니라 실행 가능한 문장들도 포함할 수 있습니다. 이 문장들은 모듈을 초기화하는 데 사용됩니다. 이것들은 임포트 문에서 모듈 이름이 처음 등장할 때만 실행됩니다. (이것들은 파일이 스크립트로 실행될 때도 실행됩니다.)

각 모듈은 자신만의 심볼 테이블을 갖고 있는데, 그 모듈에서 정의된 함수들의 전역 심볼 테이블로 사용됩니다. 그래서, 모듈의 작성자는 사용자의 전역 변수와 충돌할 것을 걱정하지 않고 전역 변수를 사용할 수 있습니다. 반면에, 여러분이 무얼 하는지 안다면, 모듈의 함수를 참조하는데 사용된 것과 같은 표기법으로 모듈의 전역 변수들을 건드릴 수 있습니다, modname.itemname.

모듈은 다른 모듈들을 임포트할 수 있습니다. 모든 import 문들을 모듈의 처음에 놓는 것이 관례지만 반드시 그래야 하는 것은 아닙니다 (스크립트도 마찬가집니다). 임포트되는 모듈 이름은 임포트하는 모듈의 전역 심볼 테이블에 들어갑니다.

모듈에 들어있는 이름들을 직접 임포트하는 모듈의 심볼 테이블로 임포트하는 import 문도 있습니다. 예를 들어:

>>>
from fibo import fib, fib2
fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

fibo.fib(30)
## 실행결과 : fibo를 import 한게 아니기 때문에 오류발생
    fibo.fib(30)
NameError: name 'fibo' is not defined

이것은 지역 심볼 테이블에 임포트되는 모듈의 이름을 만들지 않습니다 (그래서 이 예에서는, fibo 가 정의되지 않습니다).

모듈이 정의하는 모든 이름을 임포트하는 것도 있습니다.

from fibo import *
fib(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

이것은 밑줄 (_) 로 시작하는 것들을 제외한 모든 이름을 임포트 합니다. 대부분 파이썬 프로그래머들은 이 기능을 사용하지 않는데, 인터프리터로 알려지지 않은 이름들의 집합을 도입하게 되어, 여러분이 이미 정의한 것들을 모호하게 할 수 있기 때문입니다.

일반적으로 모듈이나 패키지에서 * 를 임포트하지 않습니다. 하지만, 대화형 세션에서 입력을 줄이고자 사용하는 것은 상관없습니다.

모듈 이름 다음에 as 를  쓸 경우, as 다음의 이름을 임포트한 모듈에 직접 연결합니다.

>>>
import fibo as fb
fb.fib(500)

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

이것은 import fibo 와 같은 방식으로 모듈을 임포트 하는데,  차이점은 그 모듈을 fb 라는 이름으로 사용할 수 있다는 것입니다.

from을 쓸 떄도 사용할 수 있습니다:

>>>
>>> from fibo import fib as fibonacci
>>> fibonacci(500)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377

참고

 

효율성의 이유로, 각 모듈은 인터프리터 세션마다 한 번만 임포트됩니다. 그래서, 여러분이 모듈을 수정하면, 인터프리터를 다시 시작시켜야 합니다 — 또는, 대화형으로 시험하는 모듈이 하나뿐이라면, importlib.reload() 를 사용하세요.

예를 들어, import importlib; importlib.reload(modulename).

6.1.1. 모듈을 스크립트로 실행하기

여러분이 파이썬 모듈을 이렇게 실행하면

python fibo.py <arguments>

모듈에 있는 코드는, 모듈을 임포트할 때처럼 실행됩니다.  __name__ 은 "__main__" 로 설정됩니다.

이 코드를 모듈의 끝에 붙여서 사용합니다.

if __name__ == "__main__":
    import sys
    fib(int(sys.argv[1]))

파일을 임포트할 수 있는 모듈뿐만 아니라 스크립트로도 사용할 수 있도록 만들 수 있음을 의미하는데, 오직 모듈이 《메인》 파일로 실행될 때만 명령행을 파싱하는 코드가 실행되기 때문입니다:

$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34

모듈이 다른 모듈로 임포트될 때에 코드는 실행되지 않습니다:

>>>
import fibo

이것은 종종 모듈에 대한 편리한 사용자 인터페이스를 제공하거나 테스트 목적으로 사용됩니다

6.1.2. 모듈 검색 경로

spam 이라는 이름의 모듈이 임포트될 때, 인터프리터는 먼저 그 이름의 내장 모듈을 찾습니다. 발견되지 않으면, 변수 sys.path 로 주어지는 디렉터리들에서 spam.py 라는 이름의 파일을 찾습니다. sys.path 는 이 위치들로 초기화됩니다:

  • 입력 스크립트에 포함된 디렉터리 (또는 파일이 지정되지 않았을 때는 현재 디렉터리).
  • PYTHONPATH (디렉터리 이름들의 목록, 셸 변수 PATH 와 같은 문법).
  • The installation-dependent default (by convention including a site-packages directory, handled by the site module).

참고

 

심볼릭 링크를 지원하는 파일 시스템에서, 입력 스크립트에 포함된 디렉터리는 심볼릭 링크를 변환한 후에 계산됩니다. 다른 말로, 심볼릭 링크를 포함하는 디렉터리는 모듈 검색 경로에 포함되지 않습니다.

초기화 후에, 파이썬 프로그램은 sys.path 를 수정할 수 있습니다. 스크립트를 포함하는 디렉터리는 검색 경로의 처음에, 표준 라이브러리 경로의 앞에 놓입니다. 이것은 같은 이름일 경우 라이브러리 디렉터리에 있는 것 대신 스크립트를 포함하는 디렉터리의 것이 로드된다는 뜻입니다. 이 치환이 의도된 것이 아니라면 에러입니다. 더 자세한 정보는 표준 모듈들 을 보세요.

6.1.3. 《컴파일된》 파이썬 파일

모듈 로딩을 빠르게 하려고, 파이썬은 __pycache__ 디렉터리에 각 모듈의 컴파일된 버전을 module.version.pyc 라는 이름으로 캐싱합니다. version 은 컴파일된 파일의 형식을 지정합니다; 일반적으로 파이썬의 버전 번호를 포함합니다. 예를 들어, CPython 배포 3.8 에서 spam.py 의 컴파일된 버전은 __pycache__/spam.cpython-38.pyc 로 캐싱 됩니다. 이 명명법은 서로 다른 파이썬 배포와 버전의 컴파일된 모듈들이 공존할 수 있도록 합니다.

파이썬은 소스의 수정 시간을 컴파일된 버전과 비교해서 시효가 지나 다시 컴파일해야 하는지 검사합니다. 이것은 완전히 자동화된 과정입니다. 또한, 컴파일된 모듈은 플랫폼 독립적이기 때문에, 같은 라이브러리를 서로 다른 아키텍처 시스템들에서 공유할 수 있습니다.

파이썬은 두 가지 상황에서 캐시를 검사하지 않습니다. 첫째로, 명령행에서 직접 로드되는 모듈들은 항상 재컴파일하고 그 결과를 저장하지 않습니다. 둘째로, 소스 모듈이 없으면 캐시를 검사하지 않습니다. 소스 없는 (컴파일된 파일만 있는) 배포를 지원하려면, 컴파일된 모듈이 소스 디렉터리에 있어야 하고, 소스 모듈이 없어야 합니다.

전문가를 위한 몇 가지 팁

  • 컴파일된 모듈의 크기를 줄이려면 파이썬 명령에 -O 나 -OO 스위치를 사용할 수 있습니다. -O 스위치는 assert 문을 제거하고, -OO 스위치는 assert 문과 __doc__ 문자열을 모두 제거합니다. 어떤 프로그램들은 이것들에 의존하기 때문에, 무엇을 하고 있는지 아는 경우만 이 옵션을 사용해야 합니다. 《최적화된》 모듈은 opt- 태그를 갖고, 보통 더 작습니다. 미래의 배포에서는 최적화의 효과가 변경될 수 있습니다.
  • .py 파일에서 읽을 때보다 .pyc 파일에서 읽을 때 프로그램이 더 빨리 실행되지는 않습니다; .pyc 파일에서 더 빨라지는 것은 로드되는 속도뿐입니다.
  • 모듈 compileall 은 디렉터리에 있는 모든 모듈의 .pyc 파일들을 만들 수 있습니다.
  • 이 절차에 대한 더 자세한 정보, 결정들의 순서도를 포함합니다, 는 PEP 3147 에 나옵니다.

<<< HERE >>>

6.2. 표준 모듈들

파이썬은 표준 모듈들의 라이브러리가 함께 오는데, 별도의 문서 파이썬 라이브러리 레퍼런스 (이후로는 《라이브러리 레퍼런스》) 에서 설명합니다. 어떤 모듈들은 인터프리터에 내장됩니다; 이것들은 언어의 핵심적인 부분은 아니지만 그런데도 내장된 연산들에 대한 액세스를 제공하는데, 효율이나 시스템 호출과 같은 운영 체제 기본 요소들에 대한 액세스를 제공하기 위함입니다. 그런 모듈들의 집합은 설정 옵션인데 기반 플랫폼 의존적입니다. 예를 들어, winreg 모듈은 윈도우 시스템에서만 제공됩니다. 특별한 모듈 하나는 주목을 받을 필요가 있습니다: sys. 모든 파이썬 인터프리터에 내장됩니다. 변수 sys.ps1 와 sys.ps2 는 기본과 보조 프롬프트로 사용되는 문자열을 정의합니다:

>>>
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Yuck!')
Yuck!
C>

이 두 개의 변수들은 인터프리터가 대화형 모드일 때만 정의됩니다.

변수 sys.path 는 인터프리터의 모듈 검색 경로를 결정하는 문자열들의 리스트입니다. 환경 변수 PYTHONPATH 에서 취한 기본 경로나, PYTHONPATH 가 설정되지 않는 경우 내장 기본값으로 초기화됩니다. 표준 리스트 연산을 사용해서 수정할 수 있습니다:

>>>
>>> import sys
>>> sys.path.append('/ufs/guido/lib/python')

6.3. dir() 함수

내장 함수 dir() 은 모듈이 정의하는 이름들을 찾는 데 사용됩니다. 문자열들의 정렬된 리스트를 돌려줍니다:

>>>
>>> import fibo, sys
>>> dir(fibo)
['__name__', 'fib', 'fib2']
>>> dir(sys)  
['__breakpointhook__', '__displayhook__', '__doc__', '__excepthook__',
 '__interactivehook__', '__loader__', '__name__', '__package__', '__spec__',
 '__stderr__', '__stdin__', '__stdout__', '__unraisablehook__',
 '_clear_type_cache', '_current_frames', '_debugmallocstats', '_framework',
 '_getframe', '_git', '_home', '_xoptions', 'abiflags', 'addaudithook',
 'api_version', 'argv', 'audit', 'base_exec_prefix', 'base_prefix',
 'breakpointhook', 'builtin_module_names', 'byteorder', 'call_tracing',
 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_info',
 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info',
 'float_repr_style', 'get_asyncgen_hooks', 'get_coroutine_origin_tracking_depth',
 'getallocatedblocks', 'getdefaultencoding', 'getdlopenflags',
 'getfilesystemencodeerrors', 'getfilesystemencoding', 'getprofile',
 'getrecursionlimit', 'getrefcount', 'getsizeof', 'getswitchinterval',
 'gettrace', 'hash_info', 'hexversion', 'implementation', 'int_info',
 'intern', 'is_finalizing', 'last_traceback', 'last_type', 'last_value',
 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks',
 'path_importer_cache', 'platform', 'prefix', 'ps1', 'ps2', 'pycache_prefix',
 'set_asyncgen_hooks', 'set_coroutine_origin_tracking_depth', 'setdlopenflags',
 'setprofile', 'setrecursionlimit', 'setswitchinterval', 'settrace', 'stderr',
 'stdin', 'stdout', 'thread_info', 'unraisablehook', 'version', 'version_info',
 'warnoptions']

인자가 없으면, dir() 는 현재 정의한 이름들을 나열합니다:

>>>
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']

모든 형의 이름을 나열한다는 것에 유의해야 합니다: 변수, 모듈, 함수, 등등.

dir() 은 내장 함수와 변수들의 이름을 나열하지 않습니다. 그것들의 목록을 원한다면, 표준 모듈 builtins 에 정의되어 있습니다:

>>>
>>> import builtins
>>> dir(builtins)  
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
 'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
 'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
 'FileExistsError', 'FileNotFoundError', 'FloatingPointError',
 'FutureWarning', 'GeneratorExit', 'IOError', 'ImportError',
 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError',
 'IsADirectoryError', 'KeyError', 'KeyboardInterrupt', 'LookupError',
 'MemoryError', 'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
 'NotImplementedError', 'OSError', 'OverflowError',
 'PendingDeprecationWarning', 'PermissionError', 'ProcessLookupError',
 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError',
 'SystemExit', 'TabError', 'TimeoutError', 'True', 'TypeError',
 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError',
 'UnicodeError', 'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning',
 'ValueError', 'Warning', 'ZeroDivisionError', '_', '__build_class__',
 '__debug__', '__doc__', '__import__', '__name__', '__package__', 'abs',
 'all', 'any', 'ascii', 'bin', 'bool', 'bytearray', 'bytes', 'callable',
 'chr', 'classmethod', 'compile', 'complex', 'copyright', 'credits',
 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit',
 'filter', 'float', 'format', 'frozenset', 'getattr', 'globals', 'hasattr',
 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance', 'issubclass',
 'iter', 'len', 'license', 'list', 'locals', 'map', 'max', 'memoryview',
 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow', 'print', 'property',
 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice',
 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars',
 'zip']

6.4. 패키지

패키지는 《점으로 구분된 모듈 이름》 를 써서 파이썬의 모듈 이름 공간을 구조화하는 방법입니다. 예를 들어, 모듈 이름 A.B 는 A 라는 이름의 패키지에 있는 B 라는 이름의 서브 모듈을 가리킵니다. 모듈의 사용이 다른 모듈의 저자들이 서로의 전역 변수 이름들을 걱정할 필요 없게 만드는 것과 마찬가지로, 점으로 구분된 모듈의 이름들은 NumPy 나 Pillow 과 같은 다중 모듈 패키지들의 저자들이 서로의 모듈 이름들을 걱정할 필요 없게 만듭니다.

음향 파일과 과 음향 데이터의 일관된 처리를 위한 모듈들의 컬렉션 (《패키지》) 을 설계하길 원한다고 합시다. 여러 종류의 음향 파일 형식이 있으므로 (보통 확장자로 구분됩니다, 예를 들어: .wav, .aiff, .au), 다양한 파일 형식 간의 변환을 위해 계속 늘어나는 모듈들의 컬렉션을 만들고 유지할 필요가 있습니다. 또한, 음향 데이터에 적용하고자 하는 많은 종류의 연산들도 있으므로 (믹싱, 에코 넣기, 이퀄라이저 기능 적용, 인공적인 스테레오 효과 만들기와 같은), 이 연산들을 수행하기 위한 모듈들을 끊임없이 작성하게 될 것입니다. 패키지를 이렇게 구성해 볼 수 있습니다 (계층적 파일 시스템으로 표현했습니다):

sound/                          Top-level package
      __init__.py               Initialize the sound package
      formats/                  Subpackage for file format conversions
              __init__.py
              wavread.py
              wavwrite.py
              aiffread.py
              aiffwrite.py
              auread.py
              auwrite.py
              ...
      effects/                  Subpackage for sound effects
              __init__.py
              echo.py
              surround.py
              reverse.py
              ...
      filters/                  Subpackage for filters
              __init__.py
              equalizer.py
              vocoder.py
              karaoke.py
              ...

패키지를 임포트할 때, 파이썬은 sys.path 에 있는 디렉터리들을 검색하면서 패키지 서브 디렉터리를 찾습니다.

파이썬이 디렉터리를 패키지로 취급하게 만들기 위해서 __init__.py 파일이 필요합니다. 이렇게 하면 string 처럼 흔히 쓰는 이름의 디렉터리가, 의도하지 않게 모듈 검색 경로의 뒤에 등장하는 올바른 모듈들을 가리는 일을 방지합니다. 가장 간단한 경우, __init__.py 는 그냥 빈 파일일 수 있지만, 패키지의 초기화 코드를 실행하거나 뒤에서 설명하는 __all__ 변수를 설정할 수 있습니다.

패키지 사용자는 패키지로부터 개별 모듈을 임포트할 수 있습니다, 예를 들어:

import sound.effects.echo

이것은 서브 모듈 sound.effects.echo 를 로드합니다. 전체 이름으로 참조되어야 합니다.

sound.effects.echo.echofilter(input, output, delay=0.7, atten=4)

서브 모듈을 임포트하는 다른 방법은 이렇습니다:

from sound.effects import echo

이것도 서브 모듈 echo 를 로드하고, 패키지 접두어 없이 사용할 수 있게 합니다. 그래서 이런 식으로 사용할 수 있습니다:

echo.echofilter(input, output, delay=0.7, atten=4)

또 다른 방법은 원하는 함수나 변수를 직접 임포트하는 것입니다:

from sound.effects.echo import echofilter

또다시, 이것은 서브 모듈 echo 를 로드하지만, 함수 echofilter() 를 직접 사용할 수 있게 만듭니다:

echofilter(input, output, delay=0.7, atten=4)

from package import item 를 사용할 때, item은 패키지의 서브 모듈 (또는 서브 패키지)일 수도 있고 함수, 클래스, 변수 등 패키지에 정의된 다른 이름들일 수도 있음에 유의하세요. import 문은 먼저 item이 패키지에 정의되어 있는지 검사하고, 그렇지 않으면 모듈이라고 가정하고 로드를 시도합니다. 찾지 못한다면, ImportError 예외를 일으킵니다.

이에 반하여, import item.subitem.subsubitem 와 같은 문법을 사용할 때, 마지막 것을 제외한 각 항목은 반드시 패키지여야 합니다; 마지막 항목은 모듈이나 패키지가 될 수 있지만, 앞의 항목에서 정의된 클래스, 함수, 변수 등이 될 수는 없습니다.

6.4.1. 패키지에서 * 임포트 하기

이제 from sound.effects import * 라고 쓰면 어떻게 될까? 이상적으로는, 어떻게든 파일 시스템에서 패키지에 어떤 모듈들이 들어있는지 찾은 다음, 그것들 모두를 임포트 하기를 원할 것입니다. 이렇게 하는 데는 시간이 오래 걸리고 서브 모듈을 임포트 함에 따라 어떤 서브 모듈을 명시적으로 임포트할 경우만 일어나야만 하는 원하지 않는 부수적 효과가 발생할 수 있습니다.

유일한 해결책은 패키지 저자가 패키지의 색인을 명시적으로 제공하는 것입니다. import 문은 다음과 같은 관례가 있습니다: 패키지의 __init__.py 코드가 __all__ 이라는 이름의 목록을 제공하면, 이것을 from package import * 를 만날 때 임포트 해야만 하는 모듈 이름들의 목록으로 받아들입니다. 새 버전의 패키지를 출시할 때 이 목록을 최신 상태로 유지하는 것은 패키지 저자의 책임입니다. 패키지 저자가 패키지에서 * 를 임포트하는 용도가 없다고 판단한다면, 이것을 지원하지 않기로 할 수도 있습니다. 예를 들어, 파일 sound/effects/__init__.py 는 다음과 같은 코드를 포함할 수 있습니다:

__all__ = ["echo", "surround", "reverse"]

이것은 from sound.effects import * 이 sound.effects 패키지의 세 서브 모듈들을 임포트하게 됨을 의미합니다.

__all__ 이 정의되지 않으면, 문장 from sound.effects import * 은 패키지 sound.effects 의 모든 서브 모듈들을 현재 이름 공간으로 임포트 하지 않습니다; 이것은 오직 패키지 sound.effects 가 임포트 되도록 만들고 (__init__.py 에 있는 초기화 코드들이 수행될 수 있습니다), 그 패키지가 정의하는 이름들을 임포트 합니다. 이 이름들은 __init__.py 가 정의하는 모든 이름 (그리고 명시적으로 로드된 서브 모듈들)을 포함합니다. 이 이름들에는 사전에 import 문으로 명시적으로 로드된 패키지의 서브 모듈들 역시 포함됩니다. 이 코드를 생각해봅시다:

import sound.effects.echo
import sound.effects.surround
from sound.effects import *

이 예에서, echo 와 surround 모듈이 현재 이름 공간으로 임포트 되는데, from...import 문이 실행될 때 sound.effects 패키지에 정의되기 때문입니다. (__all__ 이 정의될 때도 마찬가집니다.)

설사 어떤 모듈이 import * 를 사용할 때 특정 패턴을 따르는 이름들만 익스포트 하도록 설계되었다 하더라도, 프로덕션 코드에서는 여전히 좋지 않은 사례로 여겨집니다.

from package import specific_submodule 을 사용하는데 잘못된 것은 없다는 것을 기억하세요! 사실, 임포트하는 모듈이 다른 패키지에서 같은 이름의 서브 모듈을 사용할 필요가 없는 한 권장되는 표기법입니다.

6.4.2. 패키지 내부 간의 참조

패키지가 서브 패키지들로 구조화될 때 (예에서 나온 sound 패키지처럼), 이웃 패키지의 서브 모듈을 가리키는데 절대 임포트를 사용할 수 있습니다. 예를 들어, 모듈 sound.filters.vocoder 이 sound.effects 패키지의 echo 모듈이 필요하면, from sound.effects import echo 를 사용할 수 있습니다.

상대 임포트를 쓸 수도 있는데, from module import name 형태의 임포트 문을 사용합니다. 이 임포트는 상대 임포트에 수반되는 현재와 부모 패키지를 가리키기 위해 앞에 붙는 점을 사용합니다. 예를 들어, surround 모듈에서, 이렇게 사용할 수 있습니다:

from . import echo
from .. import formats
from ..filters import equalizer

상대 임포트가 현재 모듈의 이름에 기반을 둔다는 것에 주의하세요. 메인 모듈의 이름은 항상 "__main__" 이기 때문에, 파이썬 응용 프로그램의 메인 모듈로 사용될 목적의 모듈들은 반드시 절대 임포트를 사용해야 합니다.

6.4.3. 여러 디렉터리에 있는 패키지

패키지는 특별한 어트리뷰트 하나를 더 지원합니다, __path__. 이것은 패키지의 __init__.py 파일을 실행하기 전에, 이 파일이 들어있는 디렉터리의 이름을 포함하는 리스트로 초기화됩니다. 이 변수는 수정할 수 있습니다; 그렇게 하면 그 이후로 패키지에 포함된 모듈과 서브 패키지를 검색하는 데 영향을 주게 됩니다.

이 기능이 자주 필요하지는 않지만, 패키지에서 발견되는 모듈의 집합을 확장하는 데 사용됩니다.

각주

1

사실 함수 정의도 〈실행〉 되는 〈문장〉 입니다; 모듈 수준의 함수 정의를 실행하면 함수의 이름이 전역 심볼 테이블에 들어갑니다.

'Python' 카테고리의 다른 글

Python - 오류 및 예외  (0) 2022.01.06
Python - 입출력  (0) 2022.01.06
Python - class  (0) 2022.01.06
python - decorator  (0) 2022.01.05
파이썬 - list  (0) 2022.01.05

클래스는 객체를 표현하기 위한 문법으로 사람, 자동차 같은 특정한 개념이나 모양을 나타냅니다.

이를 실체로 구현한 것을 객체(object)라고 부릅니다. 이렇게 객체를 사용한 프로그래밍 언어를 객체 지향(object oriented) 언어라고 부르며 파이썬에서 사용되는 list, dict 등도 클래스 입니다.

클래스에는 크게 속성(데이터, 변수)과 메소드(함수)로 구성됩니다.객체는 클래스의 인스턴스라고도 하며 이 객체를 생성하는 프로세스를 인스턴스화라고 합니다.

 

클래스 정의

파이썬에서 함수 정의가 def 키워드로 시작하는 것처럼 클래스 정의는 class 키워드로 시작합니다.
클래스 내부의 첫 번째 문자열은 docstring이라고 하며 클래스에 대한 간략한 설명을 적습니다. 필수 사항은 아니지만 적극 권장합니다.

다음은 간단한 클래스 정의입니다.

class MyNewClass:
    '''This is a docstring. I have created a new class'''
    pass

 

클래스는 모든 속성이 정의된 새 로컬 네임스페이스를 만듭니다. 속성은 데이터 또는 함수일 수 있습니다.
이중 밑줄 __로 시작하는 특수 속성도 있습니다. 예를 들어 __doc__은 해당 클래스의 독스트링을 제공합니다.
클래스를 정의하면 동일한 이름으로 새 클래스 객체가 생성됩니다. 이 클래스 개체를 사용하면 다른 속성에 액세스할 수 있을 뿐만 아니라 해당 클래스의 새 개체를 인스턴스화할 수 있습니다.

class Car:
    "첫번째 문장은 docstring입니다."
    year = 2020

    def run(self):
        print("주행을 시작합니다.")

print(Car.year)
print(Car.run)
Car.run(Car)
print(Car.__doc__)

## 실행결과
2020
<function Car.run at 0x000002240D806AF0>
주행을 시작합니다.
첫번째 문장은 docstring입니다.

 

 

오브젝트 생성

해당 클래스의 새로운 객체 인스턴스(인스턴스화)를 만드는 데 사용할 수도 있습니다. 객체를 생성하는 절차는 함수 호출과 유사합니다.

bmw = Car()

 

이렇게 하면 bmw라는 새 인스턴스가 생성됩니다. 객체명으로 객체의 속성에 액세스할 수 있습니다.
속성은 데이터 또는 메소드일 수 있습니다. 개체의 메서드는 해당 클래스의 기능입니다.
이것은 Car.run 이 함수 객체(클래스의 속성)이기 때문에 Person.run가 메소드 객체가 된다는 것을 의미합니다.

class Person:
    "This is a person class"
    age = 10

    def greet(self):
        print('Hello')

harry = Person()

print(Person.greet)
print(harry.greet)
harry.greet()

## 실행경과
<function Person.greet at 0x000002227ADF6AF0>
<bound method Person.greet of <__main__.Person object at 0x000002227ADB74F0>>
Hello

 

객체가 메서드를 호출할 때마다 객체 자체가 첫 번째 인수로 전달됩니다.harry.greet()는 Person.greet(harry)로 변환됩니다.
일반적으로 n개의 인수 목록으로 메서드를 호출하는 것은 첫 번째 인수 앞에 메서드의 개체를 삽입하여 생성된 인수 목록으로 해당 함수를 호출하는 것과 같습니다.
이러한 이유로 클래스에 있는 함수의 첫 번째 인수는 객체 자체여야 합니다. 이것을 관례적으로 self라고 합니다. 다른 이름으로 지정할 수 있지만 규칙을 따르는 것이 좋습니다.

Constructors(생성자)

이중 밑줄 __로 시작하는 클래스 함수는 특별한 의미를 가지므로 특수 함수라고 합니다.
특히  __init__() 함수는 해당 클래스의 새 개체가 인스턴스화될 때마다 호출됩니다.

이러한 유형의 함수는 객체 지향 프로그래밍(OOP)에서 생성자라고도 합니다. 일반적으로 모든 변수를 초기화하는 데 사용합니다.

class ComplexNumber:
    def __init__(self, r=0, i=0):
        self.real = r
        self.imag = i

    def get_data(self):
        print(f'{self.real}+{self.imag}j')


# Create a new ComplexNumber object
num1 = ComplexNumber(2, 3)

# Call get_data() method
# Output: 2+3j
num1.get_data()

# Create another ComplexNumber object
# and create a new attribute 'attr'
num2 = ComplexNumber(5)
num2.attr = 10

# Output: (5, 0, 10)
print((num2.real, num2.imag, num2.attr))

# but num1 object doesn't have attribute 'attr'
# AttributeError: 'ComplexNumber' object has no attribute 'attr'
print(num1.attr)

Output

2+3j
(5, 0, 10)
Traceback (most recent call last):
  File "<string>", line 27, in <module>
    print(num1.attr)
AttributeError: 'ComplexNumber' object has no attribute 'attr'

In the above example, we defined a new class to represent complex numbers. It has two functions, __init__() to initialize the variables (defaults to zero) and get_data() to display the number properly.

An interesting thing to note in the above step is that attributes of an object can be created on the fly. We created a new attribute attr for object num2 and read it as well. But this does not create that attribute for object num1.

위의 예에서 우리는 복소수를 나타내는 새로운 클래스를 정의했습니다. 여기에는 변수를 초기화하는 __init__() 함수(기본값은 0)와 숫자를 올바르게 표시하는 get_data()의 두 가지 함수가 있습니다.

위 단계에서 주목해야 할 점은 객체의 속성이 즉석에서 생성될 수 있다는 것입니다. 우리는 객체 num2에 대한 새로운 속성 attr을 생성했습니다.


속성 및 개체 삭제

del 문을 사용하여 개체의 모든 속성을 언제든지 삭제할 수 있습니다. 

>>> num1 = ComplexNumber(2,3)
>>> del num1.imag
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'imag'

>>> del ComplexNumber.get_data
>>> num1.get_data()
Traceback (most recent call last):
...
AttributeError: 'ComplexNumber' object has no attribute 'get_data'

 

del 문을 사용하여 객체 자체를 삭제할 수도 있습니다.

c1 = ComplexNumber(1,3)
del c1

 

실제로는 그보다 더 복잡합니다. c1 = ComplexNumber(1,3)를 수행하면 메모리에 새 인스턴스 객체가 생성되고 c1이라는 이름이 이에 바인딩됩니다.

del c1 명령에서 이 바인딩이 제거되고 이름 c1이 해당 네임스페이스에서 삭제됩니다. 그러나 객체는 메모리에 계속 존재하며 다른 이름이 바인딩되지 않은 경우 나중에 자동으로 소멸됩니다.
Python에서 이러한 참조되지 않은 객체의 자동 파괴를 가비지 콜렉션이라고 합니다.

Python에서 객체를 삭제하면 이름 바인딩이 제거됩니다.

'Python' 카테고리의 다른 글

Python - 입출력  (0) 2022.01.06
Python - module  (0) 2022.01.06
python - decorator  (0) 2022.01.05
파이썬 - list  (0) 2022.01.05
파이썬 - lambda 함수  (0) 2022.01.05

+ Recent posts