Python First Step: 基础知识

Nov 21, 2017


本文

http://afra55.github.io/2017/11/21/python-first-step/

基础知识

前言

The Zen of Python, by Tim Peters

Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren’t special enough to break the rules.

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one– and preferably only one –obvious way to do it.

Although that way may not be obvious at first unless you’re Dutch.

Now is better than never.

Although never is often better than right now.

If the implementation is hard to explain, it’s a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea – let’s do more of those!

PEP 8

https://python.org/dev/peps/pep-0008/

关键字

and as assert break class continue
def del elif else except exec finally for from
global
if import in is lambda
nonlocal not or pass print raise return try while with yield

内置函数

内置和工厂函数 描述 返回结果
cmp(obj1, obj2) 比较两个对象 int
repr(obj) 将 obj 转化为字符串,并可以调用 eval(repr(obj)) 函数再将其转化回 obj str
str(obj) 可打印的字符串表示 str
type(obj) obj 对象的类型 type

链接

格式化操作符转换符号

格式化操作符转换符号 描述
%c 字符
%r 通过 repr() 转化的字符串
%s 通过 str() 转化的字符串
%d %i 有符号十进制整数
%u 无符号十进制整数 
%o (无符号)八进制整数
%x %X (无符号)十六进制整数(小写或大写字母)
%e %E 指数符号(小写e 或大写E)
%f %F 浮点实数(自动截断小数)
%g %G 根据值的大小采用%e或%f,但最多保留6位有效数字
%% 非转义的百分号字符(%)

注释

注释使用 井号来标志 #, # 后面的内容都会被解释器忽略

””” 注释 “”” 三个双引号之间是注释,可跨行,文档字符串

变量

命名只能包含 小写字母 + 数字 + 下划线, 不能以数字开头

计算

** 代表乘方运算 比如 2 ** 3 指 2 的 3次方, 结果是 8

基本类型

字符串

用引号引起来的都是字符串,引号包括 单引号 和 双引号

单引号和双引号可以互相包含,包含的引号就可以以字符串的形式显示出来

如果想要双引号包含双引号或者单引号包含单引号则需要进行转义:", '

name = "victor afra55"
name.title()   # "Victor Afra55"
name.upper()   # "VICTOR AFRA55"
name.lower()   # "victor afra55"

title() 方法,获取当前字符串的大写每个单词的首字母的副本

message = " Victor Afra55 "
message.strip()     # "Victor Afra55"
message.lstrip()    # "Victor Afra55 "
message.rstrip()    # " Victor Afra55"

strip() 方法删除字符串开头和末尾的空白

number = 1
str(number)     # "number"

函数 str(),用于把各种类型转义为字符串

浮点数

带小数点的数字都称为浮点数

python3 中两个整数相除得到的是浮点数,例如:3 / 2 返回的是 浮点数

列表

由一系列按顺序排列的元素组成,这个元素可以是任何东西

names = ['afra55', 'bfra55', 'cfra55', 'dfra55']
names[0]    # afra55
names[1]    # bfra55
names[-1]   # dfra55
names[-2]   # cfra55

在列表末尾添加元素: names.append('efra55')

创建空列表: empty = []

在列表中插入元素:names.insert(0, 'Ffra55')

从列表中删除元素: del names[0]

names = ['afra55', 'bfra55', 'cfra55', 'dfra55']
poped_name = names.pop()     # dfra55
print(names)                 # ['afra55', 'bfra55', 'cfra55']

方法 pop() 获取列表末尾的元素,并把它从列表中删除

names = ['afra55', 'bfra55', 'cfra55', 'dfra55']
names.remove('afra55')  # ['bfra55', 'cfra55', 'dfra55']

remove() 方法根据值来删除列表中的元素

names.sort()
names.sort(reverse=True)

sort() 方法,修改列表元素的排列顺序为顺序,比如数字从小到大或按字母排序

sort(reverse=True) 逆序排列

numbers = [2, 3, 1, 4, 5]
sorted(numbers)    # [1, 2, 3, 4, 5]
sorted(numbers, reverse=True)     # [5, 4, 3, 2, 1]
numbers            # [2, 3, 1, 4, 5]

sorted() 方法,临时排序列表,不会改变原列表顺序

sorted(reverse=True) 临时逆序

numbers = [2, 3, 1, 4, 5]
numbers.reverse()  # [5, 4, 1, 3, 2]

reverse() 方法,颠倒当前列表的排列顺序

numbers = [2, 3, 1, 4, 5]
len(numbers)    # 5

len() 方法,获取列表的长度

for

names = ['afra55', 'bfra55', 'cfra55', 'dfra55']
for name in names:
    print(name)

for 循环用于遍历列表

for value in range(1, 5):
    print(value)    # 1 2 3 4 

range() 方法用于生成一系列数字: range(1, 5) 代表 1~4

numbers = list(range(1, 5))
print(numbers)      # [1, 2, 3, 4]

list() 方法将 range() 的结果转化为列表

numbers = list(range(2, 11, 3))
print(numbers)  # [2, 5, 8]

range(2, 11, 3) 指 从 2 开始获取值,然后每获取一次加一次 3,直到超出 数值 11

numbers = list(range(1, 11))
print(numbers)          # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(min(numbers))     # 1
print(max(numbers))     # 10
print(sum(numbers))     # 55

min() 方法获取数字列表最小的数值

max() 方法获取数字列表最大的数值

sum() 方法获取数字列表的所有数值只和

列表解析

numbers = [value ** 2 for value in range(1, 11)]
print(numbers)  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

[value ** 2 for value in range(1, 11)] 这种语法称之为列表解析,用于高效创建列表,以方括号扩起来,表达式是 value ** 2 获取平方值,后面的 for 循环用于提供 value 值给表达式

切片

对切片的修改不会印象原列表,这里的切片即代表了一个副本,这与 golang 有差别

names = ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']
print(names[1:3])   # ['Bfra55', 'Cfra55']
print(names[:4])    # ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55']
print(names[2:])    # ['Cfra55', 'Dfra55', 'Fra55']
print(names[-3:])   # ['Cfra55', 'Dfra55', 'Fra55']
print(names[:-3])   # ['Afra55', 'Bfra55']

names[1:3] 指 names 列表中的部分,即包含索引为 1~2 的元素副本

names[:4] 指 names 列表中的部分,从列表开头到索引是 3 的元素副本

names[2:] 指 names 列表的部分,从索引为 2 到末尾的元素副本

names[-3:] 指 names 列表的部分,从倒数第3个到末尾的元素副本

names[:-3] 指 names 列表的部分,从列表开头到倒数第4个的元素副本

names[:] 指 整个列表的副本

字符串也可以使用切片

元组

不能修改的值即为不可变的,不可变的列表即为元组,以圆括号 () 来标志 例如:names = (‘Afra55’, ‘Bfra55’)

if

names = ('Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55')
for name in names:
    if name == 'Bfra55':
        print('I find you : ' + name)
    elif name == 'Dfra55':
        print('Hi boy : ' + name)
    else:
        print(name)
# Afra55
# I find you : Bfra55
# Cfra55
# Hi boy : Dfra55
# Fra55


age = 22
print(30 > age > 20)            # True
print(age < 30 and age > 20)    # True
print(age < 30 or age > 20)     # True

与 and

或 or

names = ('Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55')
print('Afra55' in names)    # True
print('B' in names)         # False
print('Bfra55' not in names) # False

in 检查值是否包含在列表中

not in 检查值是否不包含在列表中

布尔表达式

True

False

name = []
if name:    # 判断列表是否是空列表
    print('非空列表')
else:
    print('空列表')

字典

afra = {
    'first': 'victor', 
    'second': 24
    }
print(afra['first'])        # 'victor'
print(afra['second'])       # 24

字典是一系列键值对,任何类型都可以存储为值,字典用 花括号 {} 包裹,键值之间用冒号分割,键值对之间用逗号分隔

afra55 = {
    'name': 'victor', 
    'age': 25
    }
print(afra55)               # {'name': 'victor', 'age': 25}
afra55['weight'] = 144
afra55['height'] = 177
print(afra55)               # {'name': 'victor', 'age': 25, 'weight': 144, 'height': 177}
del afra55['age']
print(afra55)               # {'name': 'victor', 'weight': 144, 'height': 177}

afra55['height'] = 177 这样的写法即新增键值对

del afra55['age'] 指 删除 字典 afra55 中键为 ‘age’ 的键值对

遍历字典

people_one = {
    'first_name': 'victor',
    'last_name': 'afra55',
    'age': 25,
    'city': "xi'an"
    }
for key, value in people_one.items():
    print('Key: ' + key + ', value: ' + str(value))

# Key: first_name, value: victor
# Key: last_name, value: afra55
# Key: age, value: 25
# Key: city, value: xi'an

for 键,值 in 字典.items(): 遍历字典

for key in people_one.keys():
    print(key)

for 键 in 字典.keys(): 遍历字典中的所有键, 相当于 for 键 in 字典:

if 'ff' in people_one.keys():
    print(people_one['ff'])
elif 'age' in people_one.keys():
    print(people_one['age'])        # 25

如果需要排序,可以使用 sorted() 方法获取字典 key 特定排序的 副本: for key in sorted(people_one.keys()):

for value in people_one.values():
    print(value)

for 值 in 字典.values(): 遍历字典中所有的值

可以使用 集合 set 来获取字典中的唯一值,去除重复项:for 值 in set(字典.values()):

字典值和列表值可以互相包含

用户输入

message = input('what do you want to do?\n')       # 输入 232323
print('oh,2323 ' + message)                        # oh, 232323

input() 函数让程序暂停运行,等待用户输入文本,并存储为一个变量,类型是字符串

while

number = 1
while number < 5:
    print(number)
    number += 1

message = ''
while message != 'quit':
    message = input('Enter cmd: ')
    print(message)

while True:
    message = input('Enter cmd: ')
    if message == 'quit':
        print(message)
        break
    else:
        print('wrong key')

使用 break 跳出循环

使用 continue 返回循环开头

names = ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']
while names:            # 在列表为空时退出循环
    print(names.pop())

函数

def greet_user(username):               # 形参
    print('Hello! ' + username)
greet_user(input('input your name: '))  # 实参

def greet_user(username, age):
    print('Hello! ' + username.title() + " you are " + age)
name = input('Name: ')
age = input('age: ')
greet_user(age=age, username=name)      # 关键字实参

关键字实参 不用考虑传参顺序

def greet_user(username, age='22'):     # age 参数拥有默认值,调用函数时可不传 age
    print('Hello! ' + username.title() + " you are " + age)
name = input('Name: ')
greet_user(name)                        # 这个时候最好使用关键字实参

def get_full_name(first, second):
    return first + ' ' + second
fullname = get_full_name('Victor', 'Afra55')
print(fullname)         # Victor Afra55

return 可返回任何类型的值

传递列表

def greet_users(temps):
i = 0
while i < len(temps):
    temps[i] = 'I get you ' + temps[i]
    i += 1
names = ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']
print(names)                    # ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']
greet_users(names)
print(names)                    # ['I get you Afra55', 'I get you Bfra55', 'I get you Cfra55', 'I get you Dfra55', 'I get you Fra55']

在函数中对传递进来的列表进行的修改,会修改原列表的值,是永久性的

如果不想改变原列表,则传递副本即可,例如:names[:]

传递未知数量的参数

def chat_friends(*friends):             # * 让 python 创建了一个 名为 friends 的 空元组,传人的参数都封装到了 friends 中  
    print(friends)
chat_friends('Afra')                    # ('Afra',)
chat_friends('Afra', 'Bfra', 'Cfra')    # ('Afra', 'Bfra', 'Cfra')

如果需要传入不同参数,则 位置实参或者关键字实参都要在 *friends 之前:def chat_friends(me, *friends):

def create_people(name, **info):                        # ** 让 python 创建了一个 名为 info 的 空字典,传参类型是 键值对 key=value
    print(name)
    print(info)
create_people('Afra', sex='man', age='22', space='af')  # Afra
                                                        # {'sex': 'man', 'age': '22', 'space': 'af'}

在模块中存储函数

模块,即扩展名为 .py 的文件

import module_name 用于倒入模块, 然后就可以使用该模块下的函数: module_name.function()

from module_name import function_name_0, function_name_1 从模块中倒入特定的(多个)函数, 然后就可以直接使用该方法:function_name_0()

from module_name import function_name as other_name 其中 as 用于给函数指定别名 other_name,以避免命名冲突

import module_name as other_module_name 其中 as 用于给 模块起个别名

from module_name import * 倒入模块中的所有函数,如果有同名函数或变量,当前文件中的函数或变量会覆盖倒入模块的函数或变量,不建议这种操作

建议

给形参指定默认值时,或传入关键字实参时,等号两边不要有空格

使用两个空行将函数分隔开

import 应在文件开头

类名采用驼峰命名法

实例名和模块名使用小写字母加下划线的方式命名

在类中使用一个空行来分隔方法

使用两个空行来分隔类

class People:            # 首字母大写的名称专指 类
    """类"""
    def __init__(self, name, age):    # 当创建这个类当实例时,会自动运行初始化方法 __init__()
        """初始化方法"""
        self.name = name
        self.age = age
    def sing(self):
        print(self.name + " sing a song!")
    def age_info(self):
        print(self.name + " age is " + self.age)

初始化方法 init() init 前后各有两个下划线,这是规定

类中的每个方法的第一个形数都是 self 用于指向实例本身,以便访问类中的方法和属性,self 自动传递,开发者不需要传递它

people_one = People('Afra', 22)
people_one.sing()           # Afra sing a song!
people_one.age_info()       # Afra age is 22
print(people_one.name)      # Afra
print(people_one.age)       # 22

初始化方法隐式的包含retrun语句,用于返回实例

对象名.方法

对象名.属性

继承

class Person:
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
    def print_info(self):
        print(self.name + " " + str(self.age) + " " + self.sex)


class Man(Person):
    def __init__(self, name, age):
        super().__init__(name, age, '男')


class Woman(Person):
    def __init__(self, name, age):
        super().__init__(name, age, '女')


man = Man('Afra', 23)
man.print_info()            # Afra 23 男

woman = Woman('Bfra', 23)
woman.print_info()          # Bfra 23 女

class 子类名(父类名): 继承,子类继承父类时,同时也获得了父类的所有方法和属性

super() 用于调用父类的方法或属性

父类与子类必须在同一文件中,且父类位于子类之前

必要的时候,重写父类方法

属性也可以是一个对象

导入类

from common import Person

from module_name import class_name, class_name_1, class_name_2 导入类, 多个点时候用逗号分隔

import common

import module_name 导入整个模块,这样可以使用模块中的所用函数和类, 最优选, 以 module_name.function_name() , module_name.class_name 引用方法或类

from module_name import * 导入模块中的所有类, 不推荐

Python 标准库

标准库的内容很丰富,不断的探索,才是乐趣的所在

https://pymotw.com/3/

from collections import OrderedDict
favorite_languages = OrderedDict()
favorite_languages['Afra55'] = 'python'
favorite_languages['Bfra55'] = 'java'
favorite_languages['Cfra55'] = 'golong'
favorite_languages['Dfra55'] = 'ruby'
for name, language in favorite_languages.items():
    print(name.title() + "'s favorite language is " + language.title() + ".")


# Afra55's favorite language is Python.
# Bfra55's favorite language is Java.
# Cfra55's favorite language is Golong.
# Dfra55's favorite language is Ruby.

OrderedDict 实例的行为几乎与字典相同,不同的是,OrderedDict 记录了 添加键值对的顺序

from random import randint
x = randint(1, 6)
print(x)    # [1, 6] 的随机数字

文件

with open('file_path/file_name.txt') as file_object:    # windows 系统中 ,路径间隔符号是反斜杠 \
    contents = file_object.read()
    print(contents)

open() 函数即,打开文件,返回一个表示文件的对象,传入的参数是要打开的文件的路径

with 关键字的意思是,在不需要访问该文件时,自动将其关闭,该文件仅在 with 代码块内使用

如果不使用 with 则需要使用 close() 来关闭文件

read() 函数用于读取文件的全部内容,并将内容以字符串的形式返回

read() 函数读取到文件末尾时会返回一个空字符串,print 打印出来就是一个空行

print(r'\n\tfffff')     # \n\tfffff

在字符串前面加 r 代表该字符串内部没有转移字符,都是原始字符

逐行读取

with open(r'file_name.txt') as file_object:
    for line in file_object:
        print(line)

可以使用for 循环来遍历每一行内容,注意每一行的结尾都有一个换行符

with open(r'pi_digits.txt') as file_object:
    lines = file_object.readlines()     

readlines() 函数从文件中读取每一行,存储在一个列表中,并返回该列表

写入文件

with open(r'file_name.txt', 'w') as file_object:
    file_object.write("i love python!")

如果要写入文件,则需要给open() 函数出入第二个实参打开模式(‘r’,’w’,’r+’,’a’), 以所需的模式打开 这个文件

读取模式 (‘r’)

写入模式 (‘w’), 会在返回该文件对象的时候,清空文件的内容, 慎用

读取和写入模式 (‘r+’)

附加模式 (‘a’),将内容附加在原文件所有内容之后

如果写入的文件不存在,open() 函数会自动创建这个文件

write() 函数用于写入内容到文件, 只能写入字符串

异常

异常,是一个特殊的对象,用于管理程序运行期间发生的错误

如果没有对异常进行处理,程序会停止,并显示错误信息

try:
    print(str(5/0))
except ZeroDivisionError:
    print('wrong')

使用 try-except 代码块捕获异常

try:
    answer = 5 / 1
except ZeroDivisionError:
    print('wrong')
else:
    print(answer)

try-except-else 其中 try 代码块成功执行的代码都应该放到 else 代码块中去使用

try:
    answer = 5 / 0
except ZeroDivisionError:
    pass
else:
    print(answer)

关键字 pass 告诉 python 这个地方什么都不用做

msg = 'I have a word what i can not read, please help me check this word'
print(msg.count('word'))        # 2

count() 函数用于返回 该字符串包含特定 字符串 的个数

模块 json 存储数据

import json

filename = 'file/json_file.json'

names = ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']

with open(filename, 'w') as file_obj:
    json.dump(names, file_obj)  # 存储了一个列表

with open(filename) as file_obj:
    print(file_obj.read())      # ["Afra55", "Bfra55", "Cfra55", "Dfra55", "Fra55"]

json.dump(存储的数据,用于存储数据的文件对象) 将数据存储到文件中,通常文件扩展名实 .json

import json

filename = 'file/json_file.json'

with open(filename) as file_obj:
    temp_names = json.load(file_obj)    # 返回了一个列表

print(temp_names)   # ['Afra55', 'Bfra55', 'Cfra55', 'Dfra55', 'Fra55']

json.load(文件对象) 读取文件并存储到变量中返回

测试代码

单元测试用于检查某个函数的某个功能有没有问题

测试用例是一组单元测试

全覆盖测试,包含一整套单元测试,涉及各种可能性

def get_fullname(first, last):
    fullname = first + ' ' + last
    return fullname.title()

对上面这个方法进行单元测试,使用 公共库 unittest

import unittest

class NamesTestCase(unittest.TestCase):
    def test_first_last_name(self):
        fullname = get_fullname('one', 'two')
        self.assertEqual(fullname, 'one two'.title())


unittest.main()

测试类必须继承 unittest.TestCase

当运行时,所有以 test 开头的方法都将自动运行

assert 断言

assertEqual() 用于检查结果是否与预期相符

unittest.main() 让 python 运行这个文件中的测试

常用断言

方法 含义
assertEqual(a, b) a == b
assertNotEqual(a, b) a != b
assertTrue(a) a == True
assertFalse(a) a == False
assertIn(item, list) if item in list
assertNotIn(item, list) if item not in list

测试类

class People:

    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age
        self.books = []

    def show_info(self):
        print(self.first_name + ' ' + self.last_name + ' ' + str(self.age))

    def store_book(self, book):
        self.books.append(book)

    def show_books(self):
        i = 1
        for book in self.books:
            print(str(i) + ':' + book)

测试上面的类

import unittest


class TestPeople(unittest.TestCase):

    def test_store_book(self):
        people = People('one', 'two', 22)
        people.store_book('Python')
        self.assertIn('Python', people.books)

    def test_store_four_book(self):
        people = People('one', 'two', 22)
        books = ['Python', 'Ruby', 'Java', 'Go']
        for book in books:
            people.store_book(book)
        for book in books:
            self.assertIn(book, people.books)


unittest.main()

类的测试需要实例化对象, 上面对每个测试方法都创建了一个实例

import unittest


class TestPeople(unittest.TestCase):

    def setUp(self):
        self.people = People('one', 'two', 22)
        self.books = ['Python', 'Ruby', 'Java', 'Go']

    def test_store_book(self):
        self.people.store_book('Python')
        self.assertIn('Python', self.people.books)

    def test_store_four_book(self):
        for book in self.books:
            self.people.store_book(book)
        for book in self.books:
            self.assertIn(book, self.people.books)


unittest.main()

setUp() 方法,创建测试类的属性,这些属性可以在这个类中的任何地方使用

测试结果

测试通过 ..

测试引发错误 E

测试断言失败 F

结语

一些人,先写测试用例,再写函数或类

小结

基础部分,掌握。第二步,项目实战。