【问题标题】:Short (and useful) python snippets [closed]简短(且有用)的python片段[关闭]
【发布时间】:2010-10-16 01:42:12
【问题描述】:

本着现有"what's your most useful C/C++ snippet" 的精神 - 线程:

你们有没有(经常)使用的简短的、单功能的 Python sn-ps 并希望与 StackOverlow 社区分享?请保持条目小(25岁以下 行吗?),每篇文章只举一个例子。

我将从不时使用的简短 sn-p 开始计算 python 项目中的 sloc(源代码行):

# prints recursive count of lines of python source code from current directory
# includes an ignore_list. also prints total sloc

import os
cur_path = os.getcwd()
ignore_set = set(["__init__.py", "count_sourcelines.py"])

loclist = []

for pydir, _, pyfiles in os.walk(cur_path):
    for pyfile in pyfiles:
        if pyfile.endswith(".py") and pyfile not in ignore_set:
            totalpath = os.path.join(pydir, pyfile)
            loclist.append( ( len(open(totalpath, "r").read().splitlines()),
                               totalpath.split(cur_path)[1]) )

for linenumbercount, filename in loclist: 
    print "%05d lines in %s" % (linenumbercount, filename)

print "\nTotal: %s lines (%s)" %(sum([x[0] for x in loclist]), cur_path)

【问题讨论】:

  • Python Cookbook (code.activestate.com/recipes/langs/python) 是一个更好的资源。示例、评论、cmets 以及在线和书籍形式提供。另外,您的示例是维护恐怖,并且 "%05d" % ln 比 "%s" % (str(len).zfill(5)) 好。
  • “恐怖”的示例:1) 如果 cur_path 为“/home/dalke”且 m 为“/home/dalke/subdir/home/dalke/”,则 m.split(curpath)[1] 失败任何”。 2) 不需要 list() 。 3) 'for b,zn in [(r,f) for ...]' 可以简化为 'for b,ignore,zn in os.walk(cur_path)。哦,还有 4) 换行和缩进有助于提高可读性
  • 为什么不使用 .endswith() 来检查 .py 扩展名?
  • 另外,建议使用一个集合作为忽略列表。这不是一个性能敏感的应用程序,但没有理由不利用哈希进行查找。

标签: python code-snippets


【解决方案1】:

调试时,有时您希望使用基本编辑器查看字符串。用记事本显示字符串:

import os, tempfile, subprocess

def get_rand_filename(dir_=os.getcwd()):
    "Function returns a non-existent random filename."
    return tempfile.mkstemp('.tmp', '', dir_)[1]

def open_with_notepad(s):
    "Function gets a string and shows it on notepad"
    with open(get_rand_filename(), 'w') as f:
        f.write(s)
        subprocess.Popen(['notepad', f.name])

【讨论】:

【解决方案2】:

通过 x 元素块迭代任何大小(包括未知大小)的任何可迭代对象(列表、集合、文件、流、字符串等):

from itertools import chain, islice

def chunks(iterable, size, format=iter):
    it = iter(iterable)
    while True:
        yield format(chain((it.next(),), islice(it, size - 1)))

>>> l = ["a", "b", "c", "d", "e", "f", "g"]
>>> for chunk in chunks(l, 3, tuple):
...         print chunk
...     
("a", "b", "c")
("d", "e", "f")
("g",)

【讨论】:

    【解决方案3】:

    实际上我刚刚创建了这个,但我认为它将是一个非常有用的调试工具。

    def dirValues(instance, all=False):
        retVal = {}
        for prop in dir(instance):
            if not all and prop[1] == "_":
                continue
            retVal[prop] = getattr(instance, prop)
        return retVal
    

    我通常在 pdb 上下文中使用 dir(),但我认为这会更有用:

    (pdb) from pprint import pprint as pp
    (pdb) from myUtils import dirValues
    (pdb) pp(dirValues(someInstance))
    

    【讨论】:

      【解决方案4】:

      为当前目录中的文件启动一个简单的 Web 服务器:

      python -m SimpleHTTPServer
      

      对于共享文件很有用。

      【讨论】:

      • python -m SimpleHTTPServer 8008 服务于 8008 端口
      【解决方案5】:
      import tempfile
      import cPickle
      
      class DiskFifo:
          """A disk based FIFO which can be iterated, appended and extended in an interleaved way"""
          def __init__(self):
              self.fd = tempfile.TemporaryFile()
              self.wpos = 0
              self.rpos = 0
              self.pickler = cPickle.Pickler(self.fd)
              self.unpickler = cPickle.Unpickler(self.fd)
              self.size = 0
      
          def __len__(self):
              return self.size
      
          def extend(self, sequence):
              map(self.append, sequence)
      
          def append(self, x):
              self.fd.seek(self.wpos)
              self.pickler.clear_memo()
              self.pickler.dump(x)
              self.wpos = self.fd.tell()
              self.size = self.size + 1
      
          def next(self):
              try:
                  self.fd.seek(self.rpos)
                  x = self.unpickler.load()
                  self.rpos = self.fd.tell()
                  return x
      
              except EOFError:
                  raise StopIteration
      
          def __iter__(self):
              self.rpos = 0
              return self
      

      【讨论】:

        【解决方案6】:

        一个“进度条”,如下所示:

        |#############################---------------------|
        59 percent done
        

        代码:

        class ProgressBar():
            def __init__(self, width=50):
                self.pointer = 0
                self.width = width
        
            def __call__(self,x):
                 # x in percent
                 self.pointer = int(self.width*(x/100.0))
                 return "|" + "#"*self.pointer + "-"*(self.width-self.pointer)+\
                        "|\n %d percent done" % int(x) 
        

        测试功能(windows系统,将“clear”改为“CLS”):

        if __name__ == '__main__':
            import time, os
            pb = ProgressBar()
            for i in range(101):
                os.system('clear')
                print pb(i)
                time.sleep(0.1)
        

        【讨论】:

        • 我如何使用这个代码?
        • 现在我们有tqdm, from tqdm import tqdm & for i in tqdm([1,2,3]): print i
        【解决方案7】:

        模拟 switch 语句。例如 switch(x) {..}:

        def a():
          print "a"
        
        def b():
          print "b"
        
        def default():
           print "default"
        
        apply({1:a, 2:b}.get(x, default))
        

        【讨论】:

          【解决方案8】:

          以下是一些我认为值得了解但可能对日常没有用处的内容。 大部分都是一个班轮。

          从列表中删除重复项

          L = list(set(L))
          

          从字符串中获取整数(空格分隔)

          ints = [int(x) for x in S.split()]
          

          寻找阶乘

          fac=lambda(n):reduce(int.__mul__,range(1,n+1),1)
          

          求最大公约数

          >>> def gcd(a,b):
          ...     while(b):a,b=b,a%b
          ...     return a
          

          【讨论】:

          • 如何确定 set(L) 不会与原始列表的顺序发生冲突?集合是无序的
          • 是的,它可能确实如此,但是您如何在不弄乱顺序的情况下从列表中删除重复项?这不是一个非常明确的问题。
          • 为了保持顺序,您可能需要在程序中进行(对不起格式,但这是一个注释): new_list=[];对于 old_list 中的 x:如果 x 不在 new_list 中:new_list.append(x)
          【解决方案9】:
          • 像上面的另一个人一样,我说“哇!!”当我发现 enumerate()

          • 当我发现 repr() 让我有可能准确地看到我想用正则表达式分析的字符串的内容时,我对 Python 赞不绝口

            李>
          • 我很满意地发现 print '\n'.join(list_of_strings) 使用 '\n'.join(...)for ch in list_of_strings: print ch 显示得更快

            李>
          • splitlines(1) 带参数保留换行符

          这四个“技巧”组合在一个 sn-p 中非常有用,可以快速显示网页的代码源,逐行显示,每一行都被编号,所有特殊字符(如 '\t' 或换行符都不会被解释) ,并且存在换行符:

          import urllib
          from time import clock,sleep
          
          sock = urllib.urlopen('http://docs.python.org/')
          ch = sock.read()
          sock.close()
          
          
          te = clock()
          for i,line in enumerate(ch.splitlines(1)):
              print str(i) + ' ' + repr(line)
          t1 = clock() - te
          
          
          print "\n\nIn 3 seconds, I will print the same content, using '\\n'.join(....)\n" 
          
          sleep(3)
          
          te = clock()
          # here's the point of interest:
          print '\n'.join(str(i) + ' ' + repr(line)
                          for i,line in enumerate(ch.splitlines(1)) )
          t2 = clock() - te
          
          print '\n'
          print 'first  display took',t1,'seconds'
          print 'second display took',t2,'seconds'
          

          用我不是很快的电脑,我得到了:

          first  display took 4.94626048841 seconds
          second display took 0.109297410704 seconds
          

          【讨论】:

            【解决方案10】:

            当与其他列表相乘时返回笛卡尔积的自定义列表...好在笛卡尔积是可索引的,不像 itertools.product 那样(但被乘数必须是序列,而不是迭代器)。

            import operator
            
            class mylist(list):
                def __getitem__(self, args):
                    if type(args) is tuple:
                        return [list.__getitem__(self, i) for i in args]
                    else:
                        return list.__getitem__(self, args)
                def __mul__(self, args):
                    seqattrs = ("__getitem__", "__iter__", "__len__")
                    if all(hasattr(args, i) for i in seqattrs):
                        return cartesian_product(self, args)
                    else:
                        return list.__mul__(self, args)
                def __imul__(self, args):
                    return __mul__(self, args)
                def __rmul__(self, args):
                    return __mul__(args, self)
                def __pow__(self, n):
                    return cartesian_product(*((self,)*n))
                def __rpow__(self, n):
                    return cartesian_product(*((self,)*n))
            
            class cartesian_product:
                def __init__(self, *args):
                    self.elements = args
                def __len__(self):
                    return reduce(operator.mul, map(len, self.elements))
                def __getitem__(self, n):
                    return [e[i] for e, i  in zip(self.elements,self.get_indices(n))]
                def get_indices(self, n):
                    sizes = map(len, self.elements)
                    tmp = [0]*len(sizes)
                    i = -1
                    for w in reversed(sizes):
                        tmp[i] = n % w
                        n /= w
                        i -= 1
                    return tmp
                def __add__(self, arg):
                    return mylist(map(None, self)+mylist(map(None, arg)))
                def __imul__(self, args):
                    return mylist(self)*mylist(args)
                def __rmul__(self, args):
                    return mylist(args)*mylist(self)
                def __mul__(self, args):
                    if isinstance(args, cartesian_product):
                        return cartesian_product(*(self.elements+args.elements))
                    else:
                        return cartesian_product(*(self.elements+(args,)))
                def __iter__(self):
                    for i in xrange(len(self)):
                        yield self[i]
                def __str__(self):
                    return "[" + ",".join(str(i) for i in self) +"]"
                def __repr__(self):
                    return "*".join(map(repr, self.elements))
            

            【讨论】:

            • 我没有看懂其中的一行,你能评论一下它是如何工作的吗?
            【解决方案11】:

            对于 Python 2.4+ 或更早版本:

            for x,y in someIterator:
              listDict.setdefault(x,[]).append(y)
            

            在 Python 2.5+ 中,可以使用 defaultdict

            【讨论】:

              【解决方案12】:

              我喜欢使用any 和生成器:

              if any(pred(x.item) for x in sequence):
                  ...
              

              而不是这样写的代码:

              found = False
              for x in sequence:
                  if pred(x.n):
                      found = True
              if found:
                  ...
              

              我第一次从 Peter Norvig article 那里了解到这项技术。

              【讨论】:

              • +1 参考 Norvig 的数独文章。非常好。
              • 还有 all() 来检查所有项目是否为真。
              【解决方案13】:

              为了展平一个列表,比如

              [['a', 'b'], ['c'], ['d', 'e', 'f']]
              

              进入

              ['a', 'b', 'c', 'd', 'e', 'f']
              

              使用

              [inner
                  for outer in the_list
                      for inner in outer]
              

              【讨论】:

              • sum(the_list, [])。虽然我怀疑这会在某个地方出错(当然,除了生成器)。
              • @HoverHell,有些人可能会认为它可能是“正确的”,但我已经使用了一段时间并且喜欢它。最好的!
              【解决方案14】:

              嵌套列表和字典的巨大加速:

              deepcopy = lambda x: cPickle.loads(cPickle.dumps(x))
              

              【讨论】:

              • 我一直对这种技术持怀疑态度,尽管它似乎应该与我能想到的任何其他技术一样快。 pythonistas 认为这是获取深层副本的好方法吗? (fwiw,无论如何我都使用这种技术)
              【解决方案15】:

              对于需要当前的列表推导,下一步:

              [fun(curr,next) 
               for curr,next 
               in zip(list,list[1:].append(None)) 
               if condition(curr,next)] 
              

              对于循环列表zip(list,list[1:].append(list[0]))

              对于以前,当前:zip([None].extend(list[:-1]),list) 循环:zip([list[-1]].extend(list[:-1]),list)

              【讨论】:

              【解决方案16】:

              zip(*iterable) 转置一个可迭代对象。

              >>> a=[[1,2,3],[4,5,6]]
              >>> zip(*a)
                  [(1, 4), (2, 5), (3, 6)]
              

              它对字典也很有用。

              >>> d={"a":1,"b":2,"c":3}
              >>> zip(*d.iteritems())
              [('a', 'c', 'b'), (1, 3, 2)]
              

              【讨论】:

              • 当我第一次找到它时,我很喜欢它,我认为它是“解压缩”,哈哈。但是我不知道字典。谢谢。
              【解决方案17】:

              假设您有一个项目列表,并且您想要一个以这些项目作为键的字典。使用 fromkeys:

              >>> items = ['a', 'b', 'c', 'd']
              >>> idict = dict().fromkeys(items, 0)
              >>> idict
              {'a': 0, 'c': 0, 'b': 0, 'd': 0}
              >>>
              

              fromkeys 的第二个参数是要授予所有新创建的键的值。

              【讨论】:

              • fromkeys 是一个静态方法。你应该做“dict.fromkeys(items, 0)”。您的代码创建并丢弃了一个空字典。
              • @Andrew Dalke ,我相信dict.fromkeys 是一个类方法。原因:dict.fromkeys 返回一个字典,因此它应该class 作为它的第一个参数。考虑一下您何时将dict 子类化——MyDict.fromkeys 应该给出MyDict 的实例
              • @jeffjose:你是对的。我做了你建议的测试并查看了代码,因为我很好奇这是如何完成的。
              【解决方案18】:

              要确定行是否为空(即大小为 0 或仅包含空格),请在条件中使用字符串方法 strip,如下所示:

              if not line.strip():    # if line is empty
                  continue            # skip it
              

              【讨论】:

                【解决方案19】:

                初始化一个二维列表

                虽然这可以安全地初始化列表:

                lst = [0] * 3
                

                同样的技巧不适用于 2D 列表(列表列表):

                >>> lst_2d = [[0] * 3] * 3
                >>> lst_2d
                [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
                >>> lst_2d[0][0] = 5
                >>> lst_2d
                [[5, 0, 0], [5, 0, 0], [5, 0, 0]]
                

                运算符 * 复制其操作数,并且用 [] 构造的复制列表指向同一个列表。正确的做法是:

                >>> lst_2d = [[0] * 3 for i in xrange(3)]
                >>> lst_2d
                [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
                >>> lst_2d[0][0] = 5
                >>> lst_2d
                [[5, 0, 0], [0, 0, 0], [0, 0, 0]]
                

                【讨论】:

                【解决方案20】:

                我知道的唯一让我惊叹的“技巧”就是枚举。它允许您访问 for 循环中元素的索引。

                >>> l = ['a','b','c','d','e','f']
                >>> for (index,value) in enumerate(l):
                ...     print index, value
                ... 
                0 a
                1 b
                2 c
                3 d
                4 e
                5 f
                

                【讨论】:

                • 不需要把索引,值放在括号里。此外,上述评论是幼稚/无知的。
                【解决方案21】:

                我喜欢将所有内容压缩到一个目录中。为 instabackups 热键!

                import zipfile
                
                z = zipfile.ZipFile('my-archive.zip', 'w', zipfile.ZIP_DEFLATED)
                startdir = "/home/johnf"
                for dirpath, dirnames, filenames in os.walk(startdir):
                  for filename in filenames:
                    z.write(os.path.join(dirpath, filename))
                z.close()
                

                【讨论】:

                • zip -r my-archive.zip 目录/有什么问题?
                • 那不是 Python sn-p。 :) (此外,您可以在 sn-p 中包含特殊逻辑,这可能与 shell 命令有关。)
                • +1(虽然我更喜欢tarfile
                【解决方案22】:

                硬链接当前目录中的相同文件(在 unix 上,这意味着它们共享物理存储,这意味着空间要少得多):

                import os
                import hashlib
                
                dupes = {}
                
                for path, dirs, files in os.walk(os.getcwd()):
                    for file in files:
                        filename = os.path.join(path, file)
                        hash = hashlib.sha1(open(filename).read()).hexdigest()
                        if hash in dupes:
                            print 'linking "%s" -> "%s"' % (dupes[hash], filename)
                            os.rename(filename, filename + '.bak')
                            try:
                                os.link(dupes[hash], filename)
                                os.unlink(filename + '.bak')
                            except:
                                os.rename(filename + '.bak', filename)
                            finally:
                        else:
                            dupes[hash] = filename
                

                【讨论】:

                • +1,尽管可以通过使用唯一的临时文件名来改进此代码,而不是盲目地假设 filename.bak 不存在。
                猜你喜欢
                • 2011-07-13
                • 1970-01-01
                • 2010-11-01
                • 1970-01-01
                • 2010-10-31
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多