여기 있어요: Home ‣ Dive Into Python 3 ‣
난이도: ♦♦♢♢♢
❝놀라움은 모든 철학의 토양이고, 질문으로 철학은 꽃피우지만, 무시하기 시작하면 철학은 시든다.
Wonder is the foundation of all philosophy, inquiry its progress, ignorance its end. ❞
— Michel de Montaigne
자료형이라. 우리의 첫 파이썬 프로그램은 잠시 잊어버리기로 하죠, 그리고 자료형에 대해서 이야기 해봅시다. 파이썬에서 모든 값은 자료형을 가지지만, 변수의 자료형을 지정할 필요는 없습니다. 어떻게 그게 가능할까요? 파이썬은 변수에 처음 들어간 값을 보고 그 형태를 알아채 기억합니다.
파이썬은 많은 수의 고유 자료형을 가지고 있습니다. 그중 가장 중요한 것들만 써봤습니다:
참
또는 거짓
입니다.
1
이나 2
같은) 정수도 될 수 있고 (1.1
이나 1.2
같은) 실수도 될 수 있고 (1/2
이나 2/3
같은) 분수도 될 수 있고 심지어 복소수도 될 수 있습니다.
물론 이것보다 많은 자료형이 있습니다. 파이썬의 모든것은 객체이기에 모듈형, 클래스형, 메소드형, 파일형, 심지어 컴파일 코드 형 같은 것도 있죠. 일부는 이미 보았던 것들입니다: 모듈에는 이름이 있고, 함수는 참조문
을 가지는 등. 클래스형에 대해서는 클래스와 반복자 장에서 파일형에 대해서는 파일장에서 배우게 될겁니다.
문자열과 바이트는 매우 중요하고 그만큼 복잡하기도 해서 하나의 장으로 따로 빼놓았습니다. 우선은 다른것 부터 살펴보죠.
⁂
논리값은 참 또는 거짓입니다. 똑똑한 파이썬은 바로 논리값을 집어넣을 수 있도록 True
와 False
라는 두 상수를 가지고 있습니다. 식에서 논리값을 계산할 수도 있습니다. 파이썬은 (if
문 같은) 몇몇 곳에서는, 계산식의 결과가 논리값이길 기대합니다. 이런 곳들을 논리 문맥이라 합니다. 논리 문맥 안에서는 어떤 계산을 하던지 그 식의 참 또는 거짓이 판별됩니다. 각각의 자료형마다 참, 거짓을 판별하는 계산법이 틀립니다. (이 챕터 뒷부분의 구체적인 예제를 보고나면 무슨 말인지 이해가 될겁니다.)
예를 들어, 여기 humansize.py
의 일부분을 살펴보죠:
if size < 0:
raise ValueError('number must be non-negative')
size는 정수고 0도 정수고 <
는 수 연산자입니다: size < 0
식의 값은 언제나 참 또는 거짓입니다. 파이썬 바로반응 셸에서 테스트 해보세요.
>>> size = 1 >>> size < 0 False >>> size = 0 >>> size < 0 False >>> size = -1 >>> size < 0 True
파이썬 2에서의 쓰임을 물려받아 논리값은 수로 취급되기도 합니다. 참
은 1
; 거짓
은 0이지요.
>>> True + True 2 >>> True - False 1 >>> True * False 0 >>> True / False Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: int division or modulo by zero
아이쿠! 그러지 마세요. 말씀드린다는걸 깜빡했네요.
⁂
수는 굉장합니다. 많은것들이 들어있죠. 파이썬은 정수와 실수(정확하게는 부동소수)를 수라는 형태에 포함합니다. 그 둘을 다르게 선언하지 않아요; 소수점의 유무에 따라 파이썬이 그 둘을 나눕니다.
>>> type(1) ① <class 'int'> >>> isinstance(1, int) ② True >>> 1 + 1 ③ 2 >>> 1 + 1.0 ④ 2.0 >>> type(2.0) <class 'float'>
type()
함수를 써 어떤 값이나 변수의 형태를 알아볼수 잇습니다. 역시 1
은 정수형
이라고 나오네요.
isinstance()
함수를 쓰면 어떤 값이나 변수가 생각했던 형태가 맞는지 알수 있습니다.
정수
에 정수
를 더하면 정수
가 됩니다.
정수
에 실수
를 더하면 실수
가 됩니다. 파이썬은 정수
에 실수
를 더하면, 그 값을 실수
로 만들어 버립니다.
As you just saw, some operators (like addition) will coerce integers to floating point numbers as needed. You can also coerce them by yourself.
>>> float(2) ① 2.0 >>> int(2.0) ② 2 >>> int(2.5) ③ 2 >>> int(-2.5) ④ -2 >>> 1.12345678901234567890 ⑤ 1.1234567890123457 >>> type(1000000000000000) ⑥ <class 'int'>
int
to a float
by calling the float()
function.
float() 함수를 써 int형을 float형으로 강제 변환할수 있습니다.
float
to an int
by calling int()
.
int() 함수를 쓰면 float을 int로 바꿀수 있다는건 놀랍지 않겠죠?
int()
function will truncate, not round.
int() 함수는 소수점 뒷부분을 반올림하지 않고, 버립니다.
int()
function truncates negative numbers towards 0. It’s a true truncate function, not a floor function.
int() 함수는 음수의 소수 아래부분을 0에 가깝게 잘라냅니다. 이건 진짜 버리는거지, 계단형으로 만드는게 아닙니다.
☞Python 2 had separate types for
int
andlong
. Theint
datatype was limited bysys.maxint
, which varied by platform but was usually232-1
. Python 3 has just one integer type, which behaves mostly like the oldlong
type from Python 2. See PEP 237 for details. 파이썬 2에서는 int와 long형이 분리되어있었습니다. int형은 sys.maxint라는 값에 그 크기의 제한을 받고 있었습니다. (이 값은 플랫폼마다 다르기는 하지만 주로 2의 32승 - 1 입니다.) 파이썬3에서는 하나의 정수형만 존재합니다. 이 정수형은 파이썬2의 long과 거의 같다고 보시면 됩니다. 자세히 알아보려면 이 링크를 따라가세요. (링크삽입)
You can do all kinds of things with numbers. 수를 가지고 무엇이든 할 수 있습니다.
>>> 11 / 2 ① 5.5 >>> 11 // 2 ② 5 >>> −11 // 2 ③ −6 >>> 11.0 // 2 ④ 5.0 >>> 11 ** 2 ⑤ 121 >>> 11 % 2 ⑥ 1
/
operator performs floating point division. It returns a float
even if both the numerator and denominator are int
s.
/연산자는 실수 나눗셈을 합니다. 그래서 그 결과물이 항상 float으로 떨어지죠. 분모와 분자가 다 정수형이었다 하더라도요.
//
operator performs a quirky kind of integer division. When the result is positive, you can think of it as truncating (not rounding) to 0 decimal places, but be careful with that.
// 연산자는 약간 황당한 정수 나눗셈을 합니다. 만약 결과가 양수라면 소수점 이하를 (반올림 하지 않고) 버린다고 생각해도 되지만, 조심하세요.
//
operator rounds “up” to the nearest integer. Mathematically speaking, it’s rounding “down” since −6
is less than −5
, but it could trip you up if you were expecting it to truncate to −5
.
// 연산자로 음수를 나누면 그 결과값에 가까운 정수로 올림 합니다. -5 보단 -6이 더 작으니깐 정확하게 말하면 이는 내림인거죠. 만약 결과가 -5가 될거라고 생각했다면, 실수를 했을지도 모르겠네요.
//
operator doesn’t always return an integer. If either the numerator or denominator is a float
, it will still round to the nearest integer, but the actual return value will be a float
.
// 연산자는 언제나 정수 값을 내놓지는 않습니다. 분자와 분모중 하나가 실수이면, 그때도 가장 가까운 정수로 변환되긴 하지만, 실제 결과값은 실수로 나오게 됩니다.
**
operator means “raised to the power of.” 112
is 121
.
** 연산자는 제곱을 의미합니다. 11의 2승은 121이죠.
%
operator gives the remainder after performing integer division. 11
divided by 2
is 5
with a remainder of 1
, so the result here is 1
.
% 연산자는 정수 나눗셈을 하고 난 나머지를 돌려줍니다. 11을 2로 나눈 나머지는 1이죠. 그래서 결과값이 1이 된 겁니다.
☞In Python 2, the
/
operator usually meant integer division, but you could make it behave like floating point division by including a special directive in your code. In Python 3, the/
operator always means floating point division. See PEP 238 for details. 파이썬2에서, /연산자는 주로 정수연산을 의미했습니다. 하지만 코드에 특별 지시자를 넣어 실수연산을 하게 만들수도 있었죠. 파이썬3에서는 /연산자는 항상 실수연산을 의미합니다. 더 자세히는 PEP238을 보세요.
Python isn’t limited to integers and floating point numbers. It can also do all the fancy math you learned in high school and promptly forgot about.
>>> import fractions ① >>> x = fractions.Fraction(1, 3) ② >>> x Fraction(1, 3) >>> x * 2 ③ Fraction(2, 3) >>> fractions.Fraction(6, 4) ④ Fraction(3, 2) >>> fractions.Fraction(0, 0) ⑤ Traceback (most recent call last): File "<stdin>", line 1, in <module> File "fractions.py", line 96, in __new__ raise ZeroDivisionError('Fraction(%s, 0)' % numerator) ZeroDivisionError: Fraction(0, 0)
fractions
module.
Fraction
object and pass in the numerator and denominator.
Fraction
object. 2 * (1/3) = (2/3)
Fraction
object will automatically reduce fractions. (6/4) = (3/2)
You can also do basic trigonometry in Python.
>>> import math >>> math.pi ① 3.1415926535897931 >>> math.sin(math.pi / 2) ② 1.0 >>> math.tan(math.pi / 4) ③ 0.99999999999999989
math
module has a constant for π, the ratio of a circle’s circumference to its diameter.
math
module has all the basic trigonometric functions, including sin()
, cos()
, tan()
, and variants like asin()
.
tan(π / 4)
should return 1.0
, not 0.99999999999999989
.
You can use numbers in a boolean context, such as an if
statement. Zero values are false, and non-zero values are true.
>>> def is_it_true(anything): ① ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(1) ② yes, it's true >>> is_it_true(-1) yes, it's true >>> is_it_true(0) no, it's false >>> is_it_true(0.1) ③ yes, it's true >>> is_it_true(0.0) no, it's false >>> import fractions >>> is_it_true(fractions.Fraction(1, 2)) ④ yes, it's true >>> is_it_true(fractions.Fraction(0, 1)) no, it's false
0.0
is false. Be careful with this one! If there’s the slightest rounding error (not impossible, as you saw in the previous section) then Python will be testing 0.0000000000001
instead of 0 and will return True
.
Fraction(0, n)
is false for all values of n. All other fractions are true.
⁂
Lists are Python’s workhorse datatype. When I say “list,” you might be thinking “array whose size I have to declare in advance, that can only contain items of the same type, &c.” Don’t think that. Lists are much cooler than that.
☞A list in Python is like an array in Perl 5. In Perl 5, variables that store arrays always start with the
@
character; in Python, variables can be named anything, and Python keeps track of the datatype internally.
☞A list in Python is much more than an array in Java (although it can be used as one if that’s really all you want out of life). A better analogy would be to the
ArrayList
class, which can hold arbitrary objects and can expand dynamically as new items are added.
Creating a list is easy: use square brackets to wrap a comma-separated list of values.
>>> a_list = ['a', 'b', 'mpilgrim', 'z', 'example'] ① >>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[0] ② 'a' >>> a_list[4] ③ 'example' >>> a_list[-1] ④ 'example' >>> a_list[-3] ⑤ 'mpilgrim'
a_list[0]
.
a_list[4]
, because lists are always zero-based.
a_list[-1]
.
a_list[-n] == a_list[len(a_list) - n]
. So in this list, a_list[-3] == a_list[5 - 3] == a_list[2]
.
Once you’ve defined a list, you can get any part of it as a new list. This is called slicing the list.
>>> a_list ['a', 'b', 'mpilgrim', 'z', 'example'] >>> a_list[1:3] ① ['b', 'mpilgrim'] >>> a_list[1:-1] ② ['b', 'mpilgrim', 'z'] >>> a_list[0:3] ③ ['a', 'b', 'mpilgrim'] >>> a_list[:3] ④ ['a', 'b', 'mpilgrim'] >>> a_list[3:] ⑤ ['z', 'example'] >>> a_list[:] ⑥ ['a', 'b', 'mpilgrim', 'z', 'example']
a_list[1]
), up to but not including the second slice index (in this case a_list[3]
).
a_list[0:3]
returns the first three items of the list, starting at a_list[0]
, up to but not including a_list[3]
.
a_list[:3]
is the same as a_list[0:3]
, because the starting 0 is implied.
a_list[3:]
is the same as a_list[3:5]
, because this list has five items. There is a pleasing symmetry here. In this five-item list, a_list[:3]
returns the first 3 items, and a_list[3:]
returns the last two items. In fact, a_list[:n]
will always return the first n items, and a_list[n:]
will return the rest, regardless of the length of the list.
a_list[:]
is shorthand for making a complete copy of a list.
There are four ways to add items to a list.
>>> a_list = ['a'] >>> a_list = a_list + [2.0, 3] ① >>> a_list ② ['a', 2.0, 3] >>> a_list.append(True) ③ >>> a_list ['a', 2.0, 3, True] >>> a_list.extend(['four', 'Ω']) ④ >>> a_list ['a', 2.0, 3, True, 'four', 'Ω'] >>> a_list.insert(0, 'Ω') ⑤ >>> a_list ['Ω', 'a', 2.0, 3, True, 'four', 'Ω']
+
operator concatenates lists to create a new list. A list can contain any number of items; there is no size limit (other than available memory). However, if memory is a concern, you should be aware that list concatenation creates a second list in memory. In this case, that new list is immediately assigned to the existing variable a_list. So this line of code is really a two-step process — concatenation then assignment — which can (temporarily) consume a lot of memory when you’re dealing with large lists.
append()
method adds a single item to the end of the list. (Now we have four different datatypes in the list!)
extend()
method takes one argument, a list, and appends each of the items of the argument to the original list.
insert()
method inserts a single item into a list. The first argument is the index of the first item in the list that will get bumped out of position. List items do not need to be unique; for example, there are now two separate items with the value 'Ω'
: the first item, a_list[0]
, and the last item, a_list[6]
.
☞
a_list.insert(0, value)
is like theunshift()
function in Perl. It adds an item to the beginning of the list, and all the other items have their positional index bumped up to make room.
Let’s look closer at the difference between append()
and extend()
.
>>> a_list = ['a', 'b', 'c'] >>> a_list.extend(['d', 'e', 'f']) ① >>> a_list ['a', 'b', 'c', 'd', 'e', 'f'] >>> len(a_list) ② 6 >>> a_list[-1] 'f' >>> a_list.append(['g', 'h', 'i']) ③ >>> a_list ['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']] >>> len(a_list) ④ 7 >>> a_list[-1] ['g', 'h', 'i']
extend()
method takes a single argument, which is always a list, and adds each of the items of that list to a_list.
append()
method takes a single argument, which can be any datatype. Here, you’re calling the append()
method with a list of three items.
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list.count('new') ① 2 >>> 'new' in a_list ② True >>> 'c' in a_list False >>> a_list.index('mpilgrim') ③ 3 >>> a_list.index('new') ④ 2 >>> a_list.index('c') ⑤ Traceback (innermost last): File "<interactive input>", line 1, in ? ValueError: list.index(x): x not in list
count()
method returns the number of occurrences of a specific value in a list.
in
operator is slightly faster than using the count()
method. The in
operator always returns True
or False
; it will not tell you how many times the value appears in the list.
in
operator nor the count()
method will tell you where in the list a value appears. If you need to know where in the list a value is, call the index()
method. By default it will search the entire list, although you can specify an optional second argument of the (0-based) index to start from, and even an optional third argument of the (0-based) index to stop searching.
index()
method finds the first occurrence of a value in the list. In this case, 'new'
occurs twice in the list, in a_list[2]
and a_list[4]
, but the index()
method will return only the index of the first occurrence.
index()
method will raise an exception.
Wait, what? That’s right: the index()
method raises an exception if it doesn’t find the value in the list. This is notably different from most languages, which will return some invalid index (like -1
). While this may seem annoying at first, I think you will come to appreciate it. It means your program will crash at the source of the problem instead of failing strangely and silently later. Remember, -1
is a valid list index. If the index()
method returned -1
, that could lead to some not-so-fun debugging sessions!
Lists can expand and contract automatically. You’ve seen the expansion part. There are several different ways to remove items from a list as well.
>>> a_list = ['a', 'b', 'new', 'mpilgrim', 'new'] >>> a_list[1] 'b' >>> del a_list[1] ① >>> a_list ['a', 'new', 'mpilgrim', 'new'] >>> a_list[1] ② 'new'
del
statement to delete a specific item from a list.
1
after deleting index 1
does not result in an error. All items after the deleted item shift their positional index to “fill the gap” created by deleting the item.
Don’t know the positional index? Not a problem; you can remove items by value instead.
>>> a_list.remove('new') ① >>> a_list ['a', 'mpilgrim', 'new'] >>> a_list.remove('new') ② >>> a_list ['a', 'mpilgrim'] >>> a_list.remove('new') Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: list.remove(x): x not in list
remove()
method. The remove()
method takes a value and removes the first occurrence of that value from the list. Again, all items after the deleted item will have their positional indices bumped down to “fill the gap.” Lists never have gaps.
remove()
method as often as you like, but it will raise an exception if you try to remove a value that isn’t in the list.
Another interesting list method is pop()
. The pop()
method is yet another way to remove items from a list, but with a twist.
>>> a_list = ['a', 'b', 'new', 'mpilgrim'] >>> a_list.pop() ① 'mpilgrim' >>> a_list ['a', 'b', 'new'] >>> a_list.pop(1) ② 'b' >>> a_list ['a', 'new'] >>> a_list.pop() 'new' >>> a_list.pop() 'a' >>> a_list.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> IndexError: pop from empty list
pop()
list method removes the last item in the list and returns the value it removed.
pop()
method. It will remove that item, shift all the items after it to “fill the gap,” and return the value it removed.
pop()
on an empty list raises an exception.
☞Calling the
pop()
list method without an argument is like thepop()
function in Perl. It removes the last item from the list and returns the value of the removed item. Perl has another function,shift()
, which removes the first item and returns its value; in Python, this is equivalent toa_list.pop(0)
.
You can also use a list in a boolean context, such as an if
statement.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true([]) ① no, it's false >>> is_it_true(['a']) ② yes, it's true >>> is_it_true([False]) ③ yes, it's true
⁂
A tuple is an immutable list. A tuple can not be changed in any way once it is created.
>>> a_tuple = ("a", "b", "mpilgrim", "z", "example") ① >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple[0] ② 'a' >>> a_tuple[-1] ③ 'example' >>> a_tuple[1:3] ④ ('b', 'mpilgrim')
a_tuple[0]
.
The major difference between tuples and lists is that tuples can not be changed. In technical terms, tuples are immutable. In practical terms, they have no methods that would allow you to change them. Lists have methods like append()
, extend()
, insert()
, remove()
, and pop()
. Tuples have none of these methods. You can slice a tuple (because that creates a new tuple), and you can check whether a tuple contains a particular value (because that doesn’t change the tuple), and… that’s about it.
# continued from the previous example >>> a_tuple ('a', 'b', 'mpilgrim', 'z', 'example') >>> a_tuple.append("new") ① Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'append' >>> a_tuple.remove("z") ② Traceback (innermost last): File "<interactive input>", line 1, in ? AttributeError: 'tuple' object has no attribute 'remove' >>> a_tuple.index("example") ③ 4 >>> "z" in a_tuple ④ True
append()
or extend()
method.
remove()
or pop()
method.
in
operator to check if an element exists in the tuple.
So what are tuples good for?
assert
statement that shows this data is constant, and that special thought (and a specific function) is required to override that.
☞Tuples can be converted into lists, and vice-versa. The built-in
tuple()
function takes a list and returns a tuple with the same elements, and thelist()
function takes a tuple and returns a list. In effect,tuple()
freezes a list, andlist()
thaws a tuple.
You can use tuples in a boolean context, such as an if
statement.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(()) ① no, it's false >>> is_it_true(('a', 'b')) ② yes, it's true >>> is_it_true((False,)) ③ yes, it's true >>> type((False)) ④ <class 'bool'> >>> type((False,)) <class 'tuple'>
Here’s a cool programming shortcut: in Python, you can use a tuple to assign multiple values at once.
>>> v = ('a', 2, True)
>>> (x, y, z) = v ①
>>> x
'a'
>>> y
2
>>> z
True
(x, y, z)
is a tuple of three variables. Assigning one to the other assigns each of the values of v to each of the variables, in order.
This has all kinds of uses. Suppose you want to assign names to a range of values. You can use the built-in range()
function with multi-variable assignment to quickly assign consecutive values.
>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ① >>> MONDAY ② 0 >>> TUESDAY 1 >>> SUNDAY 6
range()
function constructs a sequence of integers. (Technically, the range()
function returns an iterator, not a list or a tuple, but you’ll learn about that distinction later.) MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, and SUNDAY are the variables you’re defining. (This example came from the calendar
module, a fun little module that prints calendars, like the UNIX program cal
. The calendar
module defines integer constants for days of the week.)
1
, and so forth.
You can also use multi-variable assignment to build functions that return multiple values, simply by returning a tuple of all the values. The caller can treat it as a single tuple, or it can assign the values to individual variables. Many standard Python libraries do this, including the os
module, which you'll learn about in the next chapter.
⁂
A set is an unordered “bag” of unique values. A single set can contain values of any immutable datatype. Once you have two sets, you can do standard set operations like union, intersection, and set difference.
First things first. Creating a set is easy.
>>> a_set = {1} ① >>> a_set {1} >>> type(a_set) ② <class 'set'> >>> a_set = {1, 2} ③ >>> a_set {1, 2}
{}
).
You can also create a set out of a list.
>>> a_list = ['a', 'b', 'mpilgrim', True, False, 42] >>> a_set = set(a_list) ① >>> a_set ② {'a', False, 'b', True, 'mpilgrim', 42} >>> a_list ③ ['a', 'b', 'mpilgrim', True, False, 42]
set()
function. (Pedants who know about how sets are implemented will point out that this is not really calling a function, but instantiating a class. I promise you will learn the difference later in this book. For now, just know that set()
acts like a function, and it returns a set.)
Don’t have any values yet? Not a problem. You can create an empty set.
>>> a_set = set() ① >>> a_set ② set() >>> type(a_set) ③ <class 'set'> >>> len(a_set) ④ 0 >>> not_sure = {} ⑤ >>> type(not_sure) <class 'dict'>
set()
with no arguments.
{}
, perhaps? That would denote an empty dictionary, not an empty set. You’ll learn about dictionaries later in this chapter.
There are two different ways to add values to an existing set: the add()
method, and the update()
method.
>>> a_set = {1, 2} >>> a_set.add(4) ① >>> a_set {1, 2, 4} >>> len(a_set) ② 3 >>> a_set.add(1) ③ >>> a_set {1, 2, 4} >>> len(a_set) ④ 3
add()
method takes a single argument, which can be any datatype, and adds the given value to the set.
>>> a_set = {1, 2, 3} >>> a_set {1, 2, 3} >>> a_set.update({2, 4, 6}) ① >>> a_set ② {1, 2, 3, 4, 6} >>> a_set.update({3, 6, 9}, {1, 2, 3, 5, 8, 13}) ③ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 13} >>> a_set.update([10, 20, 30]) ④ >>> a_set {1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}
update()
method takes one argument, a set, and adds all its members to the original set. It’s as if you called the add()
method with each member of the set.
update()
method with any number of arguments. When called with two sets, the update()
method adds all the members of each set to the original set (dropping duplicates).
update()
method can take objects of a number of different datatypes, including lists. When called with a list, the update()
method adds all the items of the list to the original set.
There are three ways to remove individual values from a set. The first two, discard()
and remove()
, have one subtle difference.
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set {1, 3, 36, 6, 10, 45, 15, 21, 28} >>> a_set.discard(10) ① >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.discard(10) ② >>> a_set {1, 3, 36, 6, 45, 15, 21, 28} >>> a_set.remove(21) ③ >>> a_set {1, 3, 36, 6, 45, 15, 28} >>> a_set.remove(21) ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 21
discard()
method takes a single value as an argument and removes that value from the set.
discard()
method with a value that doesn’t exist in the set, it does nothing. No error; it’s just a no-op.
remove()
method also takes a single value as an argument, and it also removes that value from the set.
remove()
method raises a KeyError
exception.
Like lists, sets have a pop()
method.
>>> a_set = {1, 3, 6, 10, 15, 21, 28, 36, 45} >>> a_set.pop() ① 1 >>> a_set.pop() 3 >>> a_set.pop() 36 >>> a_set {6, 10, 45, 15, 21, 28} >>> a_set.clear() ② >>> a_set set() >>> a_set.pop() ③ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'pop from an empty set'
pop()
method removes a single value from a set and returns the value. However, since sets are unordered, there is no “last” value in a set, so there is no way to control which value gets removed. It is completely arbitrary.
clear()
method removes all values from a set, leaving you with an empty set. This is equivalent to a_set = set()
, which would create a new empty set and overwrite the previous value of the a_set variable.
KeyError
exception.
Python’s set
type supports several common set operations.
>>> a_set = {2, 4, 5, 9, 12, 21, 30, 51, 76, 127, 195} >>> 30 in a_set ① True >>> 31 in a_set False >>> b_set = {1, 2, 3, 5, 6, 8, 9, 12, 15, 17, 18, 21} >>> a_set.union(b_set) ② {1, 2, 195, 4, 5, 6, 8, 12, 76, 15, 17, 18, 3, 21, 30, 51, 9, 127} >>> a_set.intersection(b_set) ③ {9, 2, 12, 5, 21} >>> a_set.difference(b_set) ④ {195, 4, 76, 51, 30, 127} >>> a_set.symmetric_difference(b_set) ⑤ {1, 3, 4, 6, 8, 76, 15, 17, 18, 195, 127, 30, 51}
in
operator. This works the same as lists.
union()
method returns a new set containing all the elements that are in either set.
intersection()
method returns a new set containing all the elements that are in both sets.
difference()
method returns a new set containing all the elements that are in a_set but not b_set.
symmetric_difference()
method returns a new set containing all the elements that are in exactly one of the sets.
Three of these methods are symmetric.
# continued from the previous example >>> b_set.symmetric_difference(a_set) ① {3, 1, 195, 4, 6, 8, 76, 15, 17, 18, 51, 30, 127} >>> b_set.symmetric_difference(a_set) == a_set.symmetric_difference(b_set) ② True >>> b_set.union(a_set) == a_set.union(b_set) ③ True >>> b_set.intersection(a_set) == a_set.intersection(b_set) ④ True >>> b_set.difference(a_set) == a_set.difference(b_set) ⑤ False
Finally, there are a few questions you can ask of sets.
>>> a_set = {1, 2, 3} >>> b_set = {1, 2, 3, 4} >>> a_set.issubset(b_set) ① True >>> b_set.issuperset(a_set) ② True >>> a_set.add(5) ③ >>> a_set.issubset(b_set) False >>> b_set.issuperset(a_set) False
False
.
You can use sets in a boolean context, such as an if
statement.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(set()) ① no, it's false >>> is_it_true({'a'}) ② yes, it's true >>> is_it_true({False}) ③ yes, it's true
⁂
A dictionary is an unordered set of key-value pairs. When you add a key to a dictionary, you must also add a value for that key. (You can always change the value later.) Python dictionaries are optimized for retrieving the value when you know the key, but not the other way around.
☞A dictionary in Python is like a hash in Perl 5. In Perl 5, variables that store hashes always start with a
%
character. In Python, variables can be named anything, and Python keeps track of the datatype internally.
Creating a dictionary is easy. The syntax is similar to sets, but instead of values, you have key-value pairs. Once you have a dictionary, you can look up values by their key.
>>> a_dict = {'server': 'db.diveintopython3.org', 'database': 'mysql'} ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['server'] ② 'db.diveintopython3.org' >>> a_dict['database'] ③ 'mysql' >>> a_dict['db.diveintopython3.org'] ④ Traceback (most recent call last): File "<stdin>", line 1, in <module> KeyError: 'db.diveintopython3.org'
'server'
is a key, and its associated value, referenced by a_dict['server']
, is 'db.diveintopython3.org'
.
'database'
is a key, and its associated value, referenced by a_dict['database']
, is 'mysql'
.
a_dict['server']
is 'db.diveintopython3.org'
, but a_dict['db.diveintopython3.org']
raises an exception, because 'db.diveintopython3.org'
is not a key.
Dictionaries do not have any predefined size limit. You can add new key-value pairs to a dictionary at any time, or you can modify the value of an existing key. Continuing from the previous example:
>>> a_dict {'server': 'db.diveintopython3.org', 'database': 'mysql'} >>> a_dict['database'] = 'blog' ① >>> a_dict {'server': 'db.diveintopython3.org', 'database': 'blog'} >>> a_dict['user'] = 'mark' ② >>> a_dict ③ {'server': 'db.diveintopython3.org', 'user': 'mark', 'database': 'blog'} >>> a_dict['user'] = 'dora' ④ >>> a_dict {'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'} >>> a_dict['User'] = 'mark' ⑤ >>> a_dict {'User': 'mark', 'server': 'db.diveintopython3.org', 'user': 'dora', 'database': 'blog'}
'user'
, value 'mark'
) appears to be in the middle. In fact, it was just a coincidence that the items appeared to be in order in the first example; it is just as much a coincidence that they appear to be out of order now.
user
key back to "mark"? No! Look at the key closely — that’s a capital U in "User". Dictionary keys are case-sensitive, so this statement is creating a new key-value pair, not overwriting an existing one. It may look similar to you, but as far as Python is concerned, it’s completely different.
Dictionaries aren’t just for strings. Dictionary values can be any datatype, including integers, booleans, arbitrary objects, or even other dictionaries. And within a single dictionary, the values don’t all need to be the same type; you can mix and match as needed. Dictionary keys are more restricted, but they can be strings, integers, and a few other types. You can also mix and match key datatypes within a dictionary.
In fact, you’ve already seen a dictionary with non-string keys and values, in your first Python program.
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'],
1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}
Let's tear that apart in the interactive shell.
>>> SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], ... 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']} >>> len(SUFFIXES) ① 2 >>> 1000 in SUFFIXES ② True >>> SUFFIXES[1000] ③ ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] >>> SUFFIXES[1024] ④ ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'] >>> SUFFIXES[1000][3] ⑤ 'TB'
len()
function gives you the number of keys in a dictionary.
in
operator to test whether a specific key is defined in a dictionary.
1000
is a key in the SUFFIXES
dictionary; its value is a list of eight items (eight strings, to be precise).
1024
is a key in the SUFFIXES
dictionary; its value is also a list of eight items.
SUFFIXES[1000]
is a list, you can address individual items in the list by their 0-based index.
You can also use a dictionary in a boolean context, such as an if
statement.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true({}) ① no, it's false >>> is_it_true({'a': 1}) ② yes, it's true
⁂
None
None
is a special constant in Python. It is a null value. None
is not the same as False
. None
is not 0. None
is not an empty string. Comparing None
to anything other than None
will always return False
.
None
is the only null value. It has its own datatype (NoneType
). You can assign None
to any variable, but you can not create other NoneType
objects. All variables whose value is None
are equal to each other.
>>> type(None) <class 'NoneType'> >>> None == False False >>> None == 0 False >>> None == '' False >>> None == None True >>> x = None >>> x == None True >>> y = None >>> x == y True
None
In A Boolean ContextIn a boolean context, None
is false and not None
is true.
>>> def is_it_true(anything): ... if anything: ... print("yes, it's true") ... else: ... print("no, it's false") ... >>> is_it_true(None) no, it's false >>> is_it_true(not None) yes, it's true
⁂
fractions
module
math
module
© 2001–11 Mark Pilgrim