day15,内置函数一

1,复习,如何从生成器里面取值,next(每次取一个值),send(不可以用在第一个,取下一个的时候,给上一个地方传一个值),for(没有break会一直取,直到取完),强制转换(会一次性把数据加载到内存里面)调用之后,函数内的代码不会执行,不取不干活,返回生成器。所有的生成器都是迭代器。

2,作业一,面向函数编程了,要抽象功能

# 3,处理文件,用户指定要查找的文件和内容,将文件中包含要查找内容的每一行都输出到屏幕
def find_content(filename,content):
    with open(filename,encoding='utf-8') as f:  # 文件句柄,handler,类似一个操作杆,拿到它就可以去操作文件了。以后还会经常遇到,文件操作符,以后可能会叫文件对象
        for line in f:
            if content in line:
                yield line

g_find_content = find_content("employ_list.txt","IT")
for i in g_find_content:
    print(i.strip())

3,作业二,

# 4.写生成器,从文件中读取内容,在每一次读取到的内容之前加上‘***’之后再返回给用户。

def find_content(filename,content):
    with open(filename,encoding='utf-8') as f:
        for line in f:
            if content in line:
                yield '***'+line  # 只有这个地方不一样

g_find_content = find_content("employ_list.txt","IT")
for i in g_find_content:
    print(i.strip())

4,面试题一,

# 1,输出是什么? 原则就是只可以取一次
def demo():
    for i in range(4):
        yield i

g=demo()

g1=(i for i in g)
# def func():
#     for i in g:
#         yield i   # 上面的生成器等价于这个
g2=(i for i in g1)
# g2=(i for i in (i for i in g))  看到上面那样的,就把他写进来,不然容易绕蒙了
#print(list(g))  # 如果我运行了这一句,那后面的两个打印就都为空了
print(list(g1))  # 如果我运行了这一个强转,就代表者g1已经取过一次了,一个生成器只可以取一次的,所以下面的那一句就取不到g1了
print(list(g2))  # 如果前面两个打印都没有执行,这里才会有[1,2,3,4]打印出来

运行结果:
[0, 1, 2, 3]
[]

5,面试题二,但凡遇到表达式套生成器的这种就把他拆开,不拆就是晕

# 2,输出是什么?
def add(n,i):
    return n+i

def test():
    for i in range(4):
        yield i

g=test()

for n in [1,10]:
    g=(add(n,i) for i in g)
print(list(g))
 
# 前面的生成器套生成器比较浮躁,首先给他拆成下面这样,再来分析   
# n = 1
# g=(add(n,i) for i in test())
#
# n = 10
# g=(add(n,i) for i in (add(n,i) for i in test()))
# 20,21,22,23         10,11,12,13     0,1,2,3
# 生成器只能去一次,n=1 的时候并没有实际运行,是到了这里才实际运行的,而到了这儿n已经等于10了,不能拿1来算了


运行结果:
[20, 21, 22, 23]

6,内置函数,就是Python解释器一启动就有的函数,一打开就可以用的函数,截止到3.6.2,一共有68个内置函数,能够直接加括号调用,并且不用提前定义的都是内置函数

7,作用域相关的两个,globals(),locals()

# 内置函数,用的不多
print(locals())  #返回本地作用域中的所有名字
print(globals())  # 返回全局作用域中的所有名字

# 关键字,用于声明,和for is一样是关键字,用的多
global  变量 # 声明变量
nonlocal 变量 #内层函数用外层函数变量,用域函数内部,和变量的实际作用域相关

8,和迭代器生成器相关的3个range,iter,next,python里面一切都是对象,双下的用起来比较麻烦,

# 之前讲过迭代器里面有双下函数__next__和__iter__
# 但是双下函数我们一般不会直接调用
# 迭代器.__next__  我们不会这样调用
# 怎么调用呢?
# next(迭代器) 其实内部还是代用的双下方法

# 注意一点:
# __next__属于迭代器的方法
# next()内置函数

def next(迭代器):
    迭代器.__next__()

[].__len__()
len([])

迭代器 = iter(可迭代的)
迭代器 = 可迭代的.__iter__
python里面一切都是对象,可迭代的就是可迭代对象

9,再说range

# 可切片,但是不是用冒号
range(10)
range(1,11)
range(1,11,2)

print('__next__' in dir(range(10)))   # False range结果是一个可迭代对象
print('__next__' in dir(iter(range(10))))# True 被iter函数转化,也就是调用了双下iter方法之后就是迭代器了

10,其他类型12个,首先看dir()函数,查看一个变量拥有的方法

# 返回的是一个列表
print(dir([]))
print(dir(1))

11,callable(),查看一个变量是否可以用括号调用,是否是可调用的,函数名,列表名,字典名,其实都是变量,只能查变量,看一下是值还是函数,一般就是检测是否是函数,还有其他可调用的,目前没学

print(callable(print))  # True
a = 1
print(callable(a))  # false
def func():pass
print(callable(func)) # True

print(callable(globals)) # True

12,help() 查看帮助信息,没有返回值,help函数就是直接打印,返回所有方法,和dir 是差不多的,给的更详细一些,当对一个变量或者是数据类型不了解的时候,可以拿来查看一下,封闭开发的时候,看help很给用。

help(str)  #返回所有有的帮助文档,函数介绍,怎么用等等
help(func)

13,import方法,其实也是调用的__import__方法,导入模块,某个方法属于某个数据类型的变量,就用点调用,如果某个方法不依赖于任何数据类型,就直接调用,这就是内置函数和自定义的函数

import os   # import 是一个关键字,不依赖于任何数据类型
__import__('os') # 这个双下方法是不依赖于任何的数据类型的,__iter__这个是依赖于可迭代对象的

14,列表句柄,虽然我们一般不这样说,但是他确实就像是一个操作杆, 拿着他就可以操作列表了

l = [1,2,3,4]
l.append(5) # 列表句柄

15,open 打开文件,之前用的比较多,这里不再多说了

with open("file.txt",encoding='utf-8') as f:
    print(f.writable()) # 是否可读
    print(f.readable()) # 是否可写

运行结果:
False
True

16,id 函数 查看内存地址,代表一个变量他所在的内存地址,不再写例子,比较简单

17,hash函数,计算哈希值,可哈希就是不可变数据类型,包括int,bool,float,str和tuple,对于相同可哈希数据类型的哈希值,在一次程序运行中的哈希值是不会变的,但是在下一次运行时的哈希值是会变的,只是在一次程序运行内的值是不会变的,哈希其实也是和内存相关的,可不可哈希其实就是能不能执行这个哈希函数,哈希和ID这两个函数其实用的都不多的。

import time
while True:
    time.sleep(1)
    print(hash(1))  # int类型的哈希值还是自己
    print(hash(1.23))
    print(hash(True)) # bool类型的哈希值还是自己
    print(hash('sss'))
    print(hash((1,)))
    print('***************************')

运行结果:
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
1
530343892119149569
1
8413743691931804847
3430019387558
***************************
print(hash([]))

运行结果:
Traceback (most recent call last):
  File "/Users/guolixiao/PycharmProjects/lisa's_practise/boys/part one/15.4_内置函数其他.py", line 50, in <module>
    print(hash([]))
TypeError: unhashable type: 'list'
print(hash('sss'))
print(hash('sss'))
print(hash('sss'))

第一次运行结果:
-4352255816779243253
-4352255816779243253
-4352255816779243253

第二次运行结果:
2236786100360963608
2236786100360963608
2236786100360963608

第三次运行结果:
8099329436765032024
8099329436765032024
8099329436765032024

18,相对于字典的查找,非常的快速,只要一次查找就可以的,为何呢,因为字典的value直接存储在key所对应的哈希值代表的内存中,也就是哈希值就是他的内存地址,直接到这个内存地址去取值就可以。这也是key必须可哈希的原因了,我们一般都是循环key来找value,因为,value都比较大,比方说视频,循环起来很可怕的,包括后面的数据库也有很多快速的取值的方法,有些通过哈希,有些不通过哈希,这个会到后面再来讲

19,print函数,end sep 都比较熟悉了,另外有一个file=None

f = open("file.txt", 'r+',encoding='utf-8')
print(hash('sss'),file=None)  # None得话代表输入到下面的屏幕
print(hash('sss'),file=f) #代表输入到文件,这一句打印到了file.txt中
f.close()

20,一个简单的打印进度条的函数,其实Python有提供一个专门的打印进度条的模块,叫做progress bar,需要单独下载安装,有兴趣可以去研究一下。

# 自己的版本
import time
for i in range(0,101,2):
    time.sleep(0.1)   # 不sleep的话,打印的太快看不到进度,直接就100了
    print('
%s%%   ' % i,end='') #
是回到行首不换行的意思
    print('*'*i,end='')
print()  # 为了下一次输入时在新的一行,所以这儿多加了一行打印

# 老师的版本
import time
for i in range(0,101,2):
     time.sleep(0.1)
     char_num = i//2
     per_str = '
%s%% : %s
' % (i, '*' * char_num) 
         if i == 100 else '
%s%% : %s' % (i,'*'*char_num)
     print(per_str,end='', flush=True) # flush立刻把文件输出到文件流,不做缓存
运行结果:
100%   ****************************************************************************************************

21,input函数,返回都是字符串,交互用的,不再展开写

22,exec,eval和compile,字符串类型代码的执行,先说exec吧:

'print(123)' #这就是一个字符串,里面的代码不会去执行
# 但是如果这样的话
exec('print(123)') # 就可以正常输出123
eval('print(123)') # 也可以输出123

# 乍一看,貌似一样
运行结果:
123
123

其实呢?
print(exec('1+2+3+4'))
print(eval('1+2+3+4'))

运行结果:
None
10

23,结论:exec和eval都可以执行字符串类型的代码,但是eval有返回值,exec没有,eval只能用在你明确知道你要执行的代码是什么的并且用eval代码确实会变简单,但是不能因为简单就忽略了安全,exec是简单的流程控制,eval有结果的简单计算

另外非常重要的是eval一般情况下不要用,但是eval也有用它会非常好的地方,为什么一般不让用呢,比方说文件里面写的,和用户输入的字符串。文件里面的代码很不安全的,比方说一个黑客攻击了你的电脑,改了这个文件,那么整个程序就都崩塌了。容易攻陷账号密码,公司里的代码不不能随便用eval去读的,用户输入更不安全了,因为不是所有的用户都是良性用户的,一定有一写用户在攻击你网站,想办法获取你的数据,那如果这个地方留了口子,这种不安全的代码,肯定会出问题的,所以不要执行用户输入的代码,或者从文件里面读,只能去执行写死了的,因为这样会简单很多

code = '''
for i in range(5):  
    print(i*'*')   
'''
exec(code)
# eval(code)   # 不可以用eval,只可以用exec来运行

运行结果:
*
**
***
****

24,compile函数,当只是简单的表达式的时候,用eval,当为流程语句的时候用exec,当需要交互的时候,需要用到single,compile用的不多,将字符串代码进行编译,然后通过exec或者eval来执行,代码对象能够通过exec来执行或者eval来求值,好,问题是exec和eval自己就可以执行字符串,为何还需要提前编译呢?答案是,计算机其实不认识我们自己写的这些代码的,他要先经过一次翻译,把你写的这些代码翻译成字节码,再去执行,但是如果对于同一段code,比如说500行,我要运行5次,如果编译五次的话,很浪费时间的,如果有个方法可以编译一次,多次执行,那就好了,这个方法就是compile,他就是把我们自己写的代码,翻译成字节码保存。他只管翻译,具体执行还得exec和eval

# 注意即使是字符串中的代码,也要注意缩进
code = '''
for i in range(5):  
    print(i*'*')   
'''

compile1 = compile(code,'','exec')
# 这个空串代表不是从文件里面读,如果从文件里面写一个文件名,但是出于安全我们不从文件读
# 'exec'必须传递字符串,
# 编译成exec模式的方式
print(type(compile1))
print(compile1)
exec(compile1)
code = '1+2+3+4'
compile1 = compile(code,'','eval')
# 编译成eval模式的方式
print(type(compile1))
print(compile1)
eval(compile1)

25,single 方式,交互式的字符串,了解一下有这么一种神奇的功能就行了,用的不多

code = 'name = input(">>>")'
compile1 = compile(code,'','single')
# 编译成eval模式的方式

print(name)
#pycharm 有时候会骗你的,这个地方pycharm感知不到字符串里面的name,会报错的,但实际上程序是没有问题的,会正常执行

运行结果:
>>>lisa
lisa

26,至此其他学完了,下面学习,基础数据类型的数字相关的14个,complex知道有这个数据类型就行了,不要深究

27,数据类型,int,float,bool,浮点数float,这在数据类型强制转换的时候使用

# 由于这个才叫浮点数的
# 341.23 =3.4123 * 10**2
# 341.23 = 34.123 *10
# 当浮点数位数足够长的时候,计算机转化成二进制的时候会出现微若的偏差,也就是最后面几位的数字可能不准确
# 就是没有办法完全转换准确,所有语言都一样,可以解决,但是我们一般不会用到这么长的小数的
i = 1.2345674677677443230987
print(i)

28,进制转换,bin,oct,hex

# 稍微了解下就行,用的也不多
print(oct(10))  # 转换成八进制,0o
print(hex(10))  # 转化成十六进制,0x
print(bin(10))  # 转化成二进制,0b

运行结果:
0o12
0xa
0b1010

29,数学运算

print(abs(-3))  # 结果3
print(divmod(8,3)) # 除余 (2, 2)
print(divmod(9,2)) # 除余 (4, 1)  在做分页的时候这个方法是真有用
print(round(3.1415926,3)) # 3.241 小数的精确,会四舍五入的
print(pow(3,3))# 27 求幂运算的
print(pow(2,3,3)) # 2 求幂运算,针对第三个数取余数,用的不多,幂运算和取余在一起
print(pow(3,2,4)) # 1

30,sum函数,这儿有问题,因为command+B进去以后,看到的是参数是*args,但是实际上是只可以接收两个参数的,老师说以前看到的参数是iterable,不晓得

# sum 求和,接收两个参数,接收一个可迭代对象
ret = sum([1,2,3,4,5])
print(ret)
# ret = sum(1,2,3,4,5)  # 
# start参数,不允许按照关键字传参,只能按照位置传
# 正产从零开始加,这个是从10开始加
ret = sum([1,2,3,4,5],10)
print(ret)

运算结果:
15
25

31,min,max 函数

# min 比sum 好的地方因为它既可以接收iterable也可以接收*args
# 我可以给一个key值,也就是一个方法名,先按照方法名来运算,再比较结果
print(min([1,2,3,4]))
print(min(1,2,-3,4,key=abs))
print(min({1,2,3,-4}, key=abs))

print(max([1,2,3,4]))
print(max(1,2,-3,4,key=abs))
print(max({1,2,3,-4}, key=abs))  #最终给出的还是列表中的数

运算结果:
1
1
1
4
4
-4

32,试题一

print(3>2==2)
print(3>2 and 2==2)
# 这两句效果是一样的

33,

# 大写A的ASCII码是65
# 小写a的ASCII码是97

34,字符串比较以首字母为准,元祖不能比较大小

35,5/2 python3结果2.5 python2 向下取整为2

36,只要是for循环就不会无限循环

37,删除一个列表里面重复的元素,转换为set是不完美的,因为变成无序了。所以我们可以建一个新的list来储存不重复的,保持原来顺序。

原文地址:https://www.cnblogs.com/lisa-blog/p/10092884.html