Python 基础学习

一、学习路线

根据下图的Python路线进入Python学习之旅。

python 学习路线图


二、数据类型

学习一门编程语言,首先得学习它的数据类型和语法。基于现在的趋势,所有的都是基于Python3的学习。

Python 的基本数据类型有以下几类:

1. 数字(int)类型:int、float、complex
2. 布尔型(bloo)
3. 字符串(str)
4. 列表(list)
5. 元组(tuple)
6. 字典(dict)
7. 集合(set)

1. 数字类型(int)

Python3中,无论整数的大小长度为多少,统称为整型int。
GitHub代码commits id:b0f0c81

power_int = 2 ** 40
print("power_int:", power_int)
print("power_int_type:", type(power_int))
str_int = int('123')
print("str_int_type:", type(str_int))

bit_length_int = 123
print(bit_length_int.bit_length())

2. 布尔类型(bool)

  对于 bool 类型来说,只存在两种值 True 和 False,对应的二进制值分别是 1 和 0。True的值太多,但 False 的值可以穷举:None, 空([], (), {}, “”), 0。【GitHub代码commits id:e420fc2

none_value = bool(None)
print("none_value: ", none_value)
blank_1 = bool([])
print("blank_1: ", blank_1)
blank_2 = bool({})
print("blank_2: ", blank_2)
blank_3 = bool("")
print("blank_3: ", blank_3)
blank_4 = bool(())
print("blank_4: ", blank_4)
zero_value = bool(0)
print("zero_value: ", zero_value)

3. 字符串(str)

  字符串可由单引号或双引号来创建,字符串是不可修改的,字符串可进行以下操作【GitHub代码commits id:4abe110】:

(1)索引
(2)切片
(3)长度
(4)遍历
(5)删除
(6)分割
(7)替换
(8)连接
(9)大小写替换
(10)判断以什么开头
(11)判断字符串的内容
(12)格式话输出
(13)扩展
# 3.1 索引
#   index() 和 find() 的区别:若索引的字符串或序列不在字符串内,index--->返回的是ValueError:subString not found,而find--->返回 -1。
string1 = "没有什么独特"
index_str = string1.index("没", 0)
print("index_str: ", index_str)
find_str = string1.find("有", 2)
print("find_str: ", find_str)

# 3.2 切片
string2= "这是一首简单的歌"
section_str = string2[0: 1]
print("section_str: ", section_str)

# 3.3 长度
string3 = "试着带入我的心事"
len_str = len(string3)
print("len_str: ", len_str)

# 3.4 遍历
string4 = "它那么幼稚"
for ergodic_str in string4:
    print("ergodic_str: ", ergodic_str)
for index in range(len(string4)):
    print("ergodic_str2: ", string4[index])

# 3.5 删除
string5 = "像个顽皮的孩子"
del string5
# print("del_str: ", string5)

# 3.6 分割
# partition制定分隔符;split指定分隔符分割几次
string6 = "多么-可笑的-心事 TEST METHOD YOU LOSE"
partition_str = string6.partition("-")
print("partition_str: ", partition_str)
split_str = string6.split(" ", 2)
print("split_str: ", split_str)

# 3.7 替换
# 与替换相关的方法:replace、strip、lstrip、rstrip
string7 = " 顽皮的像个孩子的大人 "
replace_str = string7.replace('的', "XX", 2)
print("replace_str: ", replace_str)
strip_str = string7.strip()
print("strip_str去掉两边的空格:", strip_str)
lstrip_str = string7.lstrip()
print("lstrip_str去掉左边的空格:", lstrip_str)
rstrip_str = string7.rsplit()
print("rstrip_str去掉右边的空格:", rstrip_str)

# 3.8 连接
string8 = "MOREANDMORE"
join_str = '*'.join(string8)
print("join_str: ", join_str)
list8 = ['xi', 'as', 'peo']
join_list = "->".join(list8)
print("join_list: ", join_list)

# 3.9 大小写转换
# 第一个单词首字母大写:capitalize;全部字母小写:lower;全部字母大写:upper;单词首字母大写:title;大写转小写,小写转大写:swapcase
string9 = "start is More and More"
capitalize_str = string9.capitalize()
print("capitalize_str: ", capitalize_str)
lower_str = string9.lower()
print("lower_str: ", lower_str)
upper_str = string9.upper()
print("upper_str: ", upper_str)
tittle_str = string9.title()
print("tittle_str: ", tittle_str)
swapcase_str = string9.swapcase()
print("swapcase_str: ", swapcase_str)

# 3.10 判断字符串的内容
# isalnum字符串是数字或字母的组合;isalpha字符串全部是字母;isdigit字符串数字的组合
string11 = "Howare1213"
isalnum_str = string11.isalnum()
print("isalnum字符串是数字或字母的组合: ", isalnum_str)
isalpha_str = string11.isalpha()
print("isalpha字符串全部是字母:", isalpha_str)
isdigit_str = string11.isdigit()
print("isdigit字符串数字的组合:", isdigit_str)

# 3.11 判断以什么开头
string10 = "How are 你?"
startswith_str = string10.startswith("How")
print("startswith_str: ", startswith_str)
endswith_str = string10.endswith("?")
print("endswith_str: ", endswith_str)

# 3.12 格式化输出
string12 = "My name is {name}, I'am {age} years old."
print(string12.format(name="XIAO MI", age=9))
print(string12.format_map({"name": "MI", "age": 90}))

name = input("please input your name: ")
age = int(input("please input your age: "))
sex = bool(int(input("please input your sex: ")))
job = input("please input your job: ")
salary = input("please input your salary: ")

if sex == True:
    sex = 'male'
else:
    sex = 'fmale'

if salary.isdigit():
    salary = int(salary)
else:
    exit("salary must be int.")

print(name, age, sex, job, salary)   

# 格式化输出字符串
personal_info = '''
-------------Personal information of %s---------
.........NAME: %s
.........AGE: %d
.........SEX: %s
.........JOB: %s
.........SALARY: %f
.........WORK STILL: %d YEARS
--------------This is the end-------------
''' % (name, name, age, sex, job, salary, (65-age))

print(personal_info)

# 3.13 扩展
string13 = "name\tage\tsex\nA\t22\tmale\nB\t23\tfmale"
expandtabs_str = string13.expandtabs()
print("expandtabs_str: \n", expandtabs_str)

4. 列表(list)

  列表是由一系列特定元素顺序排列的元素组成的,它的元素可以是由任何数据类型即数字、字符串、列表、元组、字典、布尔值等,同时其元素是可以修改的。【GitHub代码commits id:9a6357b

(1)索引、切片
(2)追加
(3)拓展
(4)插入
(5)取出
(6)删除
(7)排序
# (1)索引、切片
list41 = [123, 'string', [1, 2, 3], (1, 2), {"APP": "1"}, True]
index_list = list41[2]
print("index_list: ", index_list)
section_list = list41[0: 3]
print("section_list: ", section_list)

# (2)追加【append】----- 将元素整体添加
list42 = [123, 'string', [1, 2, 3], (1, 2)]
list42.append([1, 2])
print("append_list: ", list42)

# (3)拓展【extend】----- 将元素分解添加
list43 = [123, 'string', [1, 2, 3], (1, 3)]
list43.extend([1, 3])
print("append_list: ", list43)

# (4)插入【insert】
list44 = [1, 2, "ok", [20, 9]]
list44.insert(3, "R")
print("insert_list: ", list44)

# (5)取出【pop】
list45 = [23, "OOO", "pop"]
list45.pop()
print("pop_list: ", list45)

# (6)删除【remove、del】
list461 = ["1", 2, "ok", [20, 9]]
list462 = ["1", 2, "ok", [20, 9]]
list461.remove("1")
print("remove_list: ", list461)
del list462[0]
print("del_list: ", list462)

# (7)排序【sorted】
list47 = [11,55,88,66,35,42]
print("sorted_list: ", sorted(list47))
print("sorted_reverse_list: ", sorted(list47, reverse=True))

5. 元组(tuple)

  元组即为不可修改的列表,用圆括号标识,特性和list相似。【GitHub代码commits id:aa1a46a

tuple51 = (1, 2, [22, 3])
print("切片:", tuple51[0])

6. 字典(dict)

  字典为一系列的键-值对,每个键值通过逗号分割,每个键对应一个值,可以通过键来访问值。无序访问。
键的要求:必须是不可变的。可以是数字、字符串、元组、布尔值。

dict61 = {
    ('ok', ): 1,
    "abc": "中文",
    True: ['abc']
}
print("dict61: ", dict61)
# 遍历字典----键
for key in dict61:
    print(key)
print(dict61.keys())
# 遍历字典----键值对
print(dict61.items())
# 遍历字典----值
print(dict61.values())

7. 集合(set)

  集合是一个无序不重复元素的集。set集合类需要的参数必须是迭代类型的,如:序列、字典等,然后转换为无序不重复的元素集。由于集合是不重复的,所以可以对字符串、列表、元组进行去重。

集合的特性:
    (1)去重    
    (2)无序       
    (3)每个元素必须为不可变类型(hashable类型,可作为字典的key)
set711 = {"ABC", 'abc', "test", "test", (12, 3), True}
set712 = set({"ABC", 'abc', "test", "test", (12, 3), True})
set713 = frozenset({"ABC", 'abc', "test", "test", (12, 3), True, "这是一个不可变的集合"})

# (2)增【add、update】
set721 = {'A', 'B', 'C'}
set721.add('D')
print("set_add: ", set721)
set722 = {'A', 'B', 'C'}
set722.update("ERT")
print("update_set: ", set722)

#(3)删除【pop、remove、discard】
set731 = {'A', 'B', 'C'}
set731.pop()
print("pop_set: ", set731)
set732 = {'A', 'B', 'C', 'D'}
set732.remove('C')
print('remove_set: ', set732)
set733 = {'A', 'B', 'C', 'DF'}
set733.discard('E')     # 如果未找到该元素,则无视
print("discard_set: ", set733)

#(4)关系运算【交集&、并集|、差集-、交叉补集^、issubset、isupperset】
set741 = {'a', 'b', 'c', 'd', 1}
set742 = {'A', 'D', 'e', 'F', 1}
print("交集&", set741 & set742)
print("并集|", set741 | set742)
print("差集-", set741 - set742)
print("交叉补集^", set741 ^ set742)
print("issubset前是否是后的子集:", set741.issubset(set742))
print("isupperset前是否是后的父集:", set741.issuperset(set742))

8. 栈(stack)

  栈是一种后进先出(FILO)的数据结构,可以操作列表来实现栈的数据结构特性。删除的元素相当于是删掉了栈尾的元素。【GitHub代码commits id:426eb81

class Stack():
    def __init__(self, size):
        self.stack131 = []
        self.top = -1
        self.size = size

    def isfull(self):
        return self.top + 1 == self.size

    def isempty(self):
        return self.top == '-1'

    # 入栈前先检查栈是否已满
    def push_stack(self, x):  
        if self.isfull():
            raise Exception("statck is full")
        else:
            self.stack131.append(x)
            self.top = self.top + 1

    # 出栈之前检查栈是否为空
    def pop_statck(self):   
        if self.isempty():
            raise Exception("stack is empty")
        else:
            self.top = self.top - 1
            self.stack131.pop()

    def show_stack(self):
        print(self.stack131)


if __name__ == "__main__":
    s = Stack(10)
    s.show_stack()
    for i in range(6): 
        s.push_stack(i)
    s.show_stack()
    for i in range(3):
        s.pop_statck()
    s.show_stack()
    print("stack FILO is end.......")

9. 队列(queue)

  队列是一种后进先出(FIFO)的数据结构,可以操作列表来实现栈的数据结构特性。新增的元素是添加的队列结尾的元素,出队列的元素相当于是删掉了对列前面的元素。【GitHub代码commits id:6367333

class Queue():
    def __init__(self, size):
        self.queue132 = []
        self.front = -1
        self.rear = -1
        self.size = size

    def isfull(self):
        return self.rear - self.front + 1 == self.size

    def isempty(self):
        return self.front == self.rear

    # 入队列
    def enqueue(self, x):
        if self.isfull():
            raise Exception("queue is full")
        else:
            self.queue132.append(x)
            self.rear = self.rear + 1

    # 出队列
    def dequeue(self):
        if self.isempty():
            raise Exception("queue is empty")
        else:
            self.queue132.pop(0)
            self.front = self.front + 1

    def show_queue(self):
        print(self.queue132)

if __name__ == "__main__":
    s = Stack(10)
    s.show_stack()
    for i in range(6): 
        s.push_stack(i)
    s.show_stack()
    for i in range(3):
        s.pop_statck()
    s.show_stack()
    print("stack FILO is end.......")

    q = Queue(7)
    q.show_queue()
    for i in range(6):
        q.enqueue(i)
    q.show_queue()
    for i in range(3):
        q.dequeue()
    q.show_queue()

三、语法结构

1. 选择结构

序结构就是按照你写的代码顺序执行,也就是一条一条语句顺序执行。

分支结构又称为选择结构,是程序代码根据判断条件选择执行特定的代码。
如果条件为真,程序执行一部分代码;否则执行另一部分代码
基本语法:
    1、if
    2、if...else
    3、if...elif...else
    4、if...elif...elif......else
    5、if 嵌套
# 1.if 
a = 1
if a == 1:
    print("你的输出正确")

# 2.if...else...
a = 1
if a == 1:
    print("a的值为1")
else:
    print("a的值不为1")

# 3.if...elif...else...
a = 1
if a > 1:
    print("a的值大于1")
elif a == 1:
    print("a的值等于1")
else:
    print("a的值小于1")

# 4.if...elif...elif......else
a = 1
if a == 1:
    print("a的值为1")
elif a == 2:
    print("a的值为2")
elif a == 3:
    print("a的值为3")
else:
    print("a的值为不知道是什么")

# 5.if 嵌套
a = 1
b = 2
if a == 1:
    if b == 2:
        print("b的值为1")
    else:
        print("b的值不知道是什么")
else:
    print("a的值迷失了~")

2. 循环结构

循环结构是指满足一定的条件下,重复执行某段代码的一种编码结构。
Python的循环结构中,常见的循环结构是for循环和while循环。
for 循环经常用与遍历字符串、列表、字典等数据结构,for循环需要知道循环次数。
# 1. for...in...
list1 = [1, 2, 3, 4, 5, 2, 4, 7, 9, 0]
count = 0
for i in list1:
    if i == 2:
        count += 1
print("count: ", count)

# 2.嵌套for循环
# 乘法表
result = 0
for i in range(1, 10):
    for j in range(1, i + 1):
        print(str(j) + '*' + str(i) + '=' + str(i*j) + '', end=' ')
    print(' ')


# 3.while循环
num = 1
while num <= 5:
    print("num:", num)
    num += 1


四 文件操作

  读写文件是最常见的IO操作,现代操作系统不允许普通程序直接操作磁盘,读写文件就是请求操作系统打开一个文件操作对象,通过操作系统提供的接口进行对文件的读写操作。

1. 读文件

读取文件的三个必要步骤:
(1)以读文件的模式 read 打开一个文件对象;
(2)read() 方法读取文件中的内容;
(3)文件读取操作完后,要进行文件的关闭。因为文件对象会占用操作系统资源。
# codecs模块:主要用来解决文件乱码的问题
import codecs

f_read = codecs.open('read_file.txt', 'rb', encoding="utf-8")
print("f_read: ", f_read.read())
f_read.close()

2. 写文件

GitHub代码commits id:494a336

f_write = codecs.open('write_file.txt', 'wb', encoding='utf-8')
f_write.write("********************\n")
f_write.write("<鹅>\n")
f_write.write("曲项向天歌\n")
f_write.write("白毛浮绿水\n")
f_write.close()

3. 文件操作常用方法

GitHub代码commits id:847a943

# 3.1 readlines():用于读取所有行(直到结束符 EOF)并返回列表,该列表可以由 Python 的 for... in ... 结构进行处理。
f_readlines = codecs.open('write_file.txt', 'rb', encoding='utf-8')
text_list = f_readlines.readlines()
print('text_list_type: ', type(text_list))
print("text_list: ", text_list)
print(text_list[2])
f_readlines.close()

# 3.2 readline():用于从文件读取整行,包括 "\n" 字符。如果指定了一个非负数的参数,则返回指定大小的字节数,包括 "\n" 字符。
#     __next__():返回迭代器的下一个指向
f_readline = codecs.open('read_file.txt', 'rb', encoding='utf-8')
readline_list = f_readline.readline()
print('readline_list_type: ', type(readline_list))
print("readline_list: ", readline_list)
print(f_readline.__next__())
print(f_readline.__next__())
f_readline.close()

# 3.3 writelines():用于向文件中写入一序列的字符串。
f_writelines = codecs.open("writelines_file.txt", 'wb', encoding='utf-8')
write_list = f_writelines.write("1213311\nnewbanlance\n\n")
writelines_list = f_writelines.writelines(["11111111\n", '2222222\n', '333333333\n'])
f_writelines.close()

# 3.4 tell():返回文件的当前位置,即文件指针当前位置。
f_tell = codecs.open('tell_file.txt', 'wb', encoding='utf-8')
f_tell.write("1213311\nnewbanlance\n\n")
print(f_tell.tell())
f_tell.writelines(["11111111\n", '2222222\n', '333333333\n'])
print(f_tell.tell())
f_tell.close()

# 3.5 seek():用于移动文件读取指针到指定位置
f_seek = codecs.open('seek_file.txt', 'wb', encoding='utf-8')
f_seek.write("abcdefgh\n12131313\n\djkfdjskfjkd\n")
print(f_seek.tell())
f_seek.seek(0)
f_seek.writelines(["11111111\n", '2222222\n', '333333333\n'])
f_seek.close()

# 3.6 name(): 读取文件名
f_name = codecs.open('name_file.txt', 'wb', encoding='utf-8')
print("f_name: ", f_name.name)
print("f_name_closed", f_name.closed)

# 3.7 flush(): 刷新缓冲区的,即将缓冲区中的数据立刻写入文件,同时清空缓冲区,不需要是被动的等待输出缓冲区写入。一般情况下,文件关闭后会自动刷新缓冲区,
# 但有时你需要在关闭前刷新它,这时就可以使用 flush() 方法。

4. 文件操作的上下文管理

文件操作中经常会忘记文件的关闭操作,使用with操作会避免这一情况的发生。
GitHub代码commits id:ecf390d

with codecs.open('with_file.txt', 'wb', encoding='utf-8') as f_with:
    f_with.write("test with.")
    print("f_with_closed: ", f_with.closed)
print("f_with_closed: ", f_with.closed)

五、函数

函数是一段组织好的、可以重复使用的,用来实现单一或相关功能的代码段。
函数能提高应用的模块性,提高代码的利用率。

1. 自定义函数

1.1 函数语法

def 函数名(参数)...
	函数体
	...
	
# 自定义函数
def custom_func(elem):
    print("这是我的自定义函数...")
    print("我是参数elem: ", elem)

# 函数调用
custom_func(1)

1.2 函数的参数

1.2.1 普通参数
def common_parameter(par1, par2):       # 函数定义,形参,提供给使用者一个接口
    print(par1)
    print(par2)

common_parameter(11, 22)    # 函数调用,实参,实参值传递给形参
1.2.2 默认参数
# par_default为函数的默认参数,函数调用时如果不传值的话,就是用默认的参数的值;如果传值了就用传的值
def default_parameter(par1, par2, par_default="我是默认值"):
    print("..........default parameter..........")
    print(par1)
    print(par2)
    print(par_default)

default_parameter("我是par1", 222)
default_parameter(111, 222, "test")
default_parameter(par_default="位置参数生效", par1=1111, par2=True)
1.2.3 动态参数
# (1) 可以接受任意个参数
# (2) 动态参数有两种:*args和**kwargs,*args必须在*kwargs的前面
#       *args: 接受的是按照位置传参的值,组织成一个 **元组**
#       **kwargs: 接受的是按照关键字传参的值,组成一个 **字典**
# (3) 参数的传递顺序:位置参数、*args、默认参数、**kwargs
def dynamic_parameter(par1, par2, *args, par_default="default", **kwargs):
    print(".......dynamic parameter.......")
    print(par1)
    print(par2)
    print(args)
    print(par_default)
    print(kwargs)
    print(kwargs['name'])
    print(kwargs['age'])
    

dynamic_parameter(1, 2, 2, 3, 4, 5, par_default=5, name='kwargs', age=12)

1.3 函数的返回值

# return 语句用于退出函数,选择性地向调用方式返回一个表达式。不带参数值的return语句返回None。
def return_func(a, b):
    total = a + b
    print("函数内:", total)
    return total


total_exc = return_func(12, 23)
print("函数外:", total_exc)

2. 异常处理

  异常就是程序执行时发生错误的信号,Python中不同异常用不同类对象标识不同的异常,一个异常标识一种错误。

  Python程序执行时,检测到一个错误时,如果不处理程序就在当前异常处终止。编写特定的异常处理代码专门来处理异常,如果捕捉成功则进入定制的另一个程序分支,使程序不崩溃。所以在程序中必须提供一种异常处理机制来增强程序的健壮性和容错性,提高用户体验。

2.1 常见异常类:

(1) AttributeError          访问的对象没有该属性
(2) IOError                 输入/输出异常,基本上是无法打开文件
(3) ImportError             无法引入模块或包,基本是路径或名称错误
(4) IndentationError        语法错误,代码没有正确对齐
(5) IndexError              下标索引超出边界
(6) KeyError                访问的字典里面不存在的键
(7) KeyboardInterrupt       Ctrl + c 被按下
(8) NameError               访问一个还未被赋予对象的变量
(9) SyntaxError             Python代码非法,代码不能编译
(10) TypeError              传入对象类型与要求的不符合
(11) ValueError             传入一个调用者不期望的值
(12) UnboundLocalError      访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量
(13) AssertionError         断言错误,说明断言的条件为假
(14) ..............

2.2 异常处理方式

2.2.1 try…exception…finally

GitHub代码commits id:a7df219

list_exception = [1, 2, 3]

try:
    for i in list_exception:
        print(list_exception[i+2])

    raise TypeError('....主动抛出异常...')
except IndexError as e:
    print("异常 %s 已经在这里被捕获了,下面再有异常处理就不再被捕获了" % e)
except Exception as e:
    print(e)
finally:
    print("程序执行结束,不管异常是否被捕获,这里一定始终会执行")
2.2.2 try…exception…else

GitHub代码commits id:47da104

else_exception = [1, 2, 3]
try:
    for i in [1, 4]:
        print(i)
except IndexError as e:
    print(e)
except SyntaxError as se:
    print(se)
else:
    print("只有再try语句里面的执行成功的时候,才会执行else里面的内容")

2.3 自定义异常

GitHub代码commits id:e8936a9

class EvaException(BaseException):
    def __int__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg


try:
    raise EvaException("自定义错误")
except EvaException as e:
    print(e)

2.4 断言

  assert断言是声明其布尔值必须为真的判定,如果发生异常则说明表达式为假。
GitHub代码commits id:b4641c

assert 1 == 1
try:
    assert 1 == 2
except AssertionError as e:
    print("看见我说明断言的判断条件是错误的,这个异常已经被我捕获了: %s" % e)

六、面向对象编程

  面向对象(Object Oriented)设计思想贯穿程序设计,面向对象编程(Object Oriented Programming)是针对大型软件设计提出的,它能使代码更好滴复用,使程序更加的灵活。对象 是一个抽象的概念,万事万物皆可对象。对象通常可划分为两个部分,静态部分动态部分 ;【静态部分】称之为 属性,【动态部分】称为 方法

  面向对象编程中,将函数和变量进一步封装成类,类才是程序的基本元素,它将数据和操作紧密连接,并保护数据不被外界意外改变。

1. 面向对象术语

面向对象中的相关术语整理如下:
(1)类(class):用来描述具有相同【属性】和【方法】的对象集合,定义了该集合中每个对象所共有的属性和方法,其中对象被称为类的实例;
(2)实例:也称对象,通过类定义的初始化方法赋予具体的值;
(3)实例化:创建类的实例的过程;
(4)实例变量:定义在实例中的变量,只作用于当前实例;
(5)类变量:类变量是所有实例公有的变量。类变量定义在类中,但在方法体之外;(6)数据成员:类变量、实例变量、方法、类方法、静态方法和属性等的统称;
(7)方法:类中定义的函数;
(8)静态方法:不需要实例化就可以有类执行的方法;
(9)类方法:类方法是将类本身作为对象进行操作的方法;
(10)方法重写:从父类继承的方法不能满足子类的需求,可对父类的方法进行重写;
(11)继承:一个派生类继承父类的变量和方法;
(12)多态:根据对象类型的不同以不同的方式进行处理
# (1)类
class OOPObject(object):
    # (5)类变量:定义在类中,方法之外的变量
    phone = 123456789
    address = "memory"

    # __init__方法的类在实例化的时候,会自动调用该方法,并传递对应的参数
    def __init__(self, name, age):
        # (4)实例变量,name 和 age就是实例变量
        self.name = name
        self.age = age

    # (7)实例方法
    def o_method(self):
        print("{0}:{1}".format(self.name, self.age))

    # (8)静态方法:不需要实例化就可以有类执行的方法
    @staticmethod
    def static_method():
        print("我是静态方法")

    # (9)类方法:类方法是将类本身作为对象进行操作的方法
    # 采用@classmethod装饰,至少传入一个cls(指类本身,类似于self)参数。
    # 执行类方法时,自动将调用该方法的类赋值给cls。
    # 使用类名.类方法的调用方式(也可以使用实例名.类方法的方式调用)
    @classmethod
    def class_method(cls):
        print("我是类方法")


# (2)实例
# (3)实例化---这个过程
o1 = OOPObject("oj", 23)
# 实例方法的调用
o1.o_method()


# (6)数据成员:类变量、实例变量、方法、类方法、静态方法和属性等的统称

# (8)静态方法的调用
OOPObject.static_method()


# 类方法
OOPObject.class_method()

2. 面向对象三特征

面向对象的三大特征:封装继承多态

2.1 封装

  封装是指将 数据具体操作 的代码放在某个对象内部。使这些代码的实现细节不被外界发现,外界只能通过接口访问该对象(外界也不能直接访问类的变量和方法),而不能通过任何形式修改对象内部的实现。【GitHub代码commits id:cc3bc98

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
@File    :   62_OOPFeatures.py
@Time    :   2019/8/14 15:15
@Author  :   Crisimple
@Github :    https://crisimple.github.io/
@Contact :   Crisimple@foxmail.com
@License :   (C)Copyright 2017-2019, Micro-Circle
@Desc    :   None
"""

class ThisClass(object):
    class_name = 'This class'
    class_age = 12

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def print_class(self):
        print("{0}:{1}".format(self.name, self.age))


# 这就说明:外部不能直接调用类变量和类方法
# print(class_name)  NameError: name 'class_name' is not defined
# print_class()   NameError: name 'print_class' is not defined

# 使用:类名/实例名.变量/方法,来访问类的变量或方法
print(ThisClass.class_name)
ThisClass.class_name = 'Change name value'
print(ThisClass.class_name)
ThisClass.class_add_attribute = 'Test add attribute'
print(ThisClass.class_add_attribute)
tc = ThisClass('A', 23)
print(tc.print_class())

2.2 继承

  继承实现了代码的复用,多个类公用的代码可以只在一个类中提供,其他类只需集成这个类即可。继承最大的好处就是 子类(新定义的类) 获得了 父类(被继承的类也可成为基类或超类) 的全部变量和方法同时,又可以根据需求进行修改和扩展。
  继承又分为两类:实现继承(使用基类的属性和方法无需额外编码的能力)接口继承(仅使用属性和方法的名称,子类必须提供实现的能力,即子类重构父类方法)。【GitHub代码commits id:a7b3bee

2.2.1 构造方法的继承

继承构造方法的方式:

    (1)经典继承的写法:父类名称.__init__(self, 参数1, 参数2)
    (2)新式类的写法:super(子类, self).__init__(self, 参数1,参数2)
    
    实例化对象b ---> b调用子类的构造方法__init__() ---> 子类的构造方法__init__()继承父类的构造方法__init__() ---> 调用父类的构造方法__init__()
class FatherClass(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.country = 123

    def father_method(self):
        print('father is walking')


class BoyClass(FatherClass):
    # 先继承再重构,反着来子类就不能继承父类的属性了
    def __init__(self, name, age, sex):
        # 继承父类的构造方法
        # 经典继承
        # FatherClass.__init__(self, name, age)
        # 新式类继承
        super(BoyClass, self).__init__(name, age)
        # 定义子类本身的属性
        self.sex = sex

    def child_method(self):
        print('child is walking')


class GirlClass(FatherClass):
    pass


# 子类构造方法继承父类构造方法过程如下:
#   实例化对象b ---> b调用子类的构造方法__init__() ---> 子类的构造方法__init__()继承父类的构造方法__init__() ---> 调用父类的构造方法__init__()
b = BoyClass('Boy', 25, 'male')
print(b.name)
print(b.age)
print(b.sex)
print(b.country)
2.2.2 子类对父类方法的重写

如果要对父类的方法进行修改,而又不影响其他继承父类的类,我们可以再子类中重构该方法。

# 2.继承
class FatherClass(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.country = '中国'

    def father_method(self):
        print('father is walking')

    def talk(self):
        print("I'am father. %s" % self.name)


class BoyClass(FatherClass):
    # 先继承再重构,反着来子类就不能继承父类的属性了
    def __init__(self, name, age, sex):
        # 继承父类的构造方法
        # 经典继承
        # FatherClass.__init__(self, name, age)
        # 新式类继承
        super(BoyClass, self).__init__(name, age)
        # 定义子类本身的属性
        self.sex = sex
        print(self.name, self.age, self.country, self.sex)

    def child_method(self):
        print('child is walking...')

    def talk(self):
        print("I'am child. %s" % self.name)


class GirlClass(FatherClass):
    pass


# 2.1 构造方法继承
# 子类构造方法继承父类构造方法过程如下:
#   实例化对象b ---> b调用子类的构造方法__init__() ---> 子类的构造方法__init__()继承父类的构造方法__init__() ---> 调用父类的构造方法__init__()
b = BoyClass('Boy', 25, 'male')
print(b.name)
print(b.age)
print(b.sex)
print(b.country)
# 2.2 子类重写父类方法
f = FatherClass('A', 30)
f.talk()
b.talk()

2.3 多态

  多态是指一类事物具有多种形态。Python的多态性是指在不考虑实例类型的情况使用实例,也就是说不同类型的实例有相同的调用方法。【GitHub代码commits id:de62018

  使用多态的好处:

(1)增加了程序的灵活性:以不变应万变,不论对象千变万化,使用同一种形式去调用,如show_say(animal)
(2)增加了程序的可扩展性:通过继承Animal(下面代码例子)类创建了一个新的类,使用者无需更改自己的代码,还是用show_say(animal)方法去调用。
class Animal(object):       # 同一类事物:动物
    def say(self):
        print("I'm animal.")


class Dog(Animal):          # 动物的形态之一:狗
    def say(self):
        print("Wang wang~")


class Cat(Animal):          # 动物的形态之一:猫
    def say(self):
        print("Miao miao~")


class Cow(Animal):          # 动物的形态之一:牛
    def say(self):
        print("Mou mou~")


d = Dog()
ca = Cat()
co = Cow()
# d, ca, co 都是动物,都属于动物类,肯定都有say_hi()方法,因此不用考虑他们具体是什么类型,直接使用即可
d.say()
ca.say()
co.say()
# 我们可以统一一个接口来调用动物类的say_hi()方法
def show_say(animal):
    animal.say()


show_say(d)
show_say(ca)
show_say(co)