~ Tips for Python beginners from Pythonista with love ② ~

It is a continuation of Tips ① I will write it briefly, so I think that there are many things that are not strict, but if there are any mistakes, please comment ~

List, tuple, set, dictionary tips

List type

I've used the list type several times, so you know it, but it's an array with no size specified. Since it is a list object, it is okay to write ʻa = list () in addition to ʻa = []. The list type guarantees the order of the elements.

python:Python3.5.0


>>> a = [1,2,3,4,5,6,7,8,9]
>>> a.append(0) #Add element 0 after
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> a.insert(1,0) #Add element 0 to the specified index number
>>> a
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> a[0] #Access element with index 0
1
>>> a[2] #Index accesses second element
2
>>> a[-1] #Index accesses the first element from the back(There is no 0)
0
>>> a[2:5] #Index accesses the 2nd to 5th elements
[2, 3, 4]
>>> a[2:-2] #Index accesses the second element from the first to the second
[2, 3, 4, 5, 6, 7, 8]
>>> a[2:-2:2] ##The index accesses the second element from the first to the second element in two steps.
[2, 4, 6, 8]
>>> b = [1.1, 1.2, 1.3, 1.4, 1.5]
>>> a.extend(b) #Joining lists
>>> a
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1.1, 1.2, 1.3, 1.4, 1.5]
>>> a.pop() #Extract and delete the last element in the list
1.5
>>> a
[1, 0, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1.1, 1.2, 1.3, 1.4]
>>> sorted(a) #sort(ascending order)
[0, 0, 1, 1.1, 1.2, 1.3, 1.4, 2, 3, 4, 5, 6, 7, 8, 9]
>>> sorted(a, reverse=True) #sort(descending order)
[9, 8, 7, 6, 5, 4, 3, 2, 1.4, 1.3, 1.2, 1.1, 1, 0, 0]
>>> len(a) #List length
16

List comprehension

I'm finally here ... This is unique to Python! !! The example given earlier in the for statement

python:Python3.5.0


>>> for i in range(1,10):
...     a.append(i)
... 
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

This can be written in one line.

python:Python3.5.0


>>> a = [i for i in range(1,10)]
>>> a
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

It may be a little unpleasant at first glance, but it is quite convenient once you get used to it. By the way, it seems that the execution speed is faster than turning it with a for statement normally.

python:Python3.5.0


>>> a = [i for i in range(1,10) if i % 2 == 0]
>>> a
[2, 4, 6, 8]
>>> a = [i if i % 2 == 0 else i*i for i in range(1,10)]
>>> a
[1, 2, 9, 4, 25, 6, 49, 8, 81]
>>> a = [[j for j in range(i)] for i in range(1,10)]
>>> a
[[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7, 8]]
>>> 

It can be obfuscated as much as you want, so moderately ...

Objects are basically passed by reference

Note that in Python objects are passed by reference. int / float / str / unicode (2.x series) looks like passing by value, but passing by reference of immutable object (it's not wrong ...). Well, you should be aware that list types are passed by reference (same for tuple types, set types, and dictionary types). So if you want to pass it as an argument to another variable or function, you need to copy it explicitly.

python:Python3.5.0


>>> a = [i for i in range(10)]
>>> b = a
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> a.pop()
9
>>> a
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> b #b is also gone! !!
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> c = list(a) #This will be a copy(Different instances are generated)
>>> from copy import copy
>>> d = copy(c) #copy module can also be used
>>> a.pop()
8
>>> a
[0, 1, 2, 3, 4, 5, 6, 7]
>>> b
[0, 1, 2, 3, 4, 5, 6, 7]
>>> c
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> d
[0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> 

However, it should be noted that list (a) and copy (a) are shallow copies. A shallow copy means that deep objects such as those with nested lists in the list are not copied, only the shallowest objects are copied and deeper objects are passed by reference (difficult to explain). This is solved by using deepcopy in the copy module.

python:Python3.5.0


>>> a = [[j for j in range(4)] for i in range(4)]
>>> a
[[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> from copy import copy
>>> b = copy(a) #Shallow copy
>>> a[0].pop() #Pop from the list of elements
3
>>> a #Popped items disappear from the list of elements
[[0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> b #The popped one disappears from the list of copied list elements! !!
[[0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> from copy import deepcopy
>>> c = deepcopy(a) #Deep copy
>>> a[0].pop()
2
>>> a
[[0, 1], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> b
[[0, 1], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> c #Not disappear! !!
[[0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
>>> a is b #The shallowest object instances are different
False
>>> a[0] is b[0] #Objects stored deeper than that will be the same instance by passing by reference
True
>>> a[0] is c[0] #deepcopy ↓ Objects are passed by value even for deep objects
False
>>> 

Tuple type

The tuple type is represented by tuple. A tuple type is basically an arrangement of elements like a list, but once a value is stored, that value cannot be changed.

python:Python3.5.0


>>> a = tuple() #Empty tuple
>>> a = (1,2,3,4,5) #1~Tuples with 5 in order
>>> a[1] #Index accesses the first element
2
>>> a[1:3] #Access the elements whose index is from 1st to 3rd
(2, 3)
>>> a[0:5:2] #Access the elements with indexes 0 to 5 in step 2
(1, 3, 5)
>>> a[0] = 1 #An error occurs when assigning
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a = (1,) #Generate tuples
>>> a
(1,)
>>> a = (1) #,Without it, it won't be a tuple
>>> a
1
>>> 

The only caveat is that it doesn't become a tuple without a comma.

Collective type

The set type is represented by set. In the aggregate type, it is a collection of elements like the list type, but the order is not guaranteed as it does not allow duplicate elements.

python:Python3.5.0


>>> a = set() #Empty set
>>> a
set([])
>>> a = {i for i in range(10)} #Comprehension notation
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.add(10) #Add 10
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> a.add(10) #Add 10(It doesn't change because it already exists)
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> a = set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
>>> a.remove(10) #Delete 10
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.remove(10) #Delete 10(It will be an error because it is not in the element)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 10
>>> a.add(10)
>>> a.discard(10) #Delete 10
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.discard(10) #Delete 10(If not, do nothing)
>>> a
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b = {1,2,3,4,5}
>>> b.issubset(a) #Is b a subset of a?
True
>>> b.issuperset(a) #Whether a is a subset of b
False
>>> c = {2,4,6,8,10,12,14,16,18,20}
>>> a.union(c) #Union of two sets
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20])
>>> a.intersection(c) #The intersection of two sets
set([8, 2, 4, 6])
>>> a.difference(c) #Element of a and not element of c(a-c)set
set([0, 1, 3, 5, 7, 9])
>>> a.symmetric_difference(c) #Exclusive OR of two sets
set([0, 1, 3, 5, 7, 9, 10, 12, 14, 16, 18, 20])
>>> a_copy = a.copy() #Copy of the set(Pass by value)
>>> a is a_copy #Different instances due to passing by value
False
>>> a == a_copy #The value is the same
True
>>> a_copy.update(c) #Add elements of other sets to the target set
>>> a_copy
set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 20])
>>> a_copy.pop() #Extract and delete any element
0
>>> a_copy.clear() #Remove all elements
>>> a_copy
set([])
>>> 

** ~~ @ zakuro9715 pointed out and added and corrected hashing ~~ **

** Fixed the hashing pointed out on Twitter **

It's important that the elements are hashed and sorted, as is the case when you want to avoid duplication of elements as a use of sets (maybe to eliminate duplication of elements, maybe). This is because the hash table is used when scanning the elements, so on average you can go with O (1) *, but otherwise it will be O (N). In other words, it works best when you do something like ʻa in b. The list type requires N × len (b) scans if you do something like ʻa in b in N loops because the elements are not hashed. On the other hand, aggregate (and dictionary-type keys) are hashed, so no such scan is done. Therefore, if there are many loops and many elements, it is recommended to cast to a set type and then judge the condition such as ʻa in b`.

Dictionary type

The dictionary type is represented by dict. In the dictionary type, it is stored as a key / value pair.

** In response to @ zakuro9715's point, I added and corrected the key settings ** The ~~ key (or value) can be set on any object. ~~ The key can be set ** if it is a hashable object **. (For example, you cannot set a dict that has a dict as a key) Any object can be set for the value.

python:Python3.5.0


>>> a = dict() #Generate empty dictionary type
>>> a = {str(i)+u"Th": i*i for i in range(10)}
>>> a
{'First': 1, '0th': 0, '7th': 49, '4th': 16, '8th': 64, '6th': 36, '9th': 81, 'Fifth': 25, 'The second': 4, 'The third': 9}
>>> a["0th"] #"0th"Get the value of the key
0
>>> a["Fifth"] #"Fifth"Get the value of the key
25
>>> a["10th"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: '10th'
>>> a.get(u"10th") #"10th"Get the value of the key(No but returns None instead of an error)
>>> a.get(u"10th", 100) #"10th"Get the value of the key. If not, the value set in the second argument is returned.
100
>>> a.get(u"9th", "100") #"9th"Get the value of the key. If not, the value set in the second argument is returned.
81
>>> a.keys() #Dict the key_Return as an object called keys (list in 2 series)
dict_keys(['4th', 'The third', 'Fifth', 'The second', '8th', '0th', '9th', 'First', '7th', '6th'])
>>> a.values() #Dict the value_Return as an object called values (list in 2 series)
dict_values([16, 9, 25, 4, 64, 0, 81, 1, 49, 36])
>>> a.items() #Dict the tuple of keys and values_Return as an object called items (list in 2 series)
dict_items([('4th', 16), ('The third', 9), ('Fifth', 25), ('The second', 4), ('8th', 64), ('0th', 0), ('9th', 81), ('First', 1), ('7th', 49), ('6th', 36)])
>>> "First" in a #Check if there is a key
True
>>> del a["0th"] #Delete the value of the corresponding key
>>> a.pop(u"First") #Get the value of the corresponding key and delete it
1
>>> a.popitem() #Get and delete any item
('4th', 16)
>>> a 
{'The third': 9, 'Fifth': 25, 'The second': 4, '8th': 64, '9th': 81, '7th': 49, '6th': 36}
>>> b = a #Pass by reference
>>> c = a.copy() #Pass by value
>>> a is b #Same instance
True
>>> a is c #Different instances
False
>>> a == c #The value is the same
True
>>> a.clear() #Delete all
>>> a
{}
>>> b #Deleted because it is the same instance
{}
>>> c #It doesn't change because it's a different instance
{'9th': 81, 'Fifth': 25, 'The second': 4, '8th': 64, 'The third': 9, '7th': 49, '6th': 36}
>>> 
>>> a = {str(i)+"Th": i*i for i in range(10)} #Dictionary comprehension
>>> a_copy = a.copy()
>>> a_copy.update({"0th": 10})
>>> a_copy["0th"]
10
>>> 

List and dictionary tips

There are many useful ways to count and iterate, especially in lists and dictionaries, so here are some that you might use with your own judgment and prejudice.

Convenient iteration

python:Python3.5.0


>>> a = [i for i in range(1,6)]
>>> #Output with index number
>>> for i, num in enumerate(a):
...     print "{}Element of the second index:{}".format(i, num)
... 
0th index element: 1
First index element: 2
Second index element: 3
Third index element: 4
Fourth index element: 5
>>> #Iterate two lists at the same time
>>> b = [str(i)+u"Second index" for i in range(5)]
>>> for a_num, b_num in zip(a, b):
...     print(b_num+u":"+str(a_num))
... 
0th index: 1
1st index: 2
Second index: 3
Third index: 4
4th index: 5
>>> c = [[j**i for j in range(1,5)] for i in range(1,5)]
>>> c
[[1, 2, 3, 4], [1, 4, 9, 16], [1, 8, 27, 64], [1, 16, 81, 256]]
>>> #Can also be used for transposition
>>> c_t = [[i, j, k, l] for i, j, k, l in zip(*c)]
>>> c_t
[[1, 1, 1, 1], [2, 4, 8, 16], [3, 9, 27, 81], [4, 16, 64, 256]]
>>> 
>>> from itertools import product, permutations, combinations, combinations_with_replacement
>>> #Behavior when nesting for statements(You can specify the nesting depth with repeat)
>>> for pear in product(a, repeat=2):
...     print(pear)
... 
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 3)
(3, 4)
(3, 5)
(4, 1)
(4, 2)
(4, 3)
(4, 4)
(4, 5)
(5, 1)
(5, 2)
(5, 3)
(5, 4)
(5, 5)
>>> #Permutation that does not allow covering
>>> for pear in permutations(a, 2):
...     print(pear)
... 
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 1)
(2, 3)
(2, 4)
(2, 5)
(3, 1)
(3, 2)
(3, 4)
(3, 5)
(4, 1)
(4, 2)
(4, 3)
(4, 5)
(5, 1)
(5, 2)
(5, 3)
>>> #A combination that does not allow covering
>>> for pear in combinations(a, 2):
...     print(pear)
... 
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 3)
(2, 4)
(2, 5)
(3, 4)
(3, 5)
(4, 5)
>>> #Combination that allows for covering
>>> for pear in combinations_with_replacement(a, 2):
...     print(pear)
... 
(1, 1)
(1, 2)
(1, 3)
(1, 4)
(1, 5)
(2, 2)
(2, 3)
(2, 4)
(2, 5)
(3, 3)
(3, 4)
(3, 5)
(4, 4)
(4, 5)
(5, 5)
>>> 
Special dictionary (defaultdict, Counter)

python:Python3.5.0


>>> from itertools import combinations
>>> from collections import defaultdict, Counter
>>> 
>>> #Creating a dictionary with nested dictionaries
>>> a = {}
>>> for key, val in combinations([i for i in range(6)], 2):
...     if key not in a:
...             a[key] = {}
...     a[key][val] = key*val
... 
>>> a
{0: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 1: {2: 2, 3: 3, 4: 4, 5: 5}, 2: {3: 6, 4: 8, 5: 10}, 3: {4: 12, 5: 15}, 4: {5: 20}}
>>>
>>> a = defaultdict(dict)
>>> for key, val in combinations([i for i in range(6)], 2):
...     a[key][val] = key*val
... 
>>> a
defaultdict(<type 'dict'>, {0: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 1: {2: 2, 3: 3, 4: 4, 5: 5}, 2: {3: 6, 4: 8, 5: 10}, 3: {4: 12, 5: 15}, 4: {5: 20}})
>>>
>>>
>>> #To store the count for a key in a dictionary
>>> a = {}
>>> for key, val in combinations([i for i in range(6)], 2):
...     if key in a:
...             a[key] += val
...     else:
...             a[key] = val
... 
>>> a
{0: 15, 1: 14, 2: 12, 3: 9, 4: 5}
>>> a = Counter()
>>> for key, val in combinations([i for i in range(6)], 2):
...     a[key] += val
>>> a
Counter({0: 15, 1: 14, 2: 12, 3: 9, 4: 5})
>>> 

If you are interested in other things, please see Reference.

function

Then about how to write a function. Here, as a basic function writing method, I will write about the function definition statement / argument writing method (default setting) / return value (return, yield).

python:Python3.5.0


>>> #The most basic way of writing
>>> def hello():
...     print("Hello world!!")
... 
>>> hello()
Hello world!!
>>> 
>>> #How to write when there is an argument
>>> def hello_name(name):
...     print("Hello {}!!".format(name))
... 
>>> hello_name("Guido")
Hello Guido!!
>>> 
>>> #How to write when the argument has a default value
>>> def hello_name(name="world"):
...     print("Hello {}!!".format(name))
... 
>>> hello_name()
Hello world!!
>>> hello_name("Guido")
Hello Guido!!
>>> 
>>> #How to write when there is a return value
>>> def hello_return(name):
...     return "Hello {}!!".format(name)
... 
>>> result = hello_return("Guido")
>>> print(result)
Hello Guido!!
>>> 
>>> #Return value(Generator type)How to write when there is
>>> def hello_yield(name):
...     for s in name:
...             yield s
... 
>>> generater = hello_yield("Hello Guido!!")
>>> generater.next()
'H'
>>> generater.next()
'e'
>>> generater.next()
'l'
>>> generater.next()
'l'
>>> generater.next()
'o'
>>> generater.next()
' '
>>> generater.next()
'G'
>>> generater.next()
'u'
>>> generater.next()
'i'
>>> generater.next()
'd'
>>> generater.next()
'o'
>>> generater.next()
'!'
>>> generater.next()
'!'
>>> generater.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

As a beginner, the generator expression may be difficult to understand, but you don't have to think hard, just think "remember the previous call state and return the next state withnext ()". If there is no next state, an exception of StopIteration class will be thrown, so it is better to control with try / except when actually using it.

python:Python3.5.0


>>> generater = hello_yield("Hello Guido!!")
>>> while True:
...     try:
...             result = generater.next()
...             print(result)
...     except StopIteration:
...             break
... 
H
e
l
l
o
 
G
u
i
d
o
!
!
>>> 

class

Difference between 2.x series and 3.x series

First of all, about the basic way of writing a class, I will write it there because it is a little different between 2 series and 3 series.

python:Python2.7.9


>>> class Hello(object):
...     prefix = "Hello "
...     def hello(self, name="world"):
...             print(self.prefix+name+"!!")
... 
>>> HelloInstance = Hello()
>>> HelloInstance.hello()
Hello world!!
>>> 

This is a two-system writing style that inherits the base class ʻobject, which is a new class style. Be sure to write self in the first argument of the instance method hello as a reserved word. This is to refer to yourself (instance), this in PHP. In other words, writing ʻInstance.method (val) will be read as Class.method (self, val). There is also an old class style, so you can write only class Hello: without writing ʻobject. However, the new style and the old style have different specifications (inheritance priority / class method, static method / property), so the new class style is recommended. This is also because we made improvements without breaking the old specifications. On the other hand, in the 3rd series, class Hello:` will be the new class style in the 2nd series. The operation does not change, but I will write it for the time being.

python:Python3.5.0


>>> class Hello:
...     prefix = "Hello "
...     def hello(self, name="world"):
...             print(self.prefix+name+"!!")
... 
>>> HelloInstance = Hello()
>>> HelloInstance.hello()
Hello world!!
>>> 

constructor

Strictly speaking, it is not a constructor, but Python has a method called when creating an instance called __init__, and you can write constructor-like processing here.

python:Python3.5.0


>>> class Hello:
...     def __init__(self, prefix="Hello "):
...         self.prefix = prefix
...     def hello(self, name="world"):
...             print(self.prefix+name+"!!")
... 
>>> HelloInstance = Hello()
>>> HelloInstance.hello()
Hello world!!
>>> HelloInstance.hello("Guido")
Hello Guido!!
>>> HelloInstance = Hello("Hey ")
>>> HelloInstance.hello("Guido")
Hey Guido!!
>>> 

By the way, there is a method called __new__ that is called before __init__. It returns its own instance, and __init__ is executed when its own instance is returned. You can customize __new__ to return an instance other than yourself, but there is no benefit. .. .. Well, it's not completely out of the question, and you can write a metaclass, but is it for beginners? I feel like that, so I will omit it. (Tips for getting out of beginners / Tips for intermediate users will be written in another article)

Method arguments (instance, class, static)

In Python, if you define a method in a class, it is an instance method unless otherwise specified. As mentioned earlier, the first argument of the instance method is self, which points to your own instance. However, you can also write class methods and static methods. The differences in operation as well as how to write instance methods, class methods, and static methods are shown below, but you may not understand it unless you understand object orientation in the first place.

python:Python3.5.0


>>> class Hello:
...     prefix = "Hello "
...     def __init__(self, prefix=None):
...         if prefix:
...             self.prefix = prefix + " "
...     def hello(self, name="world"):
...         """
...Instance method: The first argument is self
...         """
...         print(self.prefix+name+"!!")
...     @classmethod
...     def hello_cls(cls, name="world"):
...         """
...Class method: The first argument is cls
...         """
...         print(cls.prefix+name+"!!")
...     @staticmethod
...     def hello_stc(name="world"):
...         """
...Static method: The first argument is not a reserved word
...         """
...         print(name+"!!")
...     @classmethod
...     def set_class_prefix(cls, prefix):
...         cls.prefix = prefix + " "
... 
>>> HelloInstance1 = Hello("Hey") #Instance prefix(self.prefix)To Hey
>>> HelloInstance1.hello("Guido!!")
Hey Guido!!!!
>>> HelloInstance1.hello_cls("Guido!!") #Since it is a class method, the prefix to access is the prefix of the class
Hello Guido!!!!
>>> 
>>> HelloInstance2 = Hello("Hi") #Instance prefix(self.prefix)To Hey
>>> HelloInstance2.hello("Guido!!")
Hi Guido!!!!
>>> HelloInstance2.hello_cls("Guido!!")
Hello Guido!!!!
>>> 
>>> HelloInstance2.set_class_prefix("I'm") #Rewrite class variables from HelloInstance2
>>> HelloInstance2.hello("Guido!!") #Instance variables do not rewrite
Hi Guido!!!!
>>> HelloInstance2.hello_cls("Guido!!") #Class variables are rewritten
I'm Guido!!!!
>>> #Another instance
>>> HelloInstance1.hello("Guido!!") #Instance variables do not rewrite
Hey Guido!!!!
>>> HelloInstance1.hello_cls("Guido!!") #Since it is a class variable, it will be rewritten! !!
I'm Guido!!!!
>>> 
>>> Hello.hello_stc() #Static methods can be called from a class
world!!
>>> 

The point to note is that if you rewrite a class variable from a class method, the class variable of another instance will also change (it's a class variable, not an instance variable, so it's quite natural).

Underscore hell and special methods

It is __ (two underscores) such as __name__, __init__, __new__, __call__ that you often see when using Python, but it is used for special methods. Here are some common special methods:

Special method function Example of use
__doc__ Document string View the documentation on the object. object.__doc__
__name__ Imported file name or executable file When executing a file. if__name__ == '__main__'
__dict__ Contains the attributes of the object Get object attributes from strings, etc.
__init__ Method called when instantiating X = Class()
__new__ Factory class when creating a new instance of a lath It is also possible to override and create a meta class
__call__ Method called when the function is executed X()
__del__ Method called when destroying an object del object
__add__ Addition(+)Methods called when using operators Overrideable and customizable
__iter__ Method called during loop for loop. Comprehension notation
__getattr__ Access to attributes X.attr
__setattr__ Assignment to attribute X.attr = x

Multiple inheritance and name mangling

Multiple inheritance is possible in Python. Here is an example of multiple inheritance just in case.

python:Python3.5.0


>>> class Hello:
...     prefix = "Hello "
...     def say(self, name):
...         return self.prefix + name
... 
>>> 
>>> class Hey:
...     prefix = "Hey "
...     def say(self, name):
...         return self.prefix + name + "!"
... 
>>> 
>>> class HowAreYou(Hello, Hey):
...     def __init__(self, name, *args, **kargs):
...         #Parent class initialization
...         #In this example the parent class__init__Nothing is executed because is not defined
...         super(HowAreYou, self).__init__(*args, **kargs)
...         self.name = name
...     def output(self):
...         greet = self.say(self.name)
...         print(greet, "How are you?")
... 
>>> 
>>> X = HowAreYou("Guido")
>>> X.output()
('Hello Guido', 'How are you?')
>>> 

As mentioned above, it's like creating a class by inheriting two or more classes. Well, if you explain here, you have to explain from object-oriented programming. I'll leave that to other articles.

However, what should be noted here is the movement when HowAreYou.output () is executed. In the case of multiple inheritance, attributes may conflict with each other. In this example as well (intentionally), the say attributes conflict with each other. In Python, it is decided which parent class is prioritized when multiple inheritance is performed. Basically, ① has priority over ② in the order of ① "left to right" ② "bottom to top" (② has priority over ① in the old style class). So in this case, HowAreYou.output () gives priority toHello.say (). Similarly, self.prefix takes precedence over Hello.prefix.

Of course, I think there are attributes that I want to have multiple inheritance but I don't want them to collide with each other (although I think it's better to design so that they don't have multiple inheritance, of course). The function used at that time is ** Nameman Gring **. Specifically, two underscores are prepended to the attribute name. Then it will be automatically interpreted as _Class__attr.

python:Python3.5.0


>>> class Hello:
...     __prefix = "Hello "
...     def __say(self, name):
...         return self.__prefix + name
... 
>>> class Hey:
...     __prefix = "Hey "
...     def __say(self, name):
...         return self.__prefix + name + "!"
... 
>>> class HowAreYou(Hello, Hey):
...     def __init__(self, name, *args, **kargs):
...         #Parent class initialization
...         #In this example the parent class__init__Nothing is executed because is not defined
...         super(HowAreYou, self).__init__(*args, **kargs)
...         self.name = name
...     def hello_output(self):
...         greet = self._Hello__say(self.name) #Hello__Call say
...         print(greet, "How are you?")
...     def hey_output(self):
...         greet = self._Hey__say(self.name) #Hey's__Call say
...         print(greet, "How are you?")
... 
>>> X = HowAreYou("Guido")
>>> X.hello_output() #Use Hello say
('Hello Guido', 'How are you?')
>>> X.hey_output() #Use Hey say
('Hey Guido!', 'How are you?')
>>> dir(X) #Show X attributes
['_Hello__prefix', '_Hello__say', '_Hey__prefix', '_Hey__say', '__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'hello_output', 'hey_output', 'name']
>>> 

As mentioned above, just add two underscores (__) and the attribute name is preceded by the _class name. ** I thought I wrote it, but this may not be something to teach beginners ʕº̫͡ºʔ **

Is there concealment?

Unlike Java, Python cannot hide attributes. However, you can do something like that by using underscores. As mentioned earlier, name mangling can be used to prevent attributes of the same name from colliding with each other in different classes. Although it is not the original usage, you can hide (like) the attributes you want to hide by using this function. Also, _x and __x have slightly different meanings (can be used properly), so I will explain them.

python:Python3.5.0


>>> class Hello:
...     def __init__(self):
...         self._prefix = "Hello" #1 underscore
...         self.__prefix = "Hey" #2 underscores
... 
>>> HelloInstance = Hello()
>>> HelloInstance._prefix #Underscore One attribute can be accessed
'Hello'
>>> HelloInstance.__prefix #Underscore Two attributes cannot be accessed as they are
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Hello' object has no attribute '__prefix'
>>> HelloInstance._Hello__prefix #Can be accessed according to the name mangling
'Hey'
>>> 

If there is only one underscore, it will be accessible, so it is just a prefix to indicate a local variable as a coding standard. However, in the case of two underscores, the name mangling automatically assigns a _class name, so you cannot access it with the same name. It cannot be completely hidden in this way, but it can be hidden in a pseudo manner.

Tired ②

I wrote it briefly, but I was tired, so I will continue with ③

Click here for Tips ① Click here for Tips ③

Recommended Posts

~ Tips for Python beginners from Pythonista with love ① ~
~ Tips for Python beginners from Pythonista with love ② ~
~ Tips for beginners to Python ③ ~
INSERT into MySQL with Python [For beginners]
Tips for dealing with binaries in Python
Tips for using python + caffe with TSUBAME
WebApi creation with Python (CRUD creation) For beginners
[For beginners] Try web scraping with Python
Causal reasoning and causal search with Python (for beginners)
Tips for Python beginners to use the Scikit-image example for themselves 9 Use from C
Wrap C with Cython for use from Python
python textbook for beginners
Wrap C ++ with Cython for use from Python
OpenCV for Python beginners
[Introduction for beginners] Working with MySQL in Python
Learning flow for Python beginners
[Tips] Handle Athena with Python
Python3 environment construction (for beginners)
Python #function 2 for super beginners
Basic Python grammar for beginners
100 Pandas knocks for Python beginners
Python for super beginners Python #functions 1
[Python + Selenium] Tips for scraping
Python #list for super beginners
With skype, notify with skype from python!
Tips for Python beginners to use Scikit-image examples for themselves 4 Use GUI
Tips for developing apps with Azure Cosmos DB in Python
[For beginners] Script within 10 lines (4. Connection from python to sqlite3)
Introduction to Python for VBA users-Calling Python from Excel with xlwings-
Tips for Python beginners to use the Scikit-image example for themselves
Get data from analytics API with Google API Client for python
Solve AtCoder Problems Boot camp for Beginners (Medium 100) with python
Python Exercise for Beginners # 2 [for Statement / While Statement]
Using Rstan from Python with PypeR
Install Python from source with Ansible
Create folders from '01' to '12' with python
Tips for running Go with docker
Python for super beginners Python # dictionary type 1 for super beginners
Getting Started with Python for PHPer-Classes
Getting Started with Julia for Pythonista
Python #index for super beginners, slices
Run Aprili from Python with Orange
<For beginners> python library <For machine learning>
[TouchDesigner] Tips for for statements using python
Python #len function for super beginners
Beginners use Python for web scraping (1)
Run unittests in Python (for beginners)
Beginners use Python for web scraping (4) ―― 1
Read fbx from python with cinema4d
Python #Hello World for super beginners
Python for super beginners Python # dictionary type 2 for super beginners
Getting Started with Python for PHPer-Functions
Collecting information from Twitter with Python (Twitter API)
Easy keyword extraction with TermExtract for Python
Receive textual data from mysql with python
Get html from element with Python selenium
[Note] Get data from PostgreSQL with Python
I tried to refer to the fun rock-paper-scissors poi for beginners with Python
WEB scraping with Python (for personal notes)
python tips
Play audio files from Python with interrupts