Python 基础简明教程

Python 基础简明教程

这是 Python 程序设计的简明教程,假设你已经有其他高级编程语言的经验。

环境准备

环境准备过程中,核心要点如下:

  1. 官方下载地址 http://python.org/download/,推荐使用最新版
  2. 安装路径,推荐选择用户目录(默认选项)
  3. 环境配置,推荐将 Python 加入 PATH
  4. 开发工具,推荐使用 PyCharm 社区版

新建项目

在 Python 中新建项目的要点:

  1. 选择项目保存地址,按个人习惯选择,例如 ~/workspace
  2. 选择 Python 解释器(interpreter),可以用已经存在的解释器,也可以选择一个虚拟环境。

新建项目

Python 是解释型语言,解释器可以类比成 Java 的 JDK 版本。我个人非常不推荐直接使用默认的 Python 解释器,因为随着项目的开发我们会引入很多依赖包,每个项目对同一个依赖包的版本可能有所不同,这时候使用同一个解释器会造成依赖混乱,后期排查的难度非常大,那时候再去把项目分离属于没必要的成本。

如果只是学习或者做非专业项目开发,可以使用默认环境,同时请关注环境污染问题。

第一个程序

一行代码就可以开启 Python 世界的大门。

print('hello world')

友情提示:Python 中的变量和方法名主要以小写和下划线声明,请在你的代码里遵循这样的规范。

用面向对象和动态语言来写第一个程序。

class Employee(object):
    pass

if __name__ == '__main__':
    employee = Employee()
    employee.code = '007'
    employee.name = 'Toby'

Employee 对象可以不声明 codename 的属性,在程序运行中再给它添加 codename

if __name__ == '__main__’ 的意思是这是 Python 程序的入口,这行代码能让很多新手纠结半天。这其实还是简单的 if 判断,关键是 __name____main__ 是什么鬼。

__name__ 是 Python 模块的名字,双下划线属于 Python 进阶课程的内容,双下划线开头和结尾的变量一般属于 Python 的内置变量,__name__ 就是其中之一,指的是当前模块的名字。但是,如果当前模块是被直接运行的模块的话,值就等于 __main__,否则就等于模块原本的名字。

想了解更多双下划线的内容,搜索 Python 的魔方方法

我们做一个简单的例子,假设有 a 和 b 两个模块。

# a.py
def what_is_name():
    print('a.__name__ = ' + __name__)

if __name__ == '__main__':
    what_is_name()

现在直接运行脚本 a.py

$ python a.py
a.__name__ = __main__

这时候的__name__返回的值就是__main__。我们来写一个 b 模块,调用 a 模块,然后看看这时候 a 里的__name__是什么。

# b.py
import a

a.what_is_name()

现在直接运行脚本 b.py

$ python b.py
a.__name__ = a

这个例子看懂了,这个 Python 入门的坎就过去了。哦对了,Python 是按缩进来严格划分代码块的,这个坑踩几次就记住了。

Python 的数据类型

数据类型是编程语言里的核心概念,Python 内置的数据类型非常简单,分类如下。

文本类型   Text Type     :  str
数字类型   Numeric Types :	int, float, complex
序列类型   Sequence Types:	list, tuple, range
字典类型   Mapping Type  :	dict
集合类型   Set Types     :	set, frozenset
布尔类型   Boolean Type  :	bool
二进制类型  Binary Types :	bytes, bytearray, memoryview
空类型    None Type      :  None

实际工作中用的最多的类型主要是文本,数字,列表,字典,布尔。使用类型时不需要声明类型,Python 在运行时会根据实际值进行运算,这是动态语言的优势,但是在如此高的灵活性下对程序员的素质要求也很高。

a = 'hello'               # text type
b = 1                     # numeric type

c = [100,200,'test']      # list type
print(c[2])               # use
c[1] = 99                 # assign

d = {'a': 1, 'b': c}      # dict type
print(d['a'])             # use
d['b'] = 'test'           # assign

e = (1,3,4)               # set type
print(e[1])               # use it, cannot assign

f = True                  # bool type
g = b'hello'              # byte type
h = None                  # null type

要判断 Python 变量的类型是什么的话,可以用两种方法,第一个是type()

>>> type(1)
# <class 'int'>
>>> type('hello')
# <class 'str'>

第二种方法是 isinstance()

>>> isinstance(1, int)
# True
>>> isinstance(1, str)
# False

控制流和语法

Python 是最接近自然语言的编程语言,所以 Python 的控制流非常容易上手。下面列举一下我们常用的控制流和语法。

# if / else
if b > a:
  print("b > a")
else:
  print("b < a")

# while
while i < 6:
  print(i)
  i += 1

# for
fruits = ["apple", "banana", "cherry"]
for x in fruits:
  print(x)

# function
def my_function():
  print("Hello from a function")

# lambda
x = lambda a : a + 10
print(x(5))

# try / catch
try:
  print(x)
except:
  print("An exception occurred")

Python 的类和构造函数

有了一点双下划线的基础后,我们就可以了解一下 Python 类的构造函数,它也是一个双下划线,名字叫 __init__。看一个简单的例子。

class Employee(object):
    def __init__(self, code, name):
        self.code = code
        self.name = name

if __name__ == '__main__':
    employee = Employee('007', 'Toby')
    print(employee.code)
    print(employee.name)

def 是 Python 里声明方法的关键字,上面的例子我们重载 Employee 的构造函数,构造函数里加入了两个参数 codename。你是不是觉得我在骗你,明明是三个参数,还有个 self 为啥不把它当参数。

我没有骗你,你看在调用的时候你只给了两个参数:Employee('007', 'Toby')

好吧,这是 Python 的第二关,又可以让新手挠半天头。self 可以理解成 Java 或者 C# 里的 this,从英文上看就是一个意思。我们把 self 可以理解成当前类的实例(instance),Python 奇怪的是所有的实例方法都要传入当前的实例(作为第一个参数)。构造函数也是一个实例方法。

假如不传入当前实例会怎么样?那么这个方法就是类的静态方法,比如这样。

class Employee(object):

    @staticmethod
    def create(code, name):
        e = Employee()
        e.code = code
        e.name = name

# 调用静态方法
Employee.create('007', 'Toby')

其实这里要想深入需要更多篇幅,Python 类的实例方法里的第一个参数一定是当前对象,但不一定叫 self,可以叫阿猫阿狗,只是约定叫 self。想了解这个设计背后的初衷可以看这篇文档。

可变参数

现在来到 Python 世界的第三关:可变参数。可变参数有两种,一种是不需要名字的可变参数,比如我们有个很厉害的函数可以把所有的参数加起来。

def add(...):
    # sum up all arguments

这个怎么写?在别的编程语言几乎不可能实现这样的功能,但是 Python 可以。

def add(*args):
    return sum(args)

print(add(1, 2, 3, 4)) # => 10

这里的 *args 拿到的是一个数组,所有的参数都是这个数组里的元素,只有索引,没有名字。

可变参数的第二种情况是我们希望每个参数都有一个名字,这样在使用的时候会更方便。比如这个例子。

class Employee(object):

    def __init__(self, **kwargs):
        print(kwargs['code'])
        print(kwargs['name'])

if __name__ == '__main__':
    employee = Employee(code='007', name='Toby', mail='toby@test.com')

上面的代码里我们可以通过参数名字拿到参数的值,在参数比较多的情况下会尤其有用。这个例子里我还传入了一个叫 mail 的参数,实际上没有使用但程序并不会报错。

那么*args**kwargs 到底是什么对象呢?很简单:

  • *args 是一个Tuple,元组,和数组有一点细微的差别,就是元组不可变,数组可变。
  • **kwargs 是一个 dict,字典,和json 字符串差不多,就是一系列的 key=value

当这两个可变参数放在一个函数里时,这个函数就成了一个超级函数,可以接受任意参数。

class Employee(object):

    def __init__(self, *args, **kwargs):
        print(f'args = {args}')
        print(f'kwargs = {kwargs}')

        # args = ('007', 'Toby')
        # kwargs = {'phone': '123-456-789', 'mail': 'toby@mail.com'}

if __name__ == '__main__':
    employee = Employee('007', 'Toby', phone='123-456-789', mail='toby@mail.com')

在很多比较抽象的模块里,你可以能会很容易看到这样的超级函数。

必要关键字参数

顺带提一个实用小技巧,如果我们需要某些参数在调用的时候一定要传入参数名字,可以这样写。

def calc(a,b,*,operator):
    ...

calc(1,2,operator='+') # OK
calc(1,2,'+') #TypeError: calc() takes 2 positional arguments but 3 were given

为什么说这个技巧实用吗?想象一下假如你遇到这样的代码就知道这个用法的好处了。

magic('001','xxx','bbb','wtf',[1,2,3]) # 鬼知道我的参数是什么意思

使用 pip 安装依赖包

在 Python 的世界里有很多轮子,我们应该尽量避免造轮子,多去找找已经存在的轮子。pip 就是安装轮子的方法。比如我们要做网络请求相关的功能开发,可以这样安装 requests 依赖库。

pip install requests

如果提示 pip 命令找不到,你需要将 pip 加入 PATH,或者通过 Python 来调用 pip

python -m pip install requests

现在就可以直接访问一个网址了。

import requests

response = requests.get('https://api.ipify.org?format=json')
print(response.json()) # {"ip":"98.207.254.136"}

requests 库可以用最少和最优雅的代码来完成网络请求相关的所有操作,强烈安利一下。

requests.get(url)
requests.post(url, data={'a': 1})
requests.put(url, json={'b': 2})
requests.delete(url)

操作数据库

为了完成后面的新手任务,我们安装一个连接 mysql 的依赖包。

pip install mysql-connector-python

假设你本机有个 mysql 的服务,我们现在需要一个数据库和一张数据表。在命令行工具里完成以下库和表的建立。

$ mysql -uroot # 默认密码为空
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

# 创建和使用数据库
mysql> create database demo;
Query OK, 1 row affected (0.00 sec)

mysql> use demo;
Database changed

# 创建数据表
mysql> create table table Employee
    -> (id int primary key auto_increment,
    -> code varchar(100),
    -> name varchar(200)
    -> );
Query OK, 0 rows affected (0.00 sec)

连接数据库

数据库的配置文件一般要和代码分离,我们先写一个数据的配置文件。

# config.ini
[DB]
username=root
password=
database=demo

然后我们再来一个数据操作类,用来保存我们的 Employee 数据。

# database.py
import configparser
import mysql.connector

class Database(object):

    def connect(self):
        parser = configparser.ConfigParser()
        parser.read('config.ini')
        db_config = dict(parser.items('DB'))
        self.connection = mysql.connector.connect(**db_config)
        self.cursor = self.connection.cursor()

    def save_employee(self, employee):
        self.connect()

        sql = "INSERT INTO employee (code, name) VALUES (%s, %s)"
        val = (employee.code, employee.name)
        self.cursor.execute(sql, val)
        self.connection.commit()

        self.close()

    def close(self):
        self.cursor.close()
        self.connection.close()

现在回到 Employee 模块,像这样。

# employee.py
class Employee(object):

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

我们来加一个 main.py 的主模块。

# main.py
from model.database import Database
from model.employee import Employee

if __name__ == '__main__':
    emp = Employee('007', 'Toby')
    db = Database()
    db.save_employee(emp)

现在的目录结构看起来是这样的。

├── config.ini
├── main.py
├── model
   ├── __init__.py
   ├── database.py
   └── employee.py

现在来运行一下 main.py。

python main.py

去查一下数据库,数据应该已经存进去了。

mysql> select * from employee;
+----+------+------+
| id | code | name |
+----+------+------+
|  1 | 001  | Toby |
+----+------+------+
1 rows in set (0.00 sec)

查询数据库的方法可以这样写。

# database.py
def query_employee(self):
    sql = 'select * from employee'
    self.connect()
    self.cursor.execute(sql)
    result = self.cursor.fetchall()
    self.close()

    return result

操作数据库记得要关闭数据库,这是初级教程,其实有更优雅的办法来处理数据的打开关闭,比如使用Python 的装饰器,有兴趣可以了解一下。

完结

OK,感谢你的阅读。你已经入门 Python 了,我猜的。