这是我用python写的第一件事。我来自Java背景。我不想只学习如何用Python语法编写java代码。我想学习如何用pythonic范例编程。
你们可以评论我如何使下面的代码更加pythonic吗?
from math import sqrt
# recursively computes the factors of a number
def factors(num):
factorList = []
numroot = int(sqrt(num)) + 1
numleft = num
# brute force divide the number until you find a factor
for i in range(2, numroot):
if num % i == 0:
# if we found a factor, add it to the list and compute the remainder
factorList.append(i)
numleft = num / i
break
# if we didn't find a factor, get out of here!
if numleft == num:
factorList.append(num)
return factorList
# now recursively find the rest of the factors
restFactors = factors(numleft)
factorList.extend(restFactors)
return factorList
# grabs all of the twos in the list and puts them into 2 ^ x form
def transformFactorList(factorList):
num2s = 0
# remove all twos, counting them as we go
while 2 in factorList:
factorList.remove(2)
num2s += 1
# simply return the list with the 2's back in the right spot
if num2s == 0: return factorList
if num2s == 1:
factorList.insert(0, 2)
return factorList
factorList.insert(0, '2 ^ ' + str(num2s))
return factorList
print transformFactorList(factors(#some number))
答案 0 :(得分:22)
大卫·古德尔(David Goodger)有一本名为“像Python一样的代码”here的优秀入门书。该文中的一些内容重新命名(引用):
joined_lower
了解函数,方法,
属性
joined_lower
或ALL_CAPS for
常数
StudlyCaps
用于课程
camelCase
只是为了顺从
已有的惯例
答案 1 :(得分:21)
只需使用'import math'和'math.sqrt()'代替'from math import sqrt'和'sqrt()';你只是导入'sqrt'就不会赢得任何东西,并且代码很快会因为太多的导入而变得难以处理。此外,当你大量使用from-import时,reload()和mock for out等测试会更快地破解。
divmod()函数是执行除法和模数的便捷方式。您可以使用for / else而不是对numleft进行单独检查。您的因子功能是发电机的自然候选者。另一个答案中已经提到了xrange()。这就是以这种方式完成的:
import math
# recursively computes the factors of a number as a generator
def factors(num):
numroot = int(math.sqrt(num)) + 1
# brute force divide the number until you find a factor
for i in xrange(2, numroot):
divider, remainder = divmod(num, i)
if not remainder:
# if we found a factor, add it to the list and compute the
# remainder
yield i
break
else:
# if we didn't find a factor, get out of here!
yield num
return
# now recursively find the rest of the factors
for factor in factors(divider):
yield factor
使用生成器意味着您只能迭代结果一次;如果你只是想要一个列表(就像你在translateFactorsList中那样),你将不得不将调用包装在list()中的factors()中。
答案 2 :(得分:17)
您可能想要看的另一件事是文档字符串。例如,此函数的注释:
# recursively computes the factors of a number
def factors(num):
可以转换成这个:
def factors(num):
""" recursively computes the factors of a number"""
以这种方式实现这一点并不是100%必要,但如果你开始使用pydoc这样的东西,这是一个很好的习惯。
你也可以这样做:
"""This is a docstring"""
>>> import docstring
>>> help(docstring)
Help on module docstring:
NAME
docstring - This is a docstring
FILE
/Users/jason/docstring.py
答案 3 :(得分:8)
一些评论:
range()
替换为xrange()
;当你调用range()
时,它会一次性分配整个范围,而当你遍历xrange()
时,它会一次返回一个结果,从而节省内存。if num2s -- 0: return factorList
)上。它使得一眼就能看到它正在做什么变得更加困难(这是一个障碍)。[sympy][1]
模块已经有了计算因子的代码,这可以通过消除大部分代码来简化代码。例如:
factorList.insert(0, '2 ^ ' + str(num2s))
可以更改为
factorlist.insert(0, '2 ^ %s' % num2s)
总而言之,我发现你的代码并不是广泛的非pythonic。只要确保你想使用floor division,因为这是默认情况下整数值会发生的事情。否则,您需要修复除法运算符:
from __future__ import division
有时令人沮丧的语言警告。
答案 4 :(得分:4)
from itertools import takewhile
def transform_factor_list(factor_list):
num_2s = len(list(takewhile(lambda e: e == 2, factor_list)))
if num_2s > 1:
factor_list[:num_2s] = ["2 ^ %i" % (num_2s, )]
return factor_list
这就是我从第二个功能中得到的结果。
大多数pythonic变化:
该函数假定输入是有序的,这可以通过因子来实现。
编辑:删除了某些列表的特殊情况,这种方式更紧凑
答案 5 :(得分:4)
根据克里斯的回答,稍加简化:
HTH:
import itertools
def factorize(n):
# ideally an iterator of prime numbers
# this'll work though
divisors = itertools.count(2)
for divisor in divisors:
# This condition is very clever!
# Note that `n` is decreasing, while `divisor` is increasing.
# And we know that `n` is not divisible by anything smaller,
# so this stops as soon as the remaining `n` is obviously prime.
if divisor**2 > n:
yield n
break
while n % divisor == 0:
yield divisor
n //= divisor
def compress(factors):
for (factor, copies) in itertools.groupby(factors):
# The second object yielded by groupby is a generator of equal factors.
# Using list() to count its length.
power = len(list(copies))
yield (factor, power)
def tostring(compressed):
return ' * '.join("%d**%d" % (factor, power) for (factor, power) in compressed)
# test
assert tostring(compress(factorize(12))) == '2**2 * 3**1'
答案 6 :(得分:3)
不要害怕列表理解。从Java切换到Python并发现它们是一个美好的一天。
对于因子函数,可能是这样的:
def factors(num):
return [i for i in xrange(1, num+1) if num % i == 0]
可能不是最好的代码,但它简短易懂。
祝你好运,它是一种很棒的语言。
答案 7 :(得分:3)
这就是我这样做的方式......
import itertools
import collections
def factorize(n):
# ideally an iterator of prime numbers
# this'll work though
divisors = itertools.count(2)
divisor = divisors.next()
while True:
if divisor**2 > n:
yield n
break
a,b = divmod(n, divisor)
if b == 0:
yield divisor
n = a
else:
divisor = divisors.next()
def compress(factors):
summands = collections.defaultdict(lambda: 0)
for factor in factors:
summands[factor] += 1
return [(base, summands[base]) for base in sorted(summands)]
def tostring(compressed):
return ' * '.join("%d**%d" % factor for factor in compressed)
答案 8 :(得分:2)
以下是对我的反应:
def transformFactorList(factorList):
oldsize = len(factorList)
factorList = [f for f in factorList if f != 2]
num2s = oldsize - len(factorList)
if num2s == 0:
return []
if num2s == 1:
return [2]+factorList
return ['2 ^ %s' % num2s] + [factorList]
表单[f for f in factorList if f != 2]
称为列表理解。
答案 9 :(得分:2)
由于这篇文章似乎被Casey(lol)复活了,我将加上2美分。
浏览 PEP-8 中的所有内容。当我遇到代码格式化问题时,它帮助了我。
答案 10 :(得分:2)
我会使用列表理解来解决这两个问题:
def transformFactorList(factorList):
twos = [x for x in factorList if x == 2]
rest = [x for x in factorList if x != 2]
rest.insert(0, "2 ^ %d" % len(twos))
return rest
请注意,这会为您提供2^0
和2^1
,而您的代码却没有。你正在做什么两个似乎是任意的(有时你得到一个字符串,有时一个数字,有时没有),所以我认为这将没事。如果您愿意,可以轻松更改:
def transformFactorList(factorList):
twos = [x for x in factorList if x == 2]
rest = [x for x in factorList if x != 2]
if twos:
rest.insert(0, 2 if len(twos)==1 else "2 ^ %d" % len(twos))
return rest
答案 11 :(得分:1)
使用递归(在没有必要的地方)不是pythonic。 Python没有尾递归消除, flat优于嵌套。
如有疑问,请尝试import this
更新:按照热门请求,这里进行迭代分解(叹气):
"""returns an iterator of tuples (factor, power) such that
reduce(operator.mul, (factor**power for factor, power in factors(n))) == n """
def factors(n):
i = 2
while n > 1:
p = 0
while n > 1 and n % i == 0:
p += 1
n /= i
if p:
yield (i, p)
i += 1