数据结构
# =========base
print('=================base')

name = 'name'
print('hello,忠翁', name)

print('''line1
line2
line3''')

print('hello %s, %.2f ' % ('zw', 1.22222))


# ==========list
print('=================list')

list_1 = [1, 2, 3]
print(list_1[0], list_1[-1])

# -----基本操作
list_1.append(4)
list_1.insert(1, 11)
print(list_1)
list_1.pop()
print(list_1)
list_1.pop(1)
print(list_1)

# ------不同类型
list_1.append('s1')
list_1.append(['a1', 'a2'])
print(list_1)


# ===========tuple
# tuple和list非常类似,但是tuple一旦初始化就不能修改
print('=================tuple')

tuple_1 = (1, 2)
print(tuple_1[0], tuple_1[-1])

# --tuple的陷阱: 
# 1 定义的时候,tuple的元素就必须被确定下来
# 2 只有1个元素时,必须加一个逗号,,来消除歧义;否则只是定义了一个变量
tuple_2 = (1)
print(tuple_2)
tuple_2 = (1,)
print(tuple_2)
# 3 嵌套元素可能可变,其不变指 直接元素的指向不变
tuple_3 = (1, [11, 12], 2)
tuple_3[1][0] = 10
print(tuple_3)


# ===========set
print('=================set')

set_1 = set([1, 1, 2, 2, 3, 3])
print(set_1)
set_1.add(4)
set_1.add(5)
print(set_1)
set_1.remove(1)

# -- set可以做数学意义上的交集、并集等操作
set_2 = set([1, 2, 'a'])
print(set_1 & set_2 )
print(set_1 | set_2)

# =============dic
print('=================dic')

dic_1 = {'k1':1, 'k2':'v2'}
dic_1[3] = 'v3'
dic_1['k4'] = 'v4'
print(dic_1)
print('k1' in dic_1)
print(dic_1.get('k5'))
dic_1.pop('k1')
print(dic_1)



# ===========条件判断
print('=================if else')

age = 20
if age >= 6:
    print('teenager 1')
    print('teenager 2')
elif age >= 18:
    print('adult')
else:
    print('kid')

if age:
    print('not empty')

# -- 非零数值、非空字符串、非空list等,就判断为True,否则为False
list_empty = []
if list_empty:
    print('list not empty')
else:
    print('list empty')


# =============循环
print('=================for while')

# -- for x in ...
for item_list_1 in list_1:
    print(item_list_1)

sum = 0
for integer in range(101):
    sum += integer
print(sum)

# -- while 表达式 
sum = 0
n = 99
while n > 0:
    sum += n
    if sum < 300:
        print('sum[%d] < 300 continue' % sum)
        continue

    if sum > 2000:
        print('sum[%d] > 2000 break' % sum)
        break
    n -= 2
print(sum)

  

函数
# 函数名其实就是指向一个函数对象的引用,完全可以把函数名赋给一个变量,相当于给这个函数起了一个“别名”

my_abs = abs
print(my_abs(-100))


# -----------定义函数 def

def fun_abs(x):
    if x >= 0:
        return x
    else:
        return -x

print(fun_abs(-200))


# ------------空函数 pass

def fun_empty(a):
    pass

def fun_empty_block(a):
    if a > 10:
        print('pass block')
        pass

print(fun_empty(11))
print(fun_empty_block(11))


# -- 参数类型检查

def fun_val_param(x):
    if not isinstance(x, (int, float)):
        raise TypeError("illegal param")
    return -x


# -- 返回多个值

def return_multi(x):
    return x+1, x+2

a1, a2 = return_multi(1)
print(a1, a2)
# - 其实这只是一种假象,Python函数返回的一个tuple
print(return_multi(1))


# -- 默认参数
# - 1 必选参数在前,默认参数在后
# - 2 把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数
# - 3 定义默认参数要牢记一点:默认参数必须指向不变对象!

def fun_default_param(name, age = 0, city = '北京'):
    print('name:', name)
    print('age:', age)
    print('city:', city)

fun_default_param('a0', 10, '河北')
fun_default_param('a1', 30)
fun_default_param('a2')

# - 参数非顺序指定,需给出名称
fun_default_param(age=100, city='保定', name='老子')

# - 默认参数有个最大的坑:默认参数L的值[],在函数定义时已计算好,
# - 调用,L指向的默认值是共享的!!

def fun_big_hole(l = []):
    l.append('end') # - 关键这里把共享的默认参数值改变了
    print(l)
    return l 

list_def_big_hole = [1]
fun_big_hole(list_def_big_hole)
fun_big_hole(list_def_big_hole)

fun_big_hole()
fun_big_hole()


# -- 可变参数:传入的参数的个数是可变的

def calculate(beg , *numbers):
    print('beg', beg)
    sum = 0
    for n in numbers:
        sum += n
    print('sum:', sum)
    return sum

calculate(1, 1, 2, 3)
calculate(1, *[1, 2, 3])

calculate(4, 5)
calculate(*(4, 5))

calculate(1)


# -- 关键字参数
# 可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple
# 而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict

def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)

person('Michael', 30)
person('Bob', 35, city='Beijing')
person('Adam', 45, gender='M', job='Engineer')
dic_person = {'k1':1, 'k2':'v2'}
person('XiaoMing', 10, **dic_person)


# -- 命名关键字参数
# 如果要限制关键字参数的名字,就可以用命名关键字参数
# 如只接收city和job作为关键字参数
# 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数
def person_named(name, age, *, city, job):
    print(name, age, city, job)

# 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
def person_var_named(name, age, *args, city, job):
    print(name, age, args, city, job)

# 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
# 命名关键字参数可以有缺省值, 调用时,可不传入city参数
def person_var_named_default(name, age, *, city='Beijing', job):
    print(name, age, city, job)

person_var_named_default('hao', 10, job = 'jobMe')


# -- 参数组合
# 在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
# 但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

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

args_compose_1(1, 2, 3, 4, 5, kw1 = [1, 1], kw2 = 'kw2')
args_compose_1(1, 2, kw1 = [1, 1], kw2 = 'kw2')

def args_compose_2(b, c=0, *, d, **kw):
    print('b =', b, 'c =', c, 'd =', d, 'kw =', kw)

args_compose_2(1, 2, d = 'hello', kw1 = [1, 1], kw2 = 'kw2')
args_compose_2(1, 2, a = 'a', d = 'd')

  

高级特性
from collections import Iterable

# ========== 切片

# -- 开始索引:结束索引(但不包括)
L = [0, 1, 2, 3, 4, 5]

print(L[0:3])
print(L[:3])

print(L[-1:-2])
print(L[-2:-1])
print(L[-2:])

L2 = L[:]
L2[0] = 10
print(L)
print(L2)

# --tuple也是一种list,唯一区别是tuple不可变。
# tuple也可以用切片操作,只是操作的结果仍是tuple
T = (1, 2, 3, 4)
print(T[:2])

# -- 字符串'xxx'也可以看成是一种list, 每个元素就是一个字符。
# 字符串也可以用切片操作,只是操作结果仍是字符串

S = '123456'
print(S[:3])


# ===========迭代 iterable

# 当我们使用for循环时,只要作用于一个可迭代对象,for循环就可以正常运行,
# 而我们不太关心该对象究竟是list还是其他数据类型。

D = {'a': 1, 'b': 2, 'c': 3}
for key in D:
    print(key)

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

for item in D.items():
    print('item', item, ' key:', item[0], " v:", item[1])

# - 如何判断一个对象是可迭代对象呢?
# - 方法是通过collections模块的Iterable类型判断

print(isinstance(D, Iterable))
print(isinstance('123', Iterable))

# - 如果要对list实现类似Java那样的下标循环怎么办?
# - Python内置的enumerate函数可以把一个list变成索引-元素对,这样就可以在for循环中同时迭代索引和元素本身

print(enumerate(D))
for i, key in enumerate(D):
    print(i, key)


# ==================列表生成式

# -- 生成[1x1, 2x2, 3x3, ..., 10x10]
print( [x * x for x in range(1, 11)])

# -- for循环后面还可以加上if判断
print([x * x for x in range(1, 11) if x % 2 == 0])

# -- 使用两层循环(甚至三层或以上)
print([m + n for m in 'ABC' for n in 'XYZ'])

# -- for循环其实可以同时使用两个甚至多个变量
d = {'x': 'A', 'y': 'B', 'z': 'C' }
print([k+'='+v for k, v in d.items()])


# ===================(数据、逻辑)生成器
# 一边循环一边计算的机制, 生成器内部保存的是逻辑,吐出的是数据/逻辑,有点像发射器

g = (x for x in range(5))
print(g)
print(next(g))
print(next(g))
print('--- in g ')
for n in g:
    print(n)

# 斐波拉契数列(Fibonacci) 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
# 斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易
def fibonacci(index, resList):
    n = 0
    a = 0
    b = 1
    while n < index:
        resList.append(b)
        a, b = b, a + b
        n += 1
fib_res = []
fibonacci(6, fib_res)
print(fib_res)

# - fibonacci逻辑其实非常类似generator
# - 把 fibonacci 函数 变为 generator, 只需要增加yield b就可以了
# - generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。
#   而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,
#   再次执行时从上次返回的yield语句处继续执行。
def fib_generator(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b          # 相当于数据流的源头
        a, b = b, a + b
        n = n + 1
    return 'done'

# - 但是用for循环调用generator时,发现拿不到generator的return语句的返回值。
# 如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中
gen_fib = fib_generator(5)
while True:
    try:
        print(next(gen_fib))
    except StopIteration as e:
        print('return value:', e.value)
        break

  

函数式编程

# ===============函数式编程
# - 公式性质:只要输入是确定的,输出就是确定的
# - 函数可做参数、返回值传递

# - 变量可以指向函数

def fun_1(x):
    print("in fun 1 x:", x)
    return x + 1

def fun_2(x):
    print("in fun 2, x:", x)

var_fun = fun_1
var_fun(1)

# - 函数名也是变量
# 那么函数名是什么呢?函数名其实就是指向函数的变量!
# 对于fun_1()这个函数,完全可以把函数名fun_1看成变量,它指向一个函数!
# 如果把fun_1指向其他对象,会有什么情况发生?

fun_1 = fun_2
fun_1(2)


# -- 高阶函数:参数还有指向函数的变量
def high_fun(x, y, f):
    print("in hight fun :", f(x) + f(y))