Python学习 - 初级第一回(语法与函数)

初学Python时就被它精简、高效、人性的语法所折服,所以连夜将Python的语法和内置模块进行了研读,有点相见恨晚的感觉。精简在于它的语法非常简单实用,入门非常容易;高效在于它有很多内置模块对常用功能进行了封装,只需要很少的代码就能完成一个复杂的功能,如果内置模块不够用,还有很多第三方模块可以拿来直接使用;人性在于它的语法非常符合人的逻辑思维,读Python的代码就像在读一遍英语短文一样,很容易理解代码的目的。在此墙裂推荐廖雪峰老师的Python入门教程: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

简单梳理一下Python入门的知识点,希望起到知识大纲的作用吧。让我们一起来感受Python的美妙。

1. Python能干嘛
  • 首选是网络应用,包括网站、后台服务等等
  • 网络爬虫
  • 其次是许多日常需要的小工具,包括系统管理员需要的脚本任务等等
  • 还有把其他语言开发的程序再包装起来,方便使用
2. Python的缺点
  • 运行速度慢,和C程序相比非常慢,因为Python是解释型语言,你的代码在执行时会一行一行地翻译成CPU能理解的机器码,这个翻译过程非常耗时,所以很慢。
  • 代码不能加密。如果要发布你的Python程序,实际上就是发布源代码。
3. Python的解释器
  • CPython,这是官方版本的解释器,也是使用最广的Python解释器;
  • Jython,是运行在Java平台上的Python解释器,可以直接把Python代码编译成Java字节码执行;
  • IronPython,IronPython和Jython类似,只不过IronPython是运行在微软.Net平台上的Python解释器,可以直接把Python代码编译成.Net的字节码;
  • 小结: Python的解释器很多,但使用最广泛的还是CPython。如果要和Java或.Net平台交互,最好的办法不是用Jython或IronPython,而是通过网络调用来交互,确保各程序之间的独立性。
4. Python的IDE
  • Sublime Text
  • PyCharm
5. Python的基本格式
  • 采用缩进方式
  • 以#开头的语句是注释
  • 大小写敏感
# print absolute value of an integer:
a = 100
if a >= 0:
    print(a)
else:
    print(-a)
6. Python的基本数据类型
  • 整数: 十六进制用0x前缀和0-9,a-f表示。另外,int()方法可以将字符串转为整数,如int('123', base=10)
  • 浮点数: 对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,如1.23e9,或者12.3e8
  • 字符串
    • 字符串是以单引号’或双引号”括起来的任意文本,比如’abc’,”xyz”
    • Python还允许用r”表示”内部的字符串默认不转义,如print(r'\\\t\\')
    • Python允许用”’…”’的格式用于换行
    print('''line1
    line2
    line3''')
  • 布尔值: 在Python中,可以直接用True、False表示布尔值(请注意大小写),另外布尔值可以用and、or和not运算
  • 空值: 空值是Python里一个特殊的值,用None表示
  • 变量: 在Python中,等号=是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量。也就是说Python里的变量没有固定类型。
  • 常量: 在Python中,通常用全部大写的变量名表示常量。但事实上PI仍然是一个变量,Python根本没有任何机制保证PI不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量PI的值,也没人能拦住你。
7. 字符串与字符编码
  • 由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
  • 以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:
>>> 'ABC'.encode('ascii')
b'ABC'
>>> '中文'.encode('utf-8')
b'\xe4\xb8\xad\xe6\x96\x87'
>>> '中文'.encode('ascii')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
  • 反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法:
>>> b'ABC'.decode('ascii')
'ABC'
>>> b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8')
'中文'
  • 在操作字符串时,我们经常遇到str和bytes的互相转换。为了避免乱码问题,应当始终坚持使用UTF-8编码对str和bytes进行转换。
  • 由于Python源代码也是一个文本文件,所以,当你的源代码中包含中文的时候,在保存源代码时,就需要务必指定保存为UTF-8编码。当Python解释器读取源代码时,为了让它按UTF-8编码读取,我们通常在文件开头写上这两行:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
  • 格式化字符串的两种方法
>>> 'Hello, %s' % 'world'
'Hello, world'
>>> 'Hi, %s, you have $%d.' % ('Michael', 1000000)
'Hi, Michael, you have $1000000.'
>>> 'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
'Hello, 小明, 成绩提升了 17.1%'
8. 集合
  • list
#定义list
>>> classmates = ['Michael', 'Bob', 'Tracy']
#通过索引访问,index可以为负数,表示倒数访问
>>> classmates[0]
#追加元素到末尾
>>> classmates.append('Adam')
#插入元素到指定位置
>>> classmates.insert(1, 'Jack')
#删除指定位置元素,参数为空时表示删除末尾元素
>>> classmates.pop(1)
#直接替换某个位置的元素
>>> classmates[1] = 'Sarah'
#list可以嵌套
>>> s = ['python', 'java', ['asp', 'php'], 'scheme']
#访问嵌套元素
>>> s[2][1]
  • tuple
#与list类似,定义如下,只是不允许对其进行修改
>>> classmates = ('Michael', 'Bob', 'Tracy')
#定义只有一个元素的tuple时,应该如下:
>>> classmates = (1,)`这里写代码片`
#可变的tuple,tuple里嵌套list即可变向实现可变的tuple
>>> t = ('a', 'b', ['A', 'B'])
>>> t[2][0] = 'X'
  • deque

    • 使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低。

    • deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈:

>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])
  • dict
    Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储
#创建dict
>>> d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
#新增键值对,由于一个key只能对应一个value,所以,多次对一个key放入value,后面的值会把前面的值冲掉
>>> d['Adam'] = 67
#通过key访问value,如果key不存在,dict就会报错
>>> d['Thomas']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Thomas'
#判断key是否存在
>>> 'Thomas' in d
False
#通过get方法取得value,如果key不存在则返回None,也可以指定返回的值
>>> d.get('Thomas')
>>> d.get('Thomas', -1)
-1
#删除一个键值对
>>> d.pop('Bob')
  • set
    类似于Java的set,表示一个不重复的key集合
#初始化
>>> s = set([1, 2, 3])
>>> s
{1, 2, 3}
#天生排重
>>> s = set([1, 1, 2, 2, 3, 3])
>>> s
{1, 2, 3}
#通过add(key)方法可以添加元素到set中
>>> s.add(4)
#通过remove(key)方法可以删除元素
>>> s.remove(4)
#通过set取交集与并集
>>> s1 = set([1, 2, 3])
>>> s2 = set([2, 3, 4])
>>> s1 & s2
{2, 3}
>>> s1 | s2
{1, 2, 3, 4}
9. 条件判断
age = 3
if age >= 18:
    print('adult')
elif age >= 6:
    print('teenager')
else:
    print('kid')
10. 循环
sum = 0
for x in range(101):
    sum = sum + x
print(sum)
n = 1
while n <= 100:
    if n > 10: 
        break
    print(n)
    n = n + 1
print('END')
*11. 函数
  • 定义函数
#可以不return,如果函数里没有return,默认在最后return了None
def my_abs(x):
    if x >= 0:
        return x
    else:
        return -x

#定义空函数
def nop():
    pass

#返回多个值,实际返回的是一个tuple
import math

def move(x, y, step, angle=0):
    nx = x + step * math.cos(angle)
    ny = y - step * math.sin(angle)
    return nx, ny
>>> x, y = move(100, 100, 60, math.pi / 6)
  • 函数参数
#默认参数
def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

#有多个默认参数时,调用的时候,既可以按顺序提供默认参数,比如调用enroll('Bob', 'M', 7)
#也可以不按顺序提供部分默认参数。当不按顺序提供部分默认参数时,需要把参数名写上。比如调用enroll('Adam', 'M', city='Tianjin')
def enroll(name, gender, age=6, city='Beijing'):
    print('name:', name)
    print('gender:', gender)
    print('age:', age)
    print('city:', city)

#定义默认参数要牢记一点:默认参数必须指向不变对象
def add_end(L=[]):
    L.append('END')
    return L

#可变参数定义
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum
#可变参数调用
>>> calc(1,2,3,4)
#或者这样调用
>>> nums = [1, 2, 3]
>>> calc(*nums)

#关键字参数定义
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)
#关键字参数调用
>>> person('Adam', 45, gender='M', job='Engineer')
#也可以这样调用
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)

#命名关键字参数定义,和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数
def person(name, age, *, city, job):
    print(name, age, city, job)
#如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person(name, age, *args, city, job):
    print(name, age, args, city, job)
#命名关键字参数调用,命名关键字参数必须传入参数名
>>> person('Jack', 24, city='Beijing', job='Engineer')

#组合参数
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
#对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(*args, **kw)
12. 切片
#list, tuple的切片
>>> L = list(range(100))
>>> L[:10:2]
[0, 2, 4, 6, 8]

#类的切片,实现__getitem__()方法使类表现得像list那样可以按照下标取元素
class Fib(object):
    def __getitem__(self, n):
        if isinstance(n, int): # n是索引
            a, b = 1, 1
            for x in range(n):
                a, b = b, a + b
            return a
        if isinstance(n, slice): # n是切片
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                    L.append(a)
                a, b = b, a + b
            return L

>>> f = Fib()
>>> f[0:5]
[1, 1, 2, 3, 5]
>>> f[:10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
13. 迭代
#可以通过for...in来循环遍历的对象叫做可迭代对象,如list, tuple, dict, set, str等
>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> for key in d:
...     print(key)

#判断一个对象是否为可迭代对象
>>> from collections import Iterable
>>> isinstance('abc', Iterable) # str是否可迭代
True
>>> isinstance([1,2,3], Iterable) # list是否可迭代
True
>>> isinstance(123, Iterable) # 整数是否可迭代
False

#可以同时在for循环里引用两个变量
>>> for x, y in [(1, 1), (2, 4), (3, 9)]:
...     print(x, y)
...
14. 列表生成式
#根据某一规则动态生成一个list
>>> [x * x for x in range(1, 11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

#生成列表时,for循环后面可以加上if判断
>>> [x * x for x in range(1, 11) if x % 2 == 0]
[4, 16, 36, 64, 100]

#可以使用两层循环,可以生成全排列:
>>> [m + n for m in 'ABC' for n in 'XYZ']
['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']

#使用两个变量来生成list
>>> d = {'x': 'A', 'y': 'B', 'z': 'C' }
>>> [k + '=' + v for k, v in d.items()]
['y=B', 'x=A', 'z=C']
15. 生成器
  • 通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
  • 所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
  • 生成器更像是一个“算法”变量,通过它能够边循环边计算下一个取值
#生成器的定义
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x1022ef630>

#可以通过next()函数获得generator的下一个返回值
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4

#使用for循环遍历,因为generator也是可迭代对象
>>> g = (x * x for x in range(10))
>>> for n in g:
...     print(n)

#也可以把generator直接转成list,这样能将所有值全部输出
>>> g = (x * x for x in range(10))
>>> list(g)

#通过函数来定义generator, yield的使用(重点,需要慢慢体会。在asyncio里会经常用到yield。)
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'

>>> f = fib(6)
>>> f
<generator object fib at 0x104feaaa0>

#yield的使用: 函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行
#要理解generator的工作原理,它是在for循环的过程中不断计算出下一个元素,并在适当的条件结束for循环。对于函数改成的generator来说,遇到return语句或者执行到函数体最后一行语句,就是结束generator的指令,for循环随之结束。
#定义
def odd():
    print('step 1')
    yield 1
    print('step 2')
    yield(3)
    print('step 3')
    yield(5)

#使用
>>> o = odd()
>>> next(o)
step 1
1
>>> next(o)
step 2
3
>>> next(o)
step 3
5
>>> next(o)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
16. 迭代器
  • 迭代器一定是可迭代对象,但可迭代对象不一定是迭代器,例如list, tuple, dict, set, str等
  • 可以被next()函数调用并不断返回下一个值的对象称为迭代器,所以generator是迭代器
#判断是否为迭代器
>>> from collections import Iterator
>>> isinstance((x for x in range(10)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abc', Iterator)
False

#将可迭代对象用iter()方法转为迭代器
>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abc'), Iterator)
True

#Python的for循环本质上就是通过不断调用next()函数实现的
for x in [1, 2, 3, 4, 5]:
    pass
#等价于:
# 首先获得Iterator对象:
it = iter([1, 2, 3, 4, 5])
# 循环:
while True:
    try:
        # 获得下一个值:
        x = next(it)
    except StopIteration:
        # 遇到StopIteration就退出循环
        break
17. 高阶函数
  • Python的函数可以接收另一个函数作为参数,这种函数被称为高阶函数
  • Python内置的几个高阶函数,示例
#map函数,对list中每个元素作处理
#返回结果是Iterator
#接受的函数应该是一个单参数的函数
>>> def f(x):
...     return x * x
...
>>> r = map(f, [1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> list(r)
[1, 4, 9, 16, 25, 36, 49, 64, 81]

#reduce函数,把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算
>>> from functools import reduce
>>> def add(x, y):
...     return x + y
...
>>> reduce(add, [1, 3, 5, 7, 9])
25

#filter函数,把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。
#起到过滤list元素的作用
def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
结果: [1, 5, 9, 15]

#sorted函数,将传入的函数依次作用于每个元素后进行排序
#直接排序
>>> sorted([36, 5, -12, 9, -21])
[-21, -12, 5, 9, 36]

#通过接受key函数来自定义排序
>>> sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True)
['Zoo', 'Credit', 'bob', 'about']
18. 返回函数
  • 一个函数的返回值可以是一个函数,这个函数可以理解为一种懒函数,即运算结果不立即返回,而是通过返回的函数再做进一步的获取
  • 当外部函数返回一个内部函数时,相关参数和变量都保存在返回的函数中了,这种称为闭包
#定义一个返回函数的函数
def lazy_sum(*args):
    def sum():
        ax = 0
        for n in args:
            ax = ax + n
        return ax
    return sum

#调用这个函数
>>> f = lazy_sum(1, 3, 5, 7, 9)
>>> f
<function lazy_sum.<locals>.sum at 0x101c6ed90>
>>> f()
25
#
19. 匿名函数(lambda表达式)
#lambda表达式的一般用法,关键字lambda表示匿名函数,冒号前面表示参数,冒号后面表示返回表达式
>>> f = lambda x: x * x
>>> f
<function <lambda> at 0x101c6ef28>
>>> f(5)
25
20. 装饰器(Decorator)
  • 所谓装饰器即在不影响原有功能的前提下对原有函数功能的补充和丰富
  • 在面向对象的设计模式中,decorator被称为装饰模式,是通过继承和组合来实现的。而Python除了能支持OOP的decorator外,直接从语法层面支持了decorator。
  • Python的decorator可以用函数实现,也可以用类来实现。
#给一个函数增强功能的常用做法
#原函数
def now():
    print('2015-3-25')

#定义一个返回函数的高阶函数用于增强功能
#注意返回函数的参数定义很巧妙,可以用来接受任何参数
def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

#常用的调用方法
now = log(now)
>>> now()
call now():
2015-3-25

#Python从语法层面支持的调用方法,有点像java里的注解
@log
def now():
    print('2015-3-25')

>>> now()
call now():
2015-3-25

#如果decorator本身需要传入参数,如下
def log(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator

@log('execute')
def now():
    print('2015-3-25')

>>> now()
execute now():
2015-3-25

#问题:以上看似已经达到了装饰的效果,但有一个小问题。此时经过装饰后,now对象的__name__变成了'wrapper',如何解决呢。
#不需要编写wrapper.__name__ = func.__name__这样的代码,Python内置的functools.wraps就是干这个事的,所以,一个完整的decorator的写法如下
import functools

def log(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)
        return wrapper
    return decorator
21. 偏函数
  • 所谓偏函数即将原函数中的部分参数固定下来,让调用更加简单
#现象及问题:例如int()函数提供了base参数,用于将不同进制的串转为十进制数,用法如下:
>>> int('12345')
12345
>>> int('12345', base=8)
5349
>>> int('12345', 16)
74565

#默认base是10,如果要转换大量的非10进制字符串,如需要大量转换2进制字符串时,每次都要调用int(x,base=2),非常麻烦。想到的一种解决方法:
def int2(x, base=2):
    return int(x, base)

#这样调用就方便多了
>>> int2('1000000')
64
>>> int2('1010101')
85

#Python在语法层面支持生成这样的偏函数
>>> import functools
>>> int2 = functools.partial(int, base=2)
>>> int2('1000000')
64
>>> int2('1010101')
85
22. 模块
  • 一个.py文件就是一个模块
  • 导入模块用import关键字,如import sys
  • 可以只引入模块的部分功能,如from functools import partial
  • 任何模块代码的第一个字符串都被视为模块的文档注释,可以用'''...'''来定义
  • 在模块文件里可以定义__author__等系统变量来完善文档属性
  • 模块中类似__xxx__这样的变量是特殊变量,可以被直接引用,但是有特殊用途,比如上面的__author__,__name__就是特殊变量,hello模块定义的文档注释也可以用特殊变量__doc__访问,我们自己的变量一般不要用这种变量名;
  • 类似_xxx和__xxx这样的函数或变量就是非公开的(private),不应该被直接引用,比如_abc,__abc等;注意,Python没有机制来限制public与private,只能靠大家编程习惯来约束,即_abc, __abc也是可以访问的。

关于Python学习的初级阶段,还会有两个回合的学习:
初级第二回(面向对象),主要讲解Python面向对象的语法及特性,如类、继承与多态、动态生成类等
初级第三回(常用模块与进阶),主要包括IO编程、进程与线程、数据库、Web开发、常用内置模块与第三方模块等

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值