鱼C论坛

 找回密码
 立即注册
楼主: lightninng

[技术交流] [记录贴]每天的问题和解决方法_正确学习方法

[复制链接]
发表于 2015-6-13 17:33:31 | 显示全部楼层
lightninng 发表于 2015-6-12 22:49
其实都是论坛或者checkio里面的一些小游戏 ,由简入繁,你也可以试试,由其是checkio这个,挺有趣的,我 ...

那你实在是太牛了,我要好好拜读一下才行~:lol:
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-13 18:00:40 | 显示全部楼层
本帖最后由 昨、夜星辰 于 2015-6-13 18:02 编辑

这网站真的很不错,居然还支持中文,是学习和巩固基础的好网站~就是慢了点~不知道是不是我的网络慢~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-13 21:27:58 | 显示全部楼层
昨、夜星辰 发表于 2015-6-13 18:00
这网站真的很不错,居然还支持中文,是学习和巩固基础的好网站~就是慢了点~不知道是不是我的网络慢~

加油~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-13 22:23:56 | 显示全部楼层
[python cookbook]
问题:你有一个数据序列,想利用一些规则从中提取出需要的值或者是缩短序列
解决:使用列表推导生成器表达式

先看看列表推导:
>>> mylist = [1, 4, -5, 10, -7, 2, 3, -1]
>>> [n for n in mylist if n > 0]
[1, 4, 10, 2, 3]
>>> [n for n in mylist if n < 0]
[-5, -7, -1]
PS:相信稍微学习了一些python的鱼油对于列表推导都不陌生,这是很有python特色的一个工具,但是有一个问题,当列表很大时,我们使用列表推导会占用大量的内存,这个时候如果能有生成式就好,生成式每次用到下一个对象时即时计算而不提前计算好放在内存中,看下面的例子
>>> pos = (n for n in mylist if n > 0)
>>> pos
<generator object <genexpr> at 0x1006a0eb0>
PS:可以看到这里的pos是一个生成式,原来直接把方括号变成圆括号就可以得到生成式,这也是我看这节所学到的
另外,当遇到更复杂的情况时,你需要使用filter函数
values = ['1', '2', '-3', '-', '4', 'N/A', '5']
def is_int(val):
    try:
        x = int(val)
        return True
    except ValueError:
        return False
ivals = list(filter(is_int, values))
print(ivals)
输出是这样的
>>> 
['1', '2', '-3', '4', '5']
另外 一个需要注意的是itertools模块中的compress函数(PS:吐槽一下,itertools里面的东西还真是好用啊),它以一个 iterable 对象和一个相对应的Boolean选择器序列作为输入参数。 然后输出 iterable 对象中对应选择器为True的元素。 当你需要用另外一个相关联的序列来过滤某个序列的时候,这个函数是非常有用的。比如下面的例子中想将那些对应count值大于5的地址全部输出
addresses = [
    '5412 N CLARK',
    '5148 N CLARK',
    '5800 E 58TH',
    '2122 N CLARK'
    '5645 N RAVENSWOOD',
    '1060 W ADDISON',
    '4801 N BROADWAY',
    '1039 W GRANVILLE',
]
counts = [ 0, 3, 10, 4, 1, 7, 6, 1]
我们这样做
>>> from itertools import compress
>>> more5 = [n > 5 for n in counts]
>>> more5
[False, False, True, False, False, True, True, False]
>>> list(compress(addresses, more5))
['5800 E 58TH', '4801 N BROADWAY', '1039 W GRANVILLE']
>>>
其实用filter函数重新定义一个函数也可以做到,不过这样做似乎更直观一些(PS:compress是压缩的意思,函数名起的真好啊)
最后,列表推导还有这样的用法
>>> clip_neg = [n if n > 0 else 0 for n in mylist]
>>> clip_neg
[1, 4, 0, 10, 0, 2, 3, 0]
>>> clip_pos = [n if n < 0 else 0 for n in mylist]
>>> clip_pos
[0, 0, -5, 0, -7, 0, 0, -1]
>>>
这其实是列表推导 和条件赋值组合使用的结果,条件赋值比如:
>>> a = 10
>>> b = 1 if a < 5 else 2
>>> print(b)
2
>>> a = 3
>>> c = 1 if a < 5 else 2
>>> c
1
上面的例子根据a的大小是否小于5来决定b和c的赋值~~




想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-14 21:44:22 | 显示全部楼层
[python cookbook]
问题:你想构造一个字典,它是另外一个字典的子集。
解决:使用字典推导
PS:是的,你没有看错是字典推导,至少对于我来说是个新名词,只知道有列表推导,没想到字典也可以推导,来看例子
prices = {
    'ACME': 45.23,
    'AAPL': 612.78,
    'IBM': 205.55,
    'HPQ': 37.20,
    'FB': 10.75
}
# Make a dictionary of all prices over 200
p1 = {key: value for key, value in prices.items() if value > 200}
# Make a dictionary of tech stocks
tech_names = {'AAPL', 'IBM', 'HPQ', 'MSFT'}
p2 = {key: value for key, value in prices.items() if key in tech_names}
print(p1)
print(p2)
输出如下
>>> ================================ RESTART ================================
>>> 
{'AAPL': 612.78, 'IBM': 205.55}
{'AAPL': 612.78, 'HPQ': 37.2, 'IBM': 205.55}
有些鱼油可能会想到,用键值对的元组做列表推导,然后将得到的列表作为字典创建时的传入参数可以达到同样的效果,如下面这样
p1 = dict((key, value) for key, value in prices.items() if value > 200)
那么两者的比较:1、字典推导更清晰,可读性好2、字典推导效率高(略高)
PS:关于效率上次了做lambda表达试和itemgetter,这次也来比一下
from time import clock
prices = {
'ACME': 45.23,
'AAPL': 612.78,
'IBM': 205.55,
'HPQ': 37.20,
'FB': 10.75
}
# Make a dictionary of all prices over 200

clock_1 = clock()
for i in range(1000000):
    p1 = {key: value for key, value in prices.items() if value > 200}
clock_2 = clock() 
for i in range(1000000):
    p1 = dict((key, value) for key, value in prices.items() if value > 200)
clock_3 = clock()
print(clock_2-clock_1)
print(clock_3-clock_2)
结果是这样的
>>> ================================ RESTART ================================
>>> 
1.1705024886121698
1.889318179922907
可以看出效率还是差不少的,至少比上次做的效果要明显

有时候完成同一件事会有多种方式。比如,第二个例子程序也可以像这样重写:
# Make a dictionary of tech stocks
tech_names = { 'AAPL', 'IBM', 'HPQ', 'MSFT' }
p2 = { key:prices[key] for key in prices.keys() & tech_names }
但是,运行时间测试结果显示这种方案大概比第一种方案慢1.6倍。 如果对程序运行性能要求比较高的话,需要花点时间去做计时测试。PS:这个我没有测试,有兴趣的鱼油可以试一下~~

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-14 21:58:02 | 显示全部楼层
楼主,我发现后面好多都是英文了~囧~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-14 22:25:44 | 显示全部楼层
昨、夜星辰 发表于 2015-6-14 21:58
楼主,我发现后面好多都是英文了~囧~

每道题 都会给你一个example就是例子,会告诉你什么输入会得到什么输出
然后用百度翻译+example基本都能明白是怎么回事,实在看不懂的就略过~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-6-14 23:08:02 | 显示全部楼层
lightninng 发表于 2015-6-14 22:25
每道题 都会给你一个example就是例子,会告诉你什么输入会得到什么输出
然后用百度翻译+example基本都能 ...

嗯,有些题目我是靠看例子来做的,英文太烂了,机器翻译又乱七八糟的,囧~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-15 22:27:17 | 显示全部楼层
昨、夜星辰 发表于 2015-6-14 23:08
嗯,有些题目我是靠看例子来做的,英文太烂了,机器翻译又乱七八糟的,囧~

恩。都这么过来的。学python英文多多少少是会接触的,就当锻炼英文吧,实在看不懂的略过先做其它的就行~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-15 22:48:31 | 显示全部楼层
[python cookbook]
问题:映射名称到序列元素
解决:运用命名元组collections模块中的namedtuple类型

PS:有些鱼油可能不明白这个是什么问题,稍微说一下,对于列表和元组来说,我们只能用下标来取某个值,但有时候每个值是有特殊的意义的,如一个存储了某个学生分数的元组(80,75,90),第一列是语文分数,第二列是数学分数,第三列是英语 分数,那么每次我们取语文分数时得得用下标0,以此类推,当科目比较多时,很难记住哪个科目在哪一个索引位置上。对于我来说,这种问题我想到的第一个办法是用一个字典来存储学生分数;另外一个方法是,用一个字典来存储索引位置。但是元组支持zip操作(大家应该记得之前有一节说到的用zip取某一列数据值吧,比如说这里要取所有学生的语文分数),还有就是解压操作(a,b,c = (80, 75,90)),等等~~
下面看一下例子
>>> from collections import namedtuple
>>> Subscriber = namedtuple('Subscriber', ['addr', 'joined'])
>>> sub = Subscriber('jonesy@example.com', '2012-10-19')
>>> sub
Subscriber(addr='jonesy@example.com', joined='2012-10-19')
>>> sub.addr
'jonesy@example.com'
>>> sub.joined
'2012-10-19'
>>>
来对比一下直接用元组和用namedtuple的代码的可读性(在写大程序的时候你经常需要去看自己的代码,除了注释,其它的比如变量命名,以及这种更直观的数据类型的应用都会影响程序的可读性):
# 使用普通元组的代码
def compute_cost(records):
total = 0.0
for rec in records:
    total += rec[1] * rec[2]
return total
# 使用nametuple的代码
from collections import namedtuple

Stock = namedtuple('Stock', ['name', 'shares', 'price'])
def compute_cost(records):
    total = 0.0
    for rec in records:
        s = Stock(*rec)
    total += s.shares * s.price
    return total

另外 一个需要注意的问题是,元组的值是不可改变的,那么当我们想改变nametuple的某个值时怎么做呢,首先当然会想到平时我们想更改元组时做的,对了创建一个新的元组替代它,nametuple有个方法叫作_replace(PS:别忘了下划线),它可以返回一个新的nametuple,这个元组是将原元组中你指定的字段替换成新的值得到的。那么它有什么用呢,当某些时候你的数据并不完整有所缺失时,你可以先创建一个由缺省值组成的nametuple(这里我用命名为stock_prototype),在每次插入新的数据时,用这个变量的_replace方法将已知的字典更新进去,如下面这样
from collections import namedtuple

Stock = namedtuple('Stock', ['name', 'shares', 'price', 'date', 'time'])

# Create a prototype instance
stock_prototype = Stock('', 0, 0.0, None, None)

# Function to convert a dictionary to a Stock
def dict_to_stock(s):
    return stock_prototype._replace(**s)
下面是它的使用方法:
>>> a = {'name': 'ACME', 'shares': 100, 'price': 123.45}
>>> dict_to_stock(a)
Stock(name='ACME', shares=100, price=123.45, date=None, time=None)
>>> b = {'name': 'ACME', 'shares': 100, 'price': 123.45, 'date': '12/17/2012'}
>>> dict_to_stock(b)
Stock(name='ACME', shares=100, price=123.45, date='12/17/2012', time=None)
>>>
最后提示,当你创建的数据结构很复杂时,命名元组并不适合,这时候创建一个包含__slot__方法的类会更加的实用~~
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2015-6-17 23:11:41 | 显示全部楼层
[python cookbook]
问题:你需要在数据序列上执行聚集函数(比如 sum() , min() , max() ), 但是首先你需要先转换或者过滤数据
解决:使用一个生成器表达式参数

看例子
nums = [1, 2, 3, 4, 5]
s = sum(x * x for x in nums)
PS:这里要计算nums中所有数的平方和,有些鱼油可能会选择这样的方式v
s = sum([x * x for x in nums])
那么两者有什么不同:下面的版本是将一个列表做为参数传入sum函数,我们知道sum函数可以接受一个可迭代对象或者多个可比较对象,下面的写法都是对的
sum(0, 1, 2, 3)  # 传入多个比较对象
sum(range(4))  # 传入1个可迭代对象
还有一点,我自己以前犯过的错误,把一个可迭代对象和一个比较对象一起比较,结果告诉我两种对象不能比较,像下面这样
>>> max([1, 2, 3, 4], 5)
Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    max([1, 2, 3, 4], 5)
TypeError: unorderable types: int() > list()
上面s的计算中,使用可生成式  x * x for x in nums  的好处是不用先在内存中创建一个列表[x * x for x in nums],从节省了内存,另外下面两种方法效果是差不多的
s = sum(x * x for x in nums)
s = sum((x * x for x in nums))
第二种方法相当于传入一个可迭代对象,第一种方法传入多个比较对象,那么这三种方式效率都如何呢,我们来看看
from time import clock
clock()
nums = list(range(100))
first = clock()
for i in range(1000000):
    s = sum(x * x for x in nums)
second = clock()
for i in range(1000000):
    s = sum((x * x for x in nums))
third = clock()
for i in range(1000000):
    s = sum([x * x for x in nums])
forth = clock()
print(second-first)
print(third-second)
print(forth-third)
以上是三种方式各运行100W次的用时对比,如果看下面~~
>>> 
8.507837522475626
8.30724140120892
6.948129495526043
>>> 
可以看到前两种方式差别不算太大,,但第三种用列表的方式明显会快一 些,虽然不知道内部的机制,但是可以确定的是用列表的方式用内存换取了效率~~


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-11 11:20:32 | 显示全部楼层
楼主那网页貌似打不开
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-11 11:27:10 | 显示全部楼层
感觉没鱼币什么都做不了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-24 17:30

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表