Python学习笔记(一)

文章目录

  • 1. 基础
  • 2. 类型
    • 2.1. 有序集合list和tuple
    • 2.2. dict和set
  • 3. 函数
    • 3.1. 闭包
    • 3.2. 匿名函数
    • 3.3. 装饰器
    • 3.4. 偏函数
  • 4. 生成器generator
  • 6. 其他:
    • 6.1. map/reduce/filter/sort
    • 6.2. 模块

供个人学习笔记回顾时使用.

1. 基础

  1. print()输出 input()输入
    r'xxx' xxx字符不需要转义
    '''xxx''' xxx中间字符支持跨行

  2. 由于Python的字符串类型是str,在内存中以Unicode表示,一个字符对应若干个字节。如果要在网络上传输,或者保存到磁盘上,就需要把str变为以字节为单位的bytes。
    Python对bytes类型的数据用带b前缀的单引号或双引号表示:

    	x = b'ABC'
    

    以Unicode表示的str通过encode()方法可以编码为指定的bytes,例如:
    反过来,如果我们从网络或磁盘上读取了字节流,那么读到的数据就是bytes。要把bytes变为str,就需要用decode()方法:
    len()函数计算的是str的字符数,如果换成bytes,len()函数就计算字节数:

    	'中文'.encode('utf-8')
    	b'ABC'.decode('ascii')
    
    	# 如果bytes中只有一小部分无效的字节,可以传入errors='ignore'忽略错误的字节:
    	b'\xe4\xb8\xad\xff'.decode('utf-8', errors='ignore')
    
    	len('中文'.encode('utf-8'))
    	# 6
    
  3. 模板字符串%

    	print('Hi, %s, you have $%d.' % ('你好', 1000000))
    
    	# format函数也可以
    	'Hello, {0}, 成绩提升了 {1:.1f}%'.format('小明', 17.125)
    	# 'Hello, 小明, 成绩提升了 17.1%'
    

    %d, %s, %f, %x - 十六进制, 其余和C语言一样
    %s会自动把数字也转换成字符串, 模板字符串里面如果想表达%的话就写%%

  4. 循环不用多说了, 一个样, forin, while, 记得最后加个:

    	names = ['Michael', 'Bob', 'Tracy']
    	for name in names:
    	    print(name)
    
    	n = 1
    	while n <= 100:
    	    print(n)
    	    n = n + 1
    	print('END')
    
    	# 判断一个对象是可迭代对象
    	from collections import Iterable
    	isinstance('abc', Iterable) #true
    
    	# 获取数组下标
    	for i, value in enumerate(['A', 'B', 'C']):
    	    print(i, value)
    
    	# 循环 + range高级用法1
    	list(range(1, 11))
    	# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    	# 循环 + range高级用法2
    	[x * x for x in range(1, 11)]
    	# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
    	# 循环 + range高级用法3
    	[x * x for x in range(1, 11) if x % 2 == 0]
    	# [4, 16, 36, 64, 100]
    	# 双层循环 + range
    	[m + n for m in 'ABC' for n in 'XYZ']
    	# ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ']
    
  5. 条件判断, 这个稍有不同, 为ifxxx elifxxx

2. 类型

2.1. 有序集合list和tuple

list

classmates = ['Michael', 'Bob', 'Tracy']

# list是一个可变的有序表,所以,可以往list中追加元素到末尾:
classmates.append('Adam')
['Michael', 'Bob', 'Tracy', 'Adam']

# 把元素插入到指定的位置,比如索引号为1的位置:
classmates.insert(1, 'Jack')
['Michael', 'Jack', 'Bob', 'Tracy', 'Adam']

# 要删除list末尾的元素,用pop()方法:
classmates.pop()
['Michael', 'Jack', 'Bob', 'Tracy']

# 删除指定位置的元素,用pop(i)方法,其中i是索引位置:
classmates.pop(1)
['Michael', 'Bob', 'Tracy']

# 切片, 类似JS中的Slice, 如果第一个索引是0, 还可以简写classmates [:2]
classmates [0:2]
['Michael', 'Bob']
# -1就是最后一位
classmates [-1]
['Tracy']

# 切片的高级用法
# 先创建一个数字比较多的list 从0-99的变量L
L = list(range(100))
# 前10个数,每两个取一个:
L[:10:2]
[0, 2, 4, 6, 8]
# 所有数,每5个取一个:
L[::5]
[0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95]
# 只写[:]就可以原样复制一个list:
L[:]
[0, 1, 2, 3, ..., 99]

不可变tuple

#tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改.
classmates = ('Michael', 'Bob', 'Tracy')

2.2. dict和set

dict和js里面的Map差不多, 就是key-value, 不过有点不同的是, 不能用list和dict作为key, 这点有点不是很清楚, 不是拿地址做的key吗?

# 写法也和JS里面的对象一样
d = {'Michael': 95, 'Bob': 75, 'Tracy': 85}
d['Michael']

# in操作符, 判断一个key是否是在一个dict当中
'Thomas' in d

# dict提供的get()方法,如果key不存在,可以返回None,或者自己指定的value
d.get('Thomas', -1)

# 要删除一个key,用pop(key)方法,对应的value也会从dict中删除:
d.pop('Bob')

set和js里面的set就更像了, 数组去重

s = set([1, 2, 3, 3])
# 1, 2, 3

# 添加元素
s.add(4)
# 删除
s.remove(4)

3. 函数

函数def是关键词, 也不需要大括号, 直接缩进搞定

  def my_abs(x):
    # 判断类型
      if not isinstance(x, (int, float)):
          raise TypeError('bad operand type')
      if x >= 0:
          return x
      else:
          return -x
          
      
      # 如果要返回多个值可以直接, return x, y, z  这个实际上是个tuple
      # 外部调用者: x, y, z = 返回多个值的函数()    即可

默认参数和Js一样, 例子如下:

  def add_end(L=[]):
      L.append('END')
      return L

这里有一点需要注意, Python函数在定义的时候,默认参数L的值就被计算出来了,即[].
因为默认参数L也是一个变量,它指向对象[].
每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

  def add_end(L=None):
      if L is None:
          L = []
      L.append('END')
      return L

可变参数, 类似于JS中arguments的功能.

	# 调用方法: calc(1, 2, 3) 或者 nums = [1, 2, 3]  calc(*nums)
	def calc(*numbers):
	    sum = 0
	    for n in numbers:
	        sum = sum + n * n
	    return sum

关键字参数, 传对象, python叫dict

	# 调用方法1: person('Adam', 45, gender='M', job='Engineer')
	# name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}
	
	# 调用方法2:
	# extra = {'city': 'Beijing', 'job': 'Engineer'}
	# person('Jack', 24, **extra)
	def person(name, age, **kw):
	    print('name:', name, 'age:', age, 'other:', 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='aaa', job='Engineer')

参数组合: 参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数.

:
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}

>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}

3.1. 闭包

和js差不多, 下面是个错误例子:

def count():
    fs = []
    for i in range(1, 4):
        def f():
             return i*i
        fs.append(f)
    return fs

f1, f2, f3 = count()
# f1, f2, f3都是3

解决方案和js的方法一样, 这里先回顾一下js解决闭包的方法:

  1. 使用let关键字, 每个闭包都绑定块级作用域
  2. 匿名立即执行函数
  3. 函数工厂, 闭包套闭包

py这里使用方案三就可以解决

def count():
    def f(j):
        def g():
            return j*j
        return g
    fs = []
    for i in range(1, 4):
        fs.append(f(i))  # f(i)立刻被执行,因此i的当前值被传入f()
    return fs

f1, f2, f3 = count()

print(f1(), f2(), f3())
# 1 4 9

这里有个小tips, 如果一个函数里想要引用全局或者上个作用域的变量, 需要增加关键字

global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)

# 例子
def createCounter():
  num = 0
  def counter():
    nonlocal num
    num = num + 1;
    return num
  return counter

3.2. 匿名函数

py需要关键字来声明, 例:

# 匿名函数
lambda x: x * x

# 实际函数
def f(x):
    return x * x

3.3. 装饰器

和js没啥区别, 下面是个例子

import functools

def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper

@log()
def now():
    print('1111')

# now = log(now)

>>> now()
# call now():
# 1111

也可以三层

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

@log('liu')
def now():
    print('1111')

# now = log('execute')(now)

>>> now()
# liu now():
# 1111

3.4. 偏函数

这个感觉是一种编程思想, 函数默认一些参数的快捷键, 没什么难度

当函数的参数个数太多,需要简化时,使用functools.partial可以创建一个新的函数,这个新函数可以固定住原函数的部分参数,从而在调用时更简单。

def int2(x, base=2):
    return int(x, base)

等同于

import functools
int2 = functools.partial(int, base=2)
max2 = functools.partial(max, 10)
max2(5, 6, 7)

等用于

args = (10, 5, 6, 7)
max(*args)

4. 生成器generator

和JS版本的generator差不多. 语法主要是yield和next

	# 创建一个generate, 只要把一个列表生成式的[]改成()
	g = (x * x for x in range(10))

	# 例子: 计算斐波拉契数列
	def fib(max):
     n, a, b = 0, 0, 1
     while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
     return 'done'

	# 调用方法1:
	result = fib(5)
	result.next()
	# 调用方法2:
	for n in fib(6):
        print(n)

	# 获取generate函数的return值
	g = fib(6)
	while True:
	     try:
	         x = next(g)
	         print('g:', x)
	     except StopIteration as e:
	         print('Generator return value:', e.value)
	         break

6. 其他:

6.1. map/reduce/filter/sort

和Js的用法一毛一样:

map()函数接收两个参数,一个是函数,一个是Iterable

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()函数需要额引入, 一个参数的这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算.

from functools import reduce
def add(x, y):
  return x + y

r = reduce(add, [1, 3, 5, 7, 9])
print(r)
# 25

filter()和上面两个函数传参都一样

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函数传参和上面这三个有点不同
第一个参数是数组, 第二个参数用来操纵数据里的每一项, 第三个参数是否倒排

L = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]

def by_name(t):
  return t[1]
 
L2 = sorted(L, key=by_name, reverse = True)
print(L2)
# [('Adam', 92), ('Lisa', 88), ('Bob', 75), ('Bart', 66)]

6.2. 模块

模块使用方式和js有不同的地方.

  1. 导入时, 不需要文件路径
  2. 不需要手动声明需要导出的函数或者变量, py全都导出, 也一样没有私有成员的概念

定义一个模块
第1行和第2行是标准注释,第1行注释可以让这个hello.py文件直接在Unix/Linux/Mac上运行,第2行注释表示.py文件本身使用标准UTF-8编码;
第4行是一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;
第6行使用__author__变量把作者写进去,这样当你公开源代码后别人就可以瞻仰你的大名;
当我们在命令行运行hello模块文件时,Python解释器把一个特殊变量__name__置为__main__,而如果在其他地方导入该hello模块时,if判断将失败,因此,这种if测试可以让一个模块通过命令行运行时执行一些额外的代码,最常见的就是运行测试。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

' a test module '

__author__ = 'asd'

import sys

def test():
    args = sys.argv
    if len(args)==1:
        print('Hello, world!')
    elif len(args)==2:
        print('Hello, %s!' % args[1])
    else:
        print('Too many arguments!')

if __name__=='__main__':
    test()

a = 1
_a = 2

使用模块

import hello

hello.test() # Hello, world!
print(hello.a) # 1
print(hello._a) # 2

py模块搜索规则
默认情况下,Python解释器会搜索当前目录、所有已安装的内置模块和第三方模块,搜索路径存放在sys模块的path变量中:

import sys
print(sys.path)

如果我们要添加自己的搜索目录,有两种方法:
一是直接修改sys.path,添加要搜索的目录, 这种方法是在运行时修改,运行结束后失效。

import sys
sys.path.append('/Users/michael/my_py_scripts')
print(sys.path)

第二种方法是设置环境变量PYTHONPATH,该环境变量的内容会被自动添加到模块搜索路径中。设置方式与设置Path环境变量类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。

如果一个文件夹下都是模块, 需要使用一个文件来声明这是个模块目录

mycompany
├─ __ init __.py
├─ abc.py
└─ xyz.py

如果想调用abc模块,则: mycompany.abc
init文件里是mycompany模块的代码


字数太多, 有点卡了… 新开一个博客

reference links:

  1. https://www.liaoxuefeng.com/wiki/1016959663602400/1017493741106496

你可能感兴趣的:(Python)