python 学习笔记

Basic Skills

module

python 文件可以当做主文件进行运行或者当做函数的集合进行调用。如果是前者一般是需要包含"_name_ =="__main__"。对于后者就是在其他的python文件中进行调用。

1
2
    import my_module # python文件
    from my_module import my_object 

packages

from packageroot.packagefolder.mod import my_object

Note: Ensure each directory within your package import contains a file _init_.py

python-path

python2 和python3 使用不同的解释器,导致在一些函数命名和计算上有一些差别,最好在文件的开头标明使用的解释器。

while or for

while : provide a condition and run the loop until the condition is not met.

for: loop for a number of specific times; loop over items or characters of a string.

examples:

1
2
3
4
    [Variable] AggregateFunction([Value] for [item] in [collection])
    x =[1, 2,3, 4, 5]
    y =[ 2*a for a in x if a%2 ==0]
    y >> [4, 8]

或者可以使用这样更加简洁的语句:

1
2
3
    lambda arguments : expression
    fun1 = lambda a,b,c : a+b+c
    print(fun1(5,6,2))

来个比较复杂的例子:

1
2
3
4
5
    nums =[1,2,3,4,5]
    letters =['a', 'b', 'c','d','e']
    # 两个for 循环也是要熟练
    nums_letters =[[n, l] for n in nums for l in letters ]
    nums_letters

break, continue, or pass

这三个关键词是python 语言中的循环控制。总结说,break 是跳出”整个“循环,continue 是跳出”本次“循环, pass 是不做任何事情,表达语义的完整,这个类似 Todo 项目,提醒自己之后需要完成这部分程序功能。ß

The break, continue, and pass statements in Python will allow you to use for loops and while loops more effectively in your code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
    number = 0
    for number in range(10):
       number = number + 1
    
       if number == 5:
          pass    # pass here
    
       print('Number is ' + str(number))
    
    print('Out of loop')

pass 关键词的作用:

  1. 空语句 do nothing
  2. 保证格式完整
  3. 保证语义完整

简单来说就是占位,没有什么实质性的内容。

The pass statement occurring after the if conditional statement is telling the program to continue to run the loop and ignore the fact that the variable number evaluates as equivalent to 5 during one of its iterations.

yield 可以用用作新的 if的测试, return results without termination

The pass statement can create minimal classes, or act as a placeholder when working on new code and thinking on an algorithmic level before hammering out details. pass 的存在就是占坑,否则这个地方就是报错(IndentationError)。用于想要扩展的地方,但是现在还没有扩展。比如在某个method 下面或者某个 if 条件下。

yield or return

yield 经常被用来作为生成器,返回但是却没有解决函数,下一回从上一回的位置开始。

when you call a normal function with a return statement the function is terminated whenever it encounters a return statement. In a function with a yield statement the state of the function is ‘saved’ from the last call and can be picked up the next time you call a generator function.

for examples

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
    gen_exp =(x **2 for x in range(10) if x %2 ==0)
    for x in gen_exp:
      print(x)
    
    def my_gen():
      for x in range(5):
        yield x
    
    gen1 =my_gen()
    next(gen1)
    
    def my_generator1():
      yield 1
      yield 2
      yield 3
      
    my_gen =my_generator1()
    # 使用 next() 进行调用下一个
    next(my_gen)

recursion

A function calling itself is known as recursion.( recursion 是递归, iteration 是循环)

list, tuples, or dictionary

在python 中是使用频繁的data structure,这个是属于 collection 类别,里面放的是element.

list: to add/update/ delete an item of a collection

1
2
3
4
5
6
    my_list.append('C') #adds at the end
    my_list[1] = 'D' #update
    my_list.pop(1) # removes
    
    mylist.pop() # 默认就是类似 栈的结构,就是pop 出来最后一个
    mylist.pop(0) # 当然也可以根据index 指定特定的 pop(delete) 的element

对于index 的访问,一定要保证有相应的size() 长度,然后再进行index 的访问

1
2
    del mylist[1:2] # 通过指定 index range 然后进行del
    mylist.sort() # 支持 sorting 然后是从小到大, 这个sort是一种操作,inplace 的操作

tuples: tuples store a sequence of objects, the object can be of any type. Tuples are faster than lists.

dictionary: It stores key/value pair objects.

1
2
3
4
5
6
7
8
9
    my_dict =dict()
    my_dict['key'] ='value'
    or 
    my_dict ={'key': 'value', ...}
    
    for key in my_dict:
    # do something
    if 'some key' in my_dict:
    # do something

Iterators

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class yrange:
    def __init__(self, n):
        self.i = 0
        self.n = n

    # 这个表明是一个 iterator,make an object iterable
    def __iter__(self):
        return self

    # 这个next 函数就被当做是 class的属性,可以被外部调用的,
    def next(self):
        if self.i < self.n:
            i = self.i
            self.i += 1
            return i
        else:
            raise StopIteration()

shallow vs deep copy

python3 中: 对于简单的数据类型,像int ,string,这种 copy() 和copy.deepcopy() 这两者都是相同的,copy 都是一种映射,都是相当于”值“ 上的引用;

1
2
3
4
5
    aa =2
    bb =aa
    print(id(aa), id(bb)) # 相同
    bb =3
    print(id(aa), id(bb)) # 不同,因为把3 这个值重新复制给了变量bb

对于复杂的数据类型,使用deepcopy() 的时候,本来就是会重新拷贝一份到内存中。在python3 中copy() 和deepcopy() 这个是没有什么区别的。

1
2
3
4
5
    list1 =['a', 'b']
    list2 =list1 # 这个是引用,所以和list1 是相同的
    list3 =copy.copy(list1)  # 这个id 和list1 不同
    list4 =copy.deepcopy(list1)# 这个id 和list1 不同 
    print(id(list1), id(list2), id(list3), id(list4))

在python 中如何返回值有多个,可以使用元组。虽然是可以使用全局变量,但是在真正的工作中是不推荐这样做的,因为在多线程环境下,这种方式并不是一种 线程安全的方法。

关于 传值还是传引用?

结论:python不允许程序员选择采用传值还是传引用。Python参数传递采用的肯定是“传对象引用”的方式。这种方式相当于传值和传引用的一种综合。如果函数收到的是一个可变对象(比如字典或者列表)的引用,就能修改对象的原始值--相当于通过“传引用”来传递对象。如果函数收到的是一个不可变对象(比如数字、字符或者元组)的引用,就不能直接修改原始对象--相当于通过“传值’来传递对象。

细说: 对于不可变的对象,原始的对象因为不能改变,于是被“抛弃”,实际上是新new 了一个数值,所以操作的不是原来主函数中的值。

python 中的基本数据类型有六种:数字,字符串,列表,字典,元组和集合,(Number, String, List, Dict, Tuple, Set)

数字包括整形,长整型,浮点型和复数,(Int, Long, Float, Complex) 布尔值 True 和 False 集合包含集合和不可变集合 (set, frozenset) 字符串里包括 字符串,字节串和万国码 (str, bytes, unicode) 列表包括 列表和字节数组 (list, bytearray) 有的时候分四种,就是数字,序列,集合和字典。序列里包括字符串和列表和元组。 有的时候分五种,就是数字,字符串,列表,元组和字典。列表里包括元组。 其中不可变的类型有数字,字符串,布尔值,元组,和 frozenset, 可变类型有列表,字典,和集合。

可变和不可变的区分是该对象是否存在 add 或者 append 等方法来增加对象元素,使得对象在不改变自身 ID 的情况改变内容。

object oriented design

1
2
3
4
5
6
    class ParentClass:
     def my_function(self):
       print 'I am here'
    
    class SubClass1(ParentClass): 
    class SubClass2(ParentClass): 

对于多继承的支持 (接口)

1
    class A(B,C):  #A implments B and C

如果想要call parent class function then you can dp:

1
    super(A, self).funcion_name()

garbage collection

all the objects in python are stored in a heap (堆) space. Python has an built-in garbage collection mechanism. Memory management in Python involves a private heap containing all Python objects and data structures. The management of this private heap is ensured internally by the Python memory manager.

In computer science, a heap is a specialized tree-based data structure which is essentially an almost complete[1] tree that satisfies the heap property: if P is a parent node of C, then the key(the value) of P is either greater than or equal to (in a max heap) or less than or equal to (in a min heap) the key of C.

try…catch

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
    # raise exceptions
    try:
      raise TyeError
    except:
      print('exception')
    
    # catching exceptions
    try:
      do_something()
    except:
      print('exception')
    # try/ catch /finally
    try:
      do_something()
    except TypeError:
      print('exception')
    finally:
      close_connections()

内置函数中的 all() 和 any()

这两个函数的参数都是iterable,也就是为list或者tuple. all() 函数: “全‘真’为True,有‘假’为False” ; 当iterable为空的时候,函数返回值为True any() “全‘假’为False,有‘真’为True”. 当iterable为空的时候,函数返回值为False

给出all () 函数的一个简单的例子

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
>>> all(['a', 'b', 'c', 'd'])  # 列表list,元素都不为空或0
True
>>> all(['a', 'b', '', 'd'])   # 列表list,存在一个为空的元素
False
>>> all([0, 12, 3])          # 列表list,存在一个为0的元素
False
   
>>> all(('a', 'b', 'c', 'd'))  # 元组tuple,元素都不为空或0
True
>>> all(('a', 'b', '', 'd'))   # 元组tuple,存在一个为空的元素
False
>>> all((0, 1, 2, 3))          # 元组tuple,存在一个为0的元素
False
   
>>> all([])             # 空列表
True
>>> all(())             # 空元组
True

总结: all():“有‘假’为False,全‘真’为True,iterable为空是True” any():“有‘真’为True,全‘假’为False,iterable为空是False”

sort() sorted() 函数

在python3 中 sorted() 取消了对cmp 的支持, 所以只能使用 sort() 函数, 比如下面语句,表示先是按照第一个元素进行升序,然后在第一个元素相同的条件下,按照第二个元素进行降序。灰常nice的一种写法。

1
2
# type envelopes: List[List[int]]
envelopes.sort(key =lambda x:(x[0], -x[1]))

list.sort( ) 是in-place 操作, 在python2 中 sorted() 是一种有返回排序好的数组的操作。

python operators

Python Arithmetic Operator

Addition(+) Subtraction(-) Multiplication(*) Division(/) Exponentiation(**) Floor Division(//) 向下取整 Modulus(%)

Python Relational Operator

Less than(<) Greater than(>) Less than or equal to(<=) Greater than or equal to(>=) Equal to(= =) Not equal to(!=)

Python Assignment Operator (python 中没有 ++ 这个符号,这个是c++ 中的符号)

Assign(=) Add and Assign(+=) Subtract and Assign(-=) Divide and Assign(/=) Divide and Assign(/=) Modulus and Assign(%=) Exponent and Assign(**=) Floor-Divide and Assign(//=)

Python Logical Operator (会有某种机制简化运算,比如 condition1 or condition2 ,如果condition1 是正确的,那么最后的结果就是正确的。)用于逻辑判断

and or not

Python Membership Operator

in ,not in

Python Identity Operator

is, is not ,

Python Bitwise Operator

(这其中的 | 表现的是一种二级制' 和’的 关系,如果在二进制下,0 | 1 那么就是1 ) 属于集合操作。

Binary AND(&) Binary OR(|) Binary XOR(^) Binary XOR(^) Binary Left-Shift(«) Binary Right-Shift(»)

Working with files

** Working with CSV, Json and XML**

Over the years, the list of possible formats that you can store your data in has grown significantly. But, there are 3 that dominate in their everyday usage: CSV, JSON, and XML. In this article, I’m going to share with you the easiest ways to work with these 3 popular data formats in Python!

有两种方式去读写 csv file:一种是 pd.read_csv() ,一种是built-in 的library 中的库函数 之前一直使用的pd.read_csv(), 现在才发现python 有built-in 的library。 We can do both read and write of a CSV using the built-in Python csv library. Usually, we’ll read the data into a list of lists.

python built-in function.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import csv 
filename = "my_data.csv"
fields = [] 
rows = [] 

with open(filename, 'r') as csvfile: 
    csvreader = csv.reader(csvfile) 
    # 如果单单是这个for,那么内存是消耗比较大的
    # fields = csvreader.next() 
    for row in csvreader: 
        rows.append(row)
for row in rows[:5]: 
    print(row)

# Writing to csv file 
with open(filename, 'w+') as csvfile: 
    csvwriter = csv.writer(csvfile) 
    csvwriter.writerow(fields) 
    csvwriter.writerows(rows)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import pandas as pd
from dicttoxml import dicttoxml
import json
# Building our dataframe
data = {'Name': ['Emily', 'Katie', 'John', 'Mike'],
        'Goals': [12, 8, 16, 3],
        'Assists': [18, 24, 9, 14],
        'Shots': [112, 96, 101, 82]
        }

df = pd.DataFrame(data, columns=data.keys())
# Converting the dataframe to a dictionary
# Then save it to file
data_dict = df.to_dict(orient="records")
with open('output.json', "w+") as f:
    json.dump(data_dict, f, indent=4)

# Converting the dataframe to XML
# Then save it to file
xml_data = dicttoxml(data_dict).decode()
with open("output.xml", "w+") as f:
    f.write(xml_data)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import json
import pandas as pd

# Read the data from file
# We now have a Python dictionary
with open('data.json') as f:
    data_listofdict = json.load(f)
    
# We can do the same thing with pandas
data_df = pd.read_json('data.json', orient='records')

# We can write a dictionary to JSON like so
# Use 'indent' and 'sort_keys' to make the JSON
# file look nice
with open('new_data.json', 'w+') as json_file:
    json.dump(data_listofdict, json_file, indent=4, sort_keys=True)

# And again the same thing with pandas
export = data_df.to_json('new_data.json', orient='records')

处理windows 和linux 中文件分割符不兼容的情况

python 中 open( mode =‘rt’) 的选项: w,r,wt,rt都是python里面文件操作的模式。 w是写模式,r是读模式。 t是windows平台特有的所谓text mode(文本模式),区别在于会自动识别windows平台的换行符。 类Unix平台的换行符是\n,而windows平台用的是\r\n两个ASCII字符来表示换行,python内部采用的是\n来表示换行符。 rt模式下,python在读取文本时会自动把\r\n转换成\n. wt模式下,Python写文件时会用\r\n来表示换行。

参考资料: https://towardsdatascience.com/the-easy-way-to-work-with-csv-json-and-xml-in-python-5056f9325ca9

输入和输出函数

输入函数

python2 有 raw_input() 和 input() 函数,前者把所有的接收值当做string,如果想要用int,那么需要自己进行转换。input() 如果得到int,那么就是int,string 类型就是string 类型。 python3 中只有input() 函数,所有的接收都是 string,需要自己进行转换。

python3 中的input() 函数就是python2 中的raw_input() 函数。下面的代码使用 python3 实现。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
if __name__ =="__main__":

    # 输入输出 n*n 的arrar
    """

    n =int(input())

    arr =[[0]*n] *n

    # 在python3 中需要 exactly 的注意这种分割,输入的时候要及其的小心
    for i in range(n):
        arr[i] = input().split(" ")
        arr[i] =[int(a) for a in arr[i]] # 转成 int 类型

    print(arr)
    
    """
    # 输入和输出 n*m 的数组
    n =int(input())
    m =int(input())

    arr =[[0]*m]*n

    for i in range(n):
        arr[i] =input().split(" ")
        arr[i] =[int(a) for a in arr[i]]

    print(arr)

处理输入和输出问题,就是使用 python3 处理,然后注释使用 list(map(str, []))list(map(int, [])) 这种处理手段。涨涨记性吧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#python 中传递的是值 还是引用
def quick_sort(nums, l, r):
    if l>= r: return 
    left, right =l, r
    
    key =nums[l]
    while(l<r):
        while(l <r and nums[r] >= key): r -=1
        nums[l] =nums[r]
        while(l <r and nums[l] <= key): l +=1
        nums[r] =nums[l]
    nums[l] =key
    
    quick_sort(nums, left, l -1)
    quick_sort(nums, l +1, right)

if __name__ =="__main__":
    n =int(input())
    nums =list(map(int, input().split()))
    quick_sort(nums, 0, len(nums)-1)
    #print(nums)
    print(" ".join(list(map(str, nums))))

String Formatting Syntax

As of Python 3.6, f-strings are a great new way to format strings. Not only are they more readable, more concise, and less prone to error than other ways of formatting, but they are also faster!

Option #1: %-formatting

This is the OG of Python formatting and has been in the language since the very beginning. You can read more in the Python docs. Keep in mind that %-formatting is not recommended by the docs.

How to Use %-formatting

1
2
3
name = "Eric"
age = 74
print("Hello, %s. You are %s." % (name, age))

Why %-formatting Isn’t Great

However, once you start using several parameters and longer strings, your code will quickly become much less easily readable. Things are starting to look a little messy already:

1
2
3
4
5
6
7
first_name = "Eric"
last_name = "Idle"
age = 74
profession = "comedian"
affiliation = "Monty Python"
"Hello, %s %s. You are %s. You are a %s. You were a member of %s." % (first_name, last_name, age, profession, affiliation)

Option #2: str.format()

This newer way of getting the job done was introduced in Python 2.6.

1
2
3
4
5
6
"Hello, {}. You are {}.".format(name, age) # 默认的顺序
"Hello, {1}. You are {0}.".format(age, name) # 按照index 的顺序

# 传入的 dict 的顺序
 person = {'name': 'Eric', 'age': 74}
 "Hello, {name}. You are {age}.".format(name=person['name'], age=person['age'])

Why str.format() Isn’t Great

1
print(("Hello, {first_name} {last_name}. You are {age}. " +"You are a {profession}. You were a member of {affiliation}.") .format(first_name=first_name, last_name=last_name, age=age,profession=profession, affiliation=affiliation))

f-Strings: A New and Improved Way to Format Strings in Python

The syntax is similar to the one you used with str.format() but less verbose.

1
2
3
4
name = "Eric"
age = 74
f"Hello, {name}. You are {age}."
F"Hello, {name}. You are {age}." #  也可以使用大写的字母F

Arbitrary Expressions

Because f-strings are evaluated at runtime, you can put any and all valid Python expressions in them. This allows you to do some nifty things.

1
2
3
4
5
6
f"{2 * 37}"

def to_lowercase(input):
	return input.lower()
name = "Eric Idle"
f"{to_lowercase(name)} is funny."
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Comedian:
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age

    def __str__(self):
        return f"{self.first_name} {self.last_name} is {self.age}."

    def __repr__(self):
        return f"{self.first_name} {self.last_name} is {self.age}. Surprise!

The __str__() and __repr__() methods deal with how objects are presented as strings, so you’ll need to make sure you include at least one of those methods in your class definition. If you have to pick one, go with __repr__() because it can be used in place of __str__().

By default, f-strings will use __str__(), but you can make sure they use __repr__() if you include the conversion flag !r:

1
2
f"{new_comedian}"
f"{new_comedian!r}"

{% fold 开/合 %} Python: str( ) vs. repr( )

According to the official documentation, __repr__() is used to compute an official string representation of an object which, and, if possible, can be used to recreate the object itself, however, __str__() is used to compute an informal string representation of that object.

Although the repr() official representation is for developers so they can use it to debug, the str() informal representation is for the final users.

代码说明:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from datetime import datetime
if __name__ == "__main__":
    nb = 1
    print (str(nb))
    #1
    print (repr(nb))
    #1
    print '*' * 20
#********************
    chaine = "hello world"
    print (str(chaine))
    #hello world
    print (repr(chaine))
    #'hello world'
    print '*' * 20
#********************
    d_cur = datetime.now()
    print (str(d_cur))
    #2019-03-14 12:01:44.377000
    print (repr(d_cur))
    #datetime.datetime(2019, 3, 14, 12, 1, 44, 377000)
    print '*' * 20
    #********************

参考文献:Python: str( ) vs. repr( )

{% endfold %}

Speed

As you already saw, f-strings are expressions evaluated at runtime rather than constant values. Here’s an excerpt from the docs:

“F-strings provide a way to embed expressions inside string literals, using a minimal syntax. It should be noted that an f-string is really an expression evaluated at run time, not a constant value. In Python source code, an f-string is a literal string, prefixed with f, which contains expressions inside braces. The expressions are replaced with their values.” (Source)

1
2
3
4
5
6
7
import timeit
timeit.timeit("""name = "Eric" age = 74 '%s is %s.' % (name, age)""", number = 10000)
# 0.003324444866599663
timeit.timeit("""name = "Eric"age = 74'{} is {}.'.format(name, age)""", number = 10000)
# 0.004242089427570761
timeit.timeit("""name = "Eric"age = 74f'{name} is {age}.'""", number = 10000)
# 0.0024820892040722242

Quotation Marks

1
2
3
4
5
f'''Eric Idle'''
f"""Eric Idle""" # 注意是三对
# 'Eric Idle'
f"The \"comedian\" is {name}, aged {age}."
# 'The "comedian" is Eric Idle, aged 74.'

Dictionaries

1
2
comedian = {'name': 'Eric Idle', 'age': 74}
f"The comedian is {comedian['name']}, aged {comedian['age']}."

Braces

In order to make a brace appear in your string, you must use double braces:

Note that using triple braces will result in there being only single braces in your string:

However, you can get more braces to show if you use more than triple braces:

Python 3’s f-Strings: An Improved String Formatting Syntax (Guide)

面向对象 (for python)

访问控制有三种级别:私有、受保护、公有。私有。(Private):只有类自身可以访问 受保护。(Protected):只有类自身和子类可以访问 公有。(Public):任何类都可以访问。

公有(Public)

在Python的类中,默认情况下定义的属性都是公有的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Foo(object):
	bar = 123

	def __init__(self, bob):
		self.bob = bob

print(Foo.bar)  # 123

foo = Foo(456)
print(foo.bob)  # 456

上面类Foo中的bar属性就是类属性,__init__方法中定义的bob是实例属性,bar和bob都是公有的属性,外部可以访问,分别print类中的bar和实例中的bob,输出了对应的值。

受保护(Protected)

在Python中定义一个受保护的属性,只需要在其名字前加一个下划线_,我们将Foo方法中的bob和bar改为_bob和_bar,他们就变成了受保护的属性了,代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Foo(object):
	_bar = 123

	def __init__(self, bob):
		self._bob = bob


class Son(Foo):
	
	def print_bob(self):
		print(self._bob)

	@classmethod
	def print_bar(cls):
		print(cls._bar)


Son.print_bar()  # 123

son = Son(456)
son.print_bob()  # 456

定义一个类Son继承自Foo,由于受保护的对象只能在类的内部和子类中被访问,不能直接调用print(Son._bar)或print(son._bob)来输出这两个属性的值,所以定义了print_bar和print_bob方法,实现在子类中输出,这段代码也正常的输出了_bar和_bob的值。

1
2
3
4
print(Son._bar)  # 123

son = Son(456)
print(son._bob)  # 456

(假装)惊讶的发现,竟然没有报错,也输出了正确的值。

Python中用加下划线来定义受保护变量,是一种约定的规范,而不是语言层面真的实现了访问控制,所以,我们定义的保护变量,依然可以在外部被访问到(这是个feature,不是bug)。

私有(private)

Python定义私有属性,需要在属性名前加两个下划线__,把上面的代码修改一下,运行一下会发现下面的代码中的任何一个print都会报错的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Foo(object):
	__bar = 123

	def __init__(self, bob):
		self.__bob = bob


class Son(Foo):
	
	def print_bob(self):
		print(self.__bob)  # Error

	@classmethod
	def print_bar(cls):
		print(cls.__bar)  # Error


print(Son.__bar)  # Error

son = Son(456)
print(son._bob)  # Error

深入一下——私有属性真的就访问不到了吗?

要了解私有属性是否真的访问不到,需要从Python是如何实现私有属性入手。CPython中,会把双下划线的属性变为_ClassName__PropertyName的形式,用代码演示一下:

1
2
3
4
class Foo(object):
	__bar = 123

print(Foo._Foo__bar)  # 123

再比如

1
2
3
4
5
class F:
    __name = "xurui"
f = F()
result = f._F__name          ##通过这个方式可以从外部访问...
print(result) 

运行一下可以知道,正常输出了__bar的值,但是不推荐这样去访问私有属性,因为不同的Python解释器对于私有属性的处理不一样。

特例

使用双下划线定义私有属性,有一种特殊情况,当属性后也有两个下划线的时候,这个属性会被Python解释器当做魔术方法,从而不做私有处理。

1
2
3
4
5
class Foo(object):
	__bar__ = 123


print(Foo.__bar__)  # 123

上面代码输出了123,证明Python解释器并没有把__bar__当做私有属性。当定义私有属性时,需要注意名字最后最多只能有一个下划线。

假如定义的属性名就叫__呢?不妨直接试一下:

1
2
3
class Foo(object):
	__ = 123
print(Foo.__)  # 123

可以发现名字叫__的属性也不会被认为是私有属性,名字是多个下划线的属性也不是私有属性(比如_______)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class ProtectMe(object):
    def __init__(self):
       self.me = "wxx"
       self.__name = "zixin"
    @property
    def name(self):
      return self.__name

p = ProtectMe()
print p.name

与面试官谈笑风生 | Python面向对象之访问控制

**类class的访问控制 **(这个实际上体现的是封装的思想)

Python中没有访问控制的关键字,例如private、protected等等。但是,在Python编码中,有一些约定来进行访问控制。Python中没有真正的私有属性或方法,可以在你想声明为私有的方法和属性前加上单下划线,以提示该属性和方法不应在外部调用.如果真的调用了也不会出错,但不符合规范.

  1. xx: 共有变量

  2. 单下划线 “_”

前置单下划线,私有化属性或方法,一般来讲,变量名_xx被看作是“私有 的”,在模块或类外不可以使用。当变量是私有的时候,用_xx 来表示变量是很好的习惯。类对象和子类可以访问,这并不能完全做到真正的私有,只是约定俗成的而已,这样写表示不希望这个变量在外部被直接调用。

  1. 双下划线"__"

前置双下划线,私有化属性或方法,无法在外部直接访问(名字重整所以访问不到,只能是允许这个类本身进行访问了。连子类也不可以)

  1. xx_:后置单下划线,用于避免与Python关键词的冲突(这种约定俗称的东西很好,一定要按照这种规范去做)

单下划线、双下划线、头尾双下划线说明:

1
2
3
4
5
6
__foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的。

_foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于 from module import *

__foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。

这种命名方式同样是适用方法的命名。

python 中也是一样的,重载是类本身就有的方法,重写是子类针对父类函数的重写。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Site:
    def __init__(self, name, url):
        self.name = name       # public
        self.__url = url   # private
        # 这个是系统的方法
 
    def who(self):
        print('name  : ', self.name)
        print('url : ', self.__url)
 
    def __foo(self):          # 私有方法
        print('这是私有方法')
 
    def foo(self):            # 公共方法
        print('这是公共方法')
        self.__foo()

继承

Python3的继承机制不同于Python2。其核心原则是下面两条,请谨记!

  • 子类在调用某个方法或变量的时候,首先在自己内部查找,如果没有找到,则开始根据继承机制在父类里查找。
  • 根据父类定义中的顺序,以深度优先的方式逐一查找父类!

继承参数的书写有先后顺序,写在前面的被优先继承。

super() 函数

我们都知道,在子类中如果有与父类同名的成员,那就会覆盖掉父类里的成员。那如果你想强制调用父类的成员呢?使用super()函数!这是一个非常重要的函数,最常见的就是通过super调用父类的实例化方法__init__!

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
class A:
    def __init__(self, name):
        self.name = name
        print("父类的__init__方法被执行了!")
    def show(self):
        print("父类的show方法被执行了!")

class B(A):
    def __init__(self, name, age):
        super(B, self).__init__(name=name)
        self.age = age

    def show(self):
        super(B, self).show()

obj = B("jack", 18)
obj.show()

继承可以把父类的所有功能都直接拿过来,这样就不必重零做起,子类只需要新增自己特有的方法,也可以把父类不适合的方法覆盖重写。

Python super().__init__和Base.__init__的区别

通过上面的分析,我们知道在类继承中,一定要使用super的方式才能正确调用类继承关系,在python3中推荐使用super().init,pytho2中使用super(Base, self).init

多态

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Animal:
    def kind(self):
        print("i am animal")
        
class Dog(Animal):
    def kind(self):
        print("i am a dog")
        
class Cat(Animal):
    def kind(self):
        print("i am a cat")

class Pig(Animal):
    def kind(self):
        print("i am a pig")

# 这个函数接收一个animal参数,并调用它的kind方法
def show_kind(animal):
    animal.kind()

d = Dog()
c = Cat()
p = Pig()

show_kind(d)
show_kind(c)
show_kind(p)

------------------
打印结果:

i am a dog
i am a cat
i am a pig

多态的思想,使用一个指针(变量)可以根据位置指向不同的子类。

python 中的三类方法

一般使用实例方法最多,需要有 self 作为一个传入参数,在子类中可以使用该方法。 类方法使用修饰器 @classmethod ;静态方法使用修饰器 @staticmethod,对于静态方法,调用时并不需要传递类或者实例。其实,静态方法很像我们在类外定义的函数,只不过静态方法可以通过类或者实例来调用而已。

实例方法只能被实例对象调用,静态方法(由@staticmethod装饰的方法)、类方法(由@classmethod装饰的方法),可以被类或类的实例对象调用。

实例方法,第一个参数必须要默认传实例对象,一般习惯用self。 静态方法,参数没有要求。 类方法,第一个参数必须要默认传类,一般习惯用cls。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Kls(object):
    def foo(self, x):
        print('executing foo(%s,%s)' % (self, x))

    @classmethod
    def class_foo(cls,x):
        print('executing class_foo(%s,%s)' % (cls,x))

    @staticmethod
    def static_foo(x):
        print('executing static_foo(%s)' % x)

ik = Kls()
# 实例方法
ik.foo(1)
print(ik.foo)
print('==========================================')
# 类方法
ik.class_foo(1)
Kls.class_foo(1)
print(ik.class_foo)
print('==========================================')
# 静态方法
ik.static_foo(1)
Kls.static_foo('hi')
print(ik.static_foo)

类方法 Python 提供了 classmethod 装饰器让我们实现上述功能,看下面的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class A(object):
    bar = 1
    @classmethod
    def class_foo(cls):
        print 'Hello, ', cls
        print cls.bar

>>> A.class_foo()   # 直接通过类来调用方法
Hello,  <class '__main__.A'>
1

在上面,我们使用了 classmethod 装饰方法 class_foo,它就变成了一个类方法,class_foo 的参数是 cls,代表类本身,当我们使用 A.class_foo() 时,cls 就会接收 A 作为参数。另外,被 classmethod 装饰的方法由于持有 cls 参数,因此我们可以在方法里面调用类的属性、方法,比如 cls.bar。

静态方法

在类中往往有一些方法跟类有关系,但是又不会改变类和实例状态的方法,这种方法是静态方法,我们使用 staticmethod 来装饰,比如下面的例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class A(object):
    bar = 1
    @staticmethod
    def static_foo():
        print 'Hello, ', A.bar

>>> a = A()
>>> a.static_foo()
Hello, 1
>>> A.static_foo()
Hello, 1

可以看到,静态方法没有 self 和 cls 参数,可以把它看成是一个普通的函数,我们当然可以把它写到类外面,但这是不推荐的,因为这不利于代码的组织和命名空间的整洁。

python 中的单例/ 多例模式

  1. 定义

单例模式(Singleton Pattern):单例模式确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式的要点有三个:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。单例模式是一种对象创建型模式。单例模式又名单件模式或单态模式。

  1. 单例模式的分类

懒汉版(Lazy Singleton):单例实例在第一次被使用时才进行初始化,这叫做延迟初始化。

Lazy Singleton存在内存泄露的问题,有两种解决方法:

  • 使用智能指针
  • 使用静态的嵌套类对象

饿汉版(Eager Singleton):指单例实例在程序运行时被立即执行初始化。由于在main函数之前初始化,所以没有线程安全的问题。

两种分类的总结: Eager Singleton 虽然是线程安全的,但存在潜在问题; Lazy Singleton通常需要加锁来保证线程安全,但局部静态变量版本在C++11后是线程安全的; 局部静态变量版本(Meyers Singleton)最优雅。

  1. 什么情况下使用单例模式
  • 系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器,或者需要考虑资源消耗太大而只允许创建一个对象。
  • 客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。

小的例子: 某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

  1. python 中的实现

有以下四种方式实现:

1
2
3
4
使用模块
使用 __new__
使用装饰器(decorator)
使用元类(metaclass)

使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

1
2
3
4
5
# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass
my_singleton = My_Singleton()

使用new 关键字, 如果已经有有了该实例,那么就不用生成了

1
2
3
4
5
6
7
8
class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
        return cls._instance  
class MyClass(Singleton):  
    a = 1

使用修饰器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from functools import wraps
def singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance
@singleton
class MyClass(object):
    a = 1

python中的单例模式

数据处理函数

读取 矩阵文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#第一种方法 python 读取矩阵文件

# 单精度是32 位,双精度是64位
def read_file(file1):

    f =open(file1)
    matrix=[]

    while True:

        line =f.readline()
        if not line: break

        line=line.strip()
        line =line.split(",")
        line =map(float, line) # 这里转化成float 就是ok的
        matrix.append(line)
    f.close()

    # matrix =numpy.array(matrix)
    return matrix


# 第二种方法 基于numpy 的实现

path ="text.txt"
matrix =numpy.loadtxt(path)

b =numpy.reshape(matrix,(100, 2) )
b =numpy.reshape(matrix, (-1, 3, 2))

shuffle 函数

只要是打散,都是会用到 shuffle() 这样的一个函数。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 纯python 实现
index= [i for i in range(len(train_x))]
random.shuffle(index)
train_x =train_x[index]
train_y  =train_y[index]

# 基于 numpy 实现

def shuffle_data(data):
    np.random.shuffle(data)
    
    return data

按照文件名进行排序

这个是按照字典序排序的。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import numpy as np
import os
 
img_path='./img/'
 
img_list=sorted(os.listdir(img_path))	#文件名按字母排序
img_nums=len(img_list)
for i in range(img_nums):
    img_name=img_path+img_list[i]
    print(img_name)

n2rAbj.png

注意下面的是按照数字进行排序的,也就是文件名。这种方法更加使用,注意在实现的时候,将 string 转换成了int 类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import numpy as np
import os
img_path='./img/'
 
img_list=os.listdir(img_path)
img_list.sort()
img_list.sort(key = lambda x: int(x[:-4])) ##文件名按数字排序
img_nums=len(img_list)
for i in range(img_nums):
    img_name=img_path+img_list[i]
    print(img_name)

n2ruGV.png

库函数

(1)heapq 在python 中默认的是一个小根堆(在c++ 中默认的是一个大根堆)

1
2
3
4
5
6
7
heapq.heappush(heap, item) 把item添加到heap中(heap是一个列表)
heapq.heappop(heap) 把堆顶元素弹出,返回的就是堆顶
heapq.heappushpop(heap, item) 先把item加入到堆中,然后再pop,比heappush()再heappop()要快得多
# 这比较好用,不用自己维护 pushpop 操作
heapq.nlargest(n, iterable, key=None) 返回最大的n个元素(Top-K问题)
heapq.nsmallest(n, iterable, key=None) 返回最小的n个元素(Top-K问题)
# 如果写成了这样,那么寻找最大K 个元素,瞬间就没有了意义,有没有感觉到

(2)dictionary

1
2
3
4
5
import collections

# 就类似一个计数器了
hash =collections.defaultdict(int);

还有一种方式,直接使用 {} 进行表示

(4)stack

python 中没有专门的处理栈库函数,但是栈的操作可以使用list 全部实现。所以当你在使用stack 的时候,基本上就是在使用list

1
2
3
4
5
# python 中的入栈
stack =[1, 2, 3]
stack.append(4)

item =stack.pop() # 注意这个是直接返回,stack 中不再存在

(5)heap

python 中默认实现的是小根堆。使用库函数 heapq 库函数,其中 heappush()heappop()

1
2
3
4
# python 中 heap 的基本操作
heap =[] 
heapq.heappush(heap, val)
val = heapq.heappop(heap)

python 中使用原有库函数实现大根堆。

使用 heapq 类实现堆,该类默认是小根堆,然后将每个值乘以 -1 从而实现了大根堆、

(6)deque

注意python中的deque是队列的实现。python 中默认实现的是双向队列,两端都是可以编辑的。

队列是一种基于先进先出(FIFO)策略的数据结构.

1
2
3
4
5
6
7
# 下面是常用操作
appendleft(x) # 添加x 到左侧
pop() # 移除并返回一个元素,右侧

# 以下体现的是双向编辑
append(x) # 添加 x 到右侧
popleft() # 移除并返回一个元素,左侧
1
2
3
4
5
6
7
8
9
from collections import deque
name=deque(["jean","li","na"])
name.append("yang")
name.append("chun")
print(name.popleft())    #不可以带参数
print(name)
 outputs:
jean
deque(['li', 'nana', 'yang', 'chun'])

还有一种比较笨的实现方法

1
2
3
4
5
q =[]
# 这个是入队操作
q.append('a')
# 出队
del q[0]

但是时间效率是不一样的, deque.popleft() 是$O(1)$时间复杂度, del q[0] 是$O(n)$ 的时间复杂度。

python 中的数据结构Dict 和Set 类型

(1) Python 中的Dict

  1. 获取 Dict长度
1
2
3
4
5
6
d = {
    'Adam': 95,
    'Lisa': 85,
    'Bart': 59
}
# 使用len(d) 可以获取长度
  1. 访问Dict中的值

下面是两种访问方式

if 判断一下

1
2
if 'Paul' in d:
	print(d['Paul'])

使用 dict 自带的 get 方法

1
d.get("Paul")
  1. 更新Dict
1
d['Paul'] =20
  1. 遍历整个 Dict
1
2
for key in d:
	print key
  1. Python中 Dict 的特点

Dict 查找速度快,但是占用内存大。list占用内存小,但是查找速度慢。

Dict 中的key 是不能重复的,这个性质和 set 很想。

(2)Python 中的set

由于 set 存储的无序集合,所以不能使用索引进行访问

set 中存储的元素和 Dict 中的key类似,必须是不变对象。

判断是否存在 set 中

1
'Bill' in s

set 的更新主要做两件事情:把新的元素放到 set 中; 把已有元素从set 中删除。

1
2
3
s =set([1, 2, 3])
s.add(4)
s.remove(4) # 如果这个时候不存在,那么会保存

其他

python 中 in 操作 在不同的数据集合中的时间复杂度 这个是取决于操作的数据结构:

  • list (tuple) -average: O(N)
  • set/dict- average: O(1), worst: O(N)

(如果 dictionary 所有的值都相同的话,那么时间复杂度就是 O(n))

The O(n) worst case for sets and dicts is very uncommon, but it can happen if hash is implemented poorly. This only happens if everything in your set has the same hash value.

操作 平均情况 最坏情况 说明
列表 list O(n) O(n) list 是由数组实现的
字典 dict O(1) O(n)
集合 set O(1) O(n) 内部实现和 dict 很像

python 中表示最大和最小的数字

1
2
3
import sys
sys.maxsize #如果是整型
float(‘inf’) # 如果是浮点型

python 中 string的切片的时间复杂度,因为python 中string是不可变的,所以切片操作基本上是通过复制完成的,所以时间复杂度一般是 $O(n)$,复制的时候需要申请一个临时的空间,所以空间复杂度基本上也稳定在 $O(n)$。常见的切片操作有三种:

  • str[:] 完全复制,返回的是exact same 的 copy,前后两个变量没有什么关系了
  • str[1:1], mystr[1:1] is mystr[2:2] is '' 是一个空的对象
  • str[a: b] 其中 $a< b$,最常见的切片复制, make a copy
  • [::-1] reverse的操作

dictionary总结

Python Pro Tip: Start using Python defaultdict and Counter in place of dictionary

However, learning to write a language and writing a language in an optimized way are two different things.

Every Language has some ingredients which make it unique.

知道算法思想,还要非常熟悉一门语言,使其高效地实现。最好的是写出 efficient and readable code.

一个 user case example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 方案一:naive python implementation
text = "I need to count the number of word occurrences in a piece of text. How could I do that? Python provides us with multiple ways to do the same thing. But only one way I find beautiful."
word_count_dict = {}
for w in text.split(" "):
    if w in word_count_dict:
        word_count_dict[w]+=1
    else:
        word_count_dict[w]=1
# 方案二: use defaultdict 
from collections import defaultdict
word_count_dict = defaultdict(int) # 意味着value 是int 类型
for w in text.split(" "):
    word_count_dict[w]+=1

# 方案三:use counter
from collections import Counter
word_count_dict = Counter()
for w in text.split(" "):
    word_count_dict[w]+=1

方案三是最好的,如果你是统计功能,那么伴随着经常需要使用以下的函数

1
word_count_dict.most_common(10) # 统计最常见的10 个单词

Other use of Counter

1
2
3
4
# Count Characters
Counter('abccccccddddd')
# Count List elements
Counter([1,2,3,4,5,1,2])

Notice that in Counter, the value is always an integer.

当 value值不能是 integer的时候,defaultdict comes to rescue

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from collections import defaultdict
# list of tuple
s = [ ('color', 'blue'), ('color', 'orange'), ('color', 'yellow'), ('fruit', 'banana'), ('fruit', 'orange'), ('fruit', 'banana')]
d =defaultdict(list) # 意味着value 是list 类型
for k, v in s:
    d[k].append(v)
print(d)

d =defaultdict(set) # 意味着 value 是set 类型
for k, v in s:
    d[k].add(v)
print(d)
1
2
3
4
# 从结果中可以看出list 和set 的区别, defaultdict 是很好的函数

defaultdict(<class 'list'>, {'color': ['blue', 'orange', 'yellow'], 'fruit': ['banana', 'orange', 'banana']})
defaultdict(<class 'set'>, {'color': {'blue', 'orange', 'yellow'}, 'fruit': {'banana', 'orange'}})
  1. python内置的dictionary
1
2
3
a_dict =dict() # less pythonic
a_dict ={} # pythonic
a_dict.get("missing_key", "default value")

可以设置default value,当没有相应的key时候。

  1. defaultdict 函数

当访问 defaultdict 实例对象中不存在的元素时,不会像python 内置dict 中抛出keyError异常。defaultdict中有默认值。该对象的其他属性、方法和内置dict 是一样的。

1
2
3
from collections import defaultdict
issubclass(defaultdict, dict)
# 是一个很好的工具类函数,辨别出两个class 的从属关系

比较一下两种写法

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
word_count ={}
for word in doc.split():
    if word in word_count:
        word_count[word] +=1
    else:
        word_count[word] =1

# 如果使用defaultdict
from collections import defaultdict
word_count =defaultdict(int)
for word in doc.split():
    word_count[word] +=1

grouping unique items

下面这种写法是可以实现 groupby 的方法,按照 key 进行 group

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
dep = [('Sales', 'John Doe'),
       ('Sales', 'Martin Smith'),
       ('Accounting', 'Jane Doe'),
       ('Marketing', 'Elizabeth Smith'),
       ('Marketing', 'Elizabeth Smith'),
       ('Marketing', 'Adam Doe'),
       ('Marketing', 'Adam Doe'),
       ('Marketing', 'Adam Doe')]

dep_dd =defaultdict(set)
for department, employee in dep:
    dep_dd[department].add(employee)
dep_dd
# 如果想要继续遍历
for department, employee in dep_dd.items():
  print(department, employee)

# value 的数值是 float
dd =defaultdict(float)

这个功能还是非常常见的,将不同的数据按照key 进行group 起来

  1. orderedDict

    Are dictionaries ordered in Python 3.6+?

    如果要 remember the order keys are added to a dictionary,建议使用 orderedDict;python3.6 是自带这种特效;为了提升兼容性,还是建议使用 orderedDict

  2. ways to remove a key from a dictionary

在字典中增加、修改和访问其中的 term 都不是很大的问题。时间效率主要差在删除操作。

  • Python pop() function
  • Python del keyword
  • In-built Python popitem() method
  • Dictionary Comprehension along with Python items() method

python in-built clear() method to delete a dictionary in python

The clear() method deletes all the key-value pairs present in the dict and returns an empty dict.

这个是全部删除

1
2
dic ={1: "python", 2: "c++"}
dic.clear()

Python pop() method can be used to delete a key and a value associated with it i.e. a key-value pair from a dictionary.

1
2
3
dic.pop(key)
dic.pop(key, None) # 这个应该是很规范的写法

python del 关键词

1
2
3
del dic[key]
# 如果是一个 nested dictionary,那么 使用以下方式
del dic[outer-key][key-name-associated-with-the-value]

返回一个键值对(key,value)形式,按照 LIFO(Last In First Out 后进先出法) 顺序规则,即最末尾的键值对。

删除的是最后一个键值对

1
dic.popitem()

dic.items() 常用的写法

1
{val: key for key, val in dic.items()}

从运行时间角度进行比较(实验过程可以参考:

[Python: How to Remove a Key from a Dictionary](Using the keyword has an edge over the rest of the methods. Although the time difference doesn’t seem to be very dramatic on smaller dictionaries. Though, it will make a huge impact when the size of the dictionary is large.))

Using the del keyword has an edge over the rest of the methods. Although the time difference doesn’t seem to be very dramatic on smaller dictionaries. Though, it will make a huge impact when the size of the dictionary is large.

使用 del 时间效率是最高的。

set 总结

  1. 定义

A set is an unordered collection of items. Every set element is unique (no duplicates) and must be immutable (cannot be changed).

  1. set 的增删改查

Empty curly braces {} will make an empty dictionary in Python. To make a set without any elements, we use the set() function without any argument.

如果想要创建空set,那么使用的是 set();使用 {} 得到的是dictionary

1
2
3
4
a ={}
print(type(a))
b =set()
print(type(b))

可以使用{} 去创建非空的set

1
my_set = {1, 2, [3, 4]}

Sets are mutable. However, since they are unordered, indexing has no meaning.

We can add a single element using the add() method, and multiple elements using the update() method. The update() method can take tuples, lists, strings or other sets as its argument. In all cases, duplicates are avoided.

对于set 的add(), update() 方法

The only difference between the two is that the discard() function leaves a set unchanged if the element is not present in the set. On the other hand, the remove() function will raise an error in such a condition (if element is not present in the set).

删除一个元素使用 remove() 和 discard() 方法

Similarly, we can remove and return an item using the pop() method. Since set is an unordered data type, there is no way of determining which item will be popped. It is completely arbitrary.

We can also remove all the items from a set using the clear() method.

pop() 会return 一个element,但是随机的;clear 是清除所有的元素。

  1. set operation
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Set union method
# initialize A and B
A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

# 1. union operation
print( A |B)
A.union(B)

# 2. intersection
print( A & B)
A.intersection(B)

# 3. set difference
print(A -B)
A.difference(B)

# 4. symmetric_difference() 其实就是异或含义
print(A^B)
# 这两个结果是一样的
A.symmetric_difference(B)
B.symmetric_difference(A)

  1. access items
1
2
3
4
5
set1 ={"apple", "banana", "cherry"}

for x in set1:
    print(x)
print(len(set1)) # 获取长度

其他的函数

1
2
all()  # returns True if all elements of the set are true (or if the set is empty)
any()  # returns True if any element of the set is true. If the set is empty, return False.