数据分析师

您的位置:首页 > 技术干货 > python︱函数、for、if、_name_、迭代器、防范报错、类定义、装饰器

python︱函数、for、if、_name_、迭代器、防范报错、类定义、装饰器

收藏

来源: CDA数据分析师 | 发布时间:2017-07-17 13:01:28

python︱函数、for、if、_name_、迭代器、防范报错、类定义、装饰器

新手入门Python,开始写一些简单函数,慢慢来,加油~
一、函数 +三个内建函数filter,map和reduce + if
1、def/lambda

def myadd(a=1,b=100):
    result = 0
    i = a
    while i <= b:    # 默认值为1+2+3+……+100
        result += i    
        i += 1
    return result

跟R一样都可以用return返回

lambda函数

lambda表达式有什么好处?匿名函数,一般用来给filter,map这样的函数式编程服务,map(lambda x: x*2,[1,2,3,4,5])

或者就是一次性产品。类似于这种即用即扔的产品:(lambda x: x*2)(3)

或者作为回调函数,传递给某些应用,比如消息处理。

2、if

python 中的三元表达式(三目运算符)
这个输出1,但没有什么意义,仅仅是一个例子。
而在python中的格式为

为真时的结果 if 判定条件 else 为假时的结果  

还是上面的例子

1 if 5>3 else 0

3、filter
filter(bool_func,seq):此函数的功能相当于过滤器。调用一个布尔函数bool_func来迭代遍历每个seq中的元素;返回一个使bool_seq返回值为true的元素的序列。
例如:

>>> filter(lambda x : x%2 == 0,[1,2,3,4,5])  
[2, 4]  

filter内建函数的python实现:

def filter(bool_func,seq):  
    filtered_seq = []  
    for eachItem in seq:  
        if bool_func(eachItem):  
            filtered_seq.append(eachItem)  
    return filtered_seq  

4、map
map(func,seq1[,seq2…]):将函数func作用于给定序列的每个元素,并用一个列表来提供返回值;如果func为None,func表现为身份函数,返回一个含有每个序列中元素集合的n个元组的列表。
例如:

>>> map(lambda x : None,[1,2,3,4])  
[None, None, None, None]  
>>> map(lambda x : x * 2,[1,2,3,4])  
[2, 4, 6, 8]  
>>> map(lambda x : x * 2,[1,2,3,4,[5,6,7]])  
[2, 4, 6, 8, [5, 6, 7, 5, 6, 7]]  
>>> map(lambda x : None,[1,2,3,4])  
[None, None, None, None]  

map内建函数的python实现:

>>> def map(func,seq):  
    mapped_seq = []  
    for eachItem in seq:  
        mapped_seq.append(func(eachItem))  
    return mapped_seq  

5、reduce
reduce(func,seq[,init]):func为二元函数,将func作用于seq序列的元素,每次携带一对(先前的结果以及下一个序列的元素),连续的将现有的结果和下一个值作用在获得的随后的结果上,最后减少我们的序列为一个单一的返回值:如果初始值init给定,第一个比较会是init和第一个序列元素而不是序列的头两个元素。
例如:

>>> reduce(lambda x,y : x + y,[1,2,3,4])  
10  
>>> reduce(lambda x,y : x + y,[1,2,3,4],10)  
20  
reduce的python实现:

def reduce(bin_func,seq,initial=None):  
    lseq = list(seq)  
    if initial is None:  
        res = lseq.pop(0)  
    else:  
        res = initial  
    for eachItem in lseq:  
        res = bin_func(res,eachItem)  
    return res  

二、for、while
python中的for比R中的要广泛很多,R中的for (i in 1:3)循环的较多的是数值,python包括数值+文本列表。
1、字母当做循环

for letter in 'Python':     # 第一个实例
   print '当前字母 :', letter

当前字母 : P
当前字母 : y
当前字母 : t
当前字母 : h
当前字母 : o
当前字母 : n

2、列表当做循环

fruits = ['banana', 'apple',  'mango']
for fruit in fruits:        # 第二个实例
   print '当前字母 :', fruit

3、数字当做循环

for num in range(10,20):  # 迭代 10 到 20 之间的数字
   for i in range(2,num): # 根据因子迭代
      if num%i == 0:      # 确定第一个因子
         j=num/i          # 计算第二个因子
         print '%d 等于 %d * %d' % (num,i,j)
         break            # 跳出当前循环
   else:                  # 循环的 else 部分
      print num, '是一个质数'

4、for 中的 _ 下划线的应用
for 中出现了 _ 那么作用跟R里面的repeat一致,有复制的功能。

import numpy as np
l=[("f1",'g1'),("f2","g2")]
h=['go1','go2']

In [17]:{iter:np.zeros(2) for iter,_ in l }
Out[17]: {'f1': array([ 0.,  0.]), 'f2': array([ 0.,  0.])}

In [18]:[{iter:np.zeros(2) for iter,_ in l } for _ in h]
Out[18]:
[{'f1': array([ 0.,  0.]), 'f2': array([ 0.,  0.])},
 {'f1': array([ 0.,  0.]), 'f2': array([ 0.,  0.])}]

比较小白,对python里面的生成器一开始看不懂,不过后来觉得跟R里面的lappy功能很像。
for iter,_ in l 提取了l=[(“f1”,’g1’),(“f2”,”g2”)]两个的第一个数字,屏蔽了第二个g1/g2
然后f1 f2赋值给了前面的函数,函数内容是iter:np.zeros(2),那么就是出现out[17]的结果。
for _ in h,完全就是repeat两次。

5、while - 重复执行
无限循环的时候,可以用ctrl + C结束。
while 语句用于循环执行程序,即在某条件下,循环执行某段程序,以处理需要重复处理的相同任务。其基本形式为:
(1)常规用法:重复执行

#!/usr/bin/python
count = 0
while (count < 9):   
   print 'The count is:', count    count = count + 1
print "Good bye!"

The count is: 0
The count is: 1
The count is: 2
The count is: 3
The count is: 4
The count is: 5
The count is: 6
The count is: 7
The count is: 8
Good bye!
for里面的重复执行,可以用 for _ in np.arrange(10):
(2)continue,break + while
while 语句时还有另外两个重要的命令 continue,break 来跳过循环,continue 用于跳过该次循环,break 则是用于退出循环,此外”判断条件”还可以是个常值,表示循环必定成立,具体用法如下:

# continue 和 break 用法i = 1
while i < 10:      i += 1    if i%2 > 0:     
# 非双数时跳过输出        
continue    print i         
# 输出双数2、4、6、8、10i = 1
while 1:            
# 循环条件为1必定成立   
 print i        
i += 1    
if i > 10:    
 # 当i大于10时跳出循环  
       break
(3)循环使用 else 语句

#!/usr/bin/python
count = 0
while count < 5:   
  print count, " is  less than 5"   count = count + 1
else:   
  print count, " is not less than 5"

>>>
0 is less than 5
1 is less than 5
2 is less than 5
3 is less than 5
4 is less than 5
5 is not less than 5
三、迭代器
两个列表同时迭代
nfc = ["Packers", "49ers"]
afc = ["Ravens", "Patriots"]
for teama, teamb in zip(nfc, afc):
     print teama + " vs. " + teamb
>>> Packers vs. Ravens
>>> 49ers vs. Patriots

带索引的列表迭代

teams = ["Packers", "49ers", "Ravens", "Patriots"]
for index, team in enumerate(teams):
    print index, team
>>> 0 Packers
>>> 1 49ers
>>> 2 Ravens
>>> 3 Patriots

已知一个列表,刷选出偶数列表方法:

numbers = [1,2,3,4,5,6]
even = []
for number in numbers:
    if number%2 == 0:
        even.append(number)
字典推导

teams = ["Packers", "49ers", "Ravens", "Patriots"]
print {key: value for value, key in enumerate(teams)}
>>> {'49ers': 1, 'Ravens': 2, 'Patriots': 3, 'Packers': 0}
和collections库一样,还有一个库叫itertools

from itertools import combinations
teams = ["Packers", "49ers", "Ravens", "Patriots"]
for game in combinations(teams, 2):
    print game
>>> ('Packers', '49ers')
>>> ('Packers', 'Ravens')
>>> ('Packers', 'Patriots')
>>> ('49ers', 'Ravens')
>>> ('49ers', 'Patriots')
>>> ('Ravens', 'Patriots')
四、_name_
    _name_在当前文件中:_name_=_main_
    _name_在别的文件中:_name_=def的名字

_name_是指示当前py文件调用方式的方法。如果它等于”_main_“就表示是直接执行,如果不是,则用来被别的文件调用,这个时候if就为False,那么它就不会执行最外层的代码了。
比如你有个Python文件里面

def XXXX():
#body
print "asdf"

这样的话,就算是别的地方导入这个文件,要调用这个XXXX函数,也会执行print “asdf”,因为他是最外层代码,或者叫做全局代码。但是往往我们希望只有我在执行这个文件的时候才运行一些代码,不是的话(也就是被调用的话)那就不执行这些代码,所以一般改为

def XXXX():
#body
if __name__="__main__":
print "asdf"

延伸:if _name_ == ‘_main_‘:

本python文档,if name == ‘main‘:以下的内容可以执行,
别的python文档, 调用的话,if name == ‘main‘:以下内容不管了。

同时main()的意义是:python 如何判断应该哪个是主执行文件呢?应用场景是在互相调用python内函数的时候。
五、防范报错
1、assert 断言

Python的assert是用来检查一个条件,如果它为真,就不做任何事。如果它为假,则会抛出AssertError并且包含错误信息。例如:

py> x = 23
py> assert x > 0, "x is not zero or negative"
py> assert x%2 == 0, "x is not an even number"
Traceback (most recent call last):
File "", line 1, in
AssertionError: x is not an even number

类似R中的stopifnot

参考博客:Python 中何时使用断言?
.
2、try…except…

try:
    f = open('xxx')
except:
    print 'fail to open'
    exit(-1)
如果try中open不出来,那么就except返回相应的内容“fail to open”
.
3、with…as…

那么with和as也是一种防止报错的防范方式,
当python执行这一句时,会调用enter函数,然后把该函数return的值传给as后指定的变量。
之后,python会执行下面do something的语句块。最后不论在该语句块出现了什么异常,都会在离开时执行exit。

ith open("x.txt") as f:
    data = f.read()

with open("x.txt") as f1, open('xxx.txt') as f2:
    do something with f1,f2

那么try和with也可以合起:

try:
    with open( "a.txt" ) as f :
        do something
except xxxError:
    do something about exception
六、类定义

参考于:Python的hasattr() getattr() setattr() 函数使用方法详解

class <类名>:
    <语句>

类需注意:

    类适合存函数,不用非要return
    在类中定义的函数只有一点不同,就是第一个参数永远是实例变量self,并且,调用时,不用传递该参数。

1、类里面一直存着参数

init存入

class save_def(object):

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

这样save_def里面就会一直存着name、score函数。

initialization = save_def(name,score)

初始化的方式跟函数一样,直接传入。
同时,initialization.name,initialization.score 也相当于initialization的属性。
不过,如果你觉得还需要额外加入一些临时属性的话,可以直接赋值:

initialization.other = "other"
.
2、类里面函数如何调用

类内的参数前面加self.para

class save_def(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def function1(self,dataframe):
    temp_data = type(dataframe[self.name])
    return temp_data

如果类里面包着函数,而且函数里面包着属性,那么可以直接用:

initialization = save_def(name,score)
 initialization.function1(dataframe)

如果是函数的话,则为:

>>>def function1(name,dataframe):
    temp_data = type(dataframe[name])
    return temp_data

>>>function1(name,dataframe)

不同的地方在于类里面,可以直接用类内存着的函数。
.
3、类内函数套函数

类内函数调用类内的函数,前面需要加self.

class save_def(object):
    def __init__(self, name, score):
        self.name = name
        self.score = score

    def function1(self,dataframe):
    temp_data = type(dataframe[self.name])
    return temp_data

    def function2(self):
        temp_data2 = self.function1(dataframe.ix[self.score>10,:])
self.function1就是一种类内调用函数的方式。从这一案例可以看出:
类内调用函数+参数,都需要用self.
.
延伸一:关于如何从调用另一个.py文件中的类

因为,Python里面全局变量所谓的全局是针对在一个文件里面的函数而言的,跨文件就等于定义在不同的包里面,也就相当于是使用了不同的命名空间。(来源:PYTHON全局变量在模块中的无法引用?)
笔者在调用另一个.py文件中的类的时候,发生大面积的报错:

globel name 'xxx' is not defined

无奈只能写在一个文档中。

一般来说,调用的方式有两种:import 和 from…import…:
import datetime
print(datetime.datetime.now())

from datetime import datetime
print(datetime.now())

通俗的说:

from import : 从车里把矿泉水拿出来,给我
import : 把车给我
.
七、装饰器

参考于:深入浅出Python装饰器、Python装饰器学习(九步入门)、Python 的闭包和装饰器

    其中笔者认为,类class适合打包函数,装饰器@适合包装函数,并不是包装参数。 同时,装饰器适合,函数之间有一定递进、级联关系,比较适合。

1、闭包

装饰器相当于升级版的闭包,一个闭包就是你调用了一个函数A,这个函数A返回了一个函数B给你。这个返回的函数B就叫做闭包。你在调用函数A的时候传递的参数就是自由变量。

def func(name):
    def inner_func(age):
        print 'name:', name, 'age:', age
    return inner_func

bb = func('the5fire')
bb(26)  # >>> name: the5fire age: 26

这里面调用func的时候就产生了一个闭包——inner_func,并且该闭包持有自由变量——name,因此这也意味着,当函数func的生命周期结束之后,name这个变量依然存在,因为它被闭包引用了,所以不会被回收。
2、初级装饰器

函数传入、函数传出,装饰器的本质就是函数闭包,或者说利用了函数闭包的特性。

def outer(function):
    def inner():
        print("执行function之前可以进行额外操作")
        result = function()
        print("执行function之后还可以进行额外操作")
        result *= 2        # 对function的返回值本身进行额外操作
        return result      # 返回‘加强’后的结果
    return inner

def wait_for_deco():
    return 1024

decorated = outer(wait_for_deco)
print decorated()
# 输出
2048

上例就是纯手工实现的一个最简单的装饰器。装饰器函数outer并没有修改被装饰函数wait_for_deco,但我们调用被装饰后的decorated函数闭包却能够得到原函数的加强版结果,还能进行额外的操作。

超级简单的案例一则:

def function1(function):
    return function() + 1
# function作为参数传入,且这个参数名称是任意的,跟普通参数一致,需要对齐,函数也要写function

def function2():
    return 2
#这样的装饰器,一般不传入参数

# 使用
>>> function1(function2)
>>> 3
# 其中,不能写成function1(function2())
.
3、带装饰符@-装饰器

实际上装饰符@就仅仅是帮我们自动地把返回的闭包函数名字替换为原函数的名字。

def outer(function):
    def inner():
        print("执行function之前可以进行额外操作")
        result = function()
        print("执行function之后还可以进行额外操作")
        result *= 2        # 对function的返回值本身进行额外操作
        return result      # 返回‘加强’后的结果
    return inner

@outer
def wait_for_deco():
    return 1024

print wait_for_deco()
# 输出
2048
.
4、带参数+装饰符的装饰器

# 例如为下面的函数写一个装饰器,应该在内部的wapper中按原样传递参数
def decorator(func):
    def wrapper(x, y)
      ret = func(x, y)    # 原函数的返回值
      return ret*2        # 原函数的结果“加强”后再返回
    return wrapper

@decorator
def wait_for_deco(x, y):
  return x + y

print(wait_for_deco(1, 2))

# 输出
6
可调节的多参数
按照上面这种写法虽然可以传参了但有个缺陷,参数个数不确定的函数就没法使用这个装饰器了。

def decorator(func):
    def wrapper(*args, **kwargs)
      ret = func(*args, **kwargs)
      return ret*2
    return wrapper

@decorator
def wait_for_deco_a(x, y):
  return x + y

@decorator
def wait_for_deco_b(x, y, z):
  return x + y + z

print(wait_for_deco_a(1, 2))
6
print(wait_for_deco_b(1, 2, 3))
12

超级简单案例一则:

def function2(function):
    # 因为要传入参数,所以下面的def 就相当于在写了一次_function2,但也不是简单的加个def,其中_代表,专属于函数内
    def _function2(b):
        # 并不能写出:function2(function)
        a = function(b)
        return a + 1
    return _function2
# 返回的是函数本身

@function2
def function1(b):
    return b + 1

function2(function1)
.
5、传参数+装饰符@+多选项装饰器
def mydec(is_print):
    def mydec_f(func):
        def mydec_a(*args, **kwargs):
            r = func(*args, **kwargs)
            if is_print:
                print("结果是:{}".format(r))
            else:
                print("不打印结果")
        return mydec_a
    return mydec_f

@mydec(True)
def mysum(a, b):
    c = a + b
    return c
@mydec(False)
def mysum2(a, b, c):
    d = a + b + c
    return d

mysum(1, 2)
mysum2(1, 2, 3)
>>>结果是:3
.
6、传参数+装饰符@+类 装饰器
class mycls():
    def __init__(self):
        print("类初始化了")

    @staticmethod
    def test1():
        print("我是mycls.test1")

    @staticmethod
    def test2():
        print("我是mycls.test2")

# 装饰器
def mydec(cls):
    def mydec_f(func):
        def mydec_a(*args, **kwargs):
            cls.test1()
            r = func(*args, **kwargs)
            print("结果是:{}".format(r))
            cls.test2()
        return mydec_a
    return mydec_f

@mydec(mycls)
def mysum(a, b):
    c = a + b
    return c
@mydec(mycls)
def mysum2(a, b, c):
    d = a + b + c
    return d

mysum(1, 2)
mysum2(1, 2, 3)
结果:

我是mycls.test1
结果是:3
我是mycls.test2
我是mycls.test1
结果是:6
我是mycls.test2

数据分析师 python

  CDA大数据分析圈是国内第一个汇聚大数据全面资源、数据人必备的APP。CDA整合了近千个大数据相关专业网站及媒体来源,汇聚了数百场国内大数据活动与会议,数千名名技术大牛、行业领袖,以及总结了最系统的优质学习课程资源。在这里,你可每天接触到最新行业资讯、前沿技术干货等信息;你可参与CDA俱乐部活动、各类大型会议,亲身与大牛接触,获得实务经验。你也可在专业课堂上与国内顶尖讲师进行交流切磋,最有效规划自身大数据职业发展。
  CDA大数据分析圈是数据人的家园,圈子里,资源流通,共享智慧,合作发展。CDA以“创新、开放、分享”的理念,期待你的加入!

分享到:

CDA数据分析师周边