Be pythonic @StudyArea 台南 2012 10月份

4,657 views

Published on

Published in: Technology
0 Comments
7 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,657
On SlideShare
0
From Embeds
0
Number of Embeds
2,912
Actions
Shares
0
Downloads
52
Comments
0
Likes
7
Embeds 0
No embeds

No notes for slide

Be pythonic @StudyArea 台南 2012 10月份

  1. 1. BePythonic 陳信屹 (Chen Hsin-Yi) StudyArea 2012, 10/20, Taiwan
  2. 2. Me?陳信屹 (Chen Hsin-Yi) a.k.a HychenPython 用大概 6 年 ,主要是寫些系統整合的工作
  3. 3. This talk is based on Christopher Arndts talk How to Write "Pythonic" Code and David Goodgers talkCode Like a Pythonista: Idiomatic Python
  4. 4. Outline● Zen of Python● Coding Style● General idioms● Functions are first-class object● Duck Typing● Class are also first-class obejct● Organized your code
  5. 5. import this
  6. 6. Zen of PythonSimple is better than complex. … Flat is better than nested. … Readability counts.
  7. 7. Coding Style程式碼是寫給人看的,特別是未來的你
  8. 8. PEP8:Style Guide for Python Code http://www.python.org/dev/peps/pep-0008/ PEP = Python Enhancement Proposal
  9. 9. Whitespace (1)● 4 spaces per indentation level.● No hard tabs.● Never mix tabs and spaces.● Two blank line between functions.● Two blank lines between classes.
  10. 10. Whitespace (2)● Add a space after "," in dicts, lists, tuples, & argument lists, and after ":" in dicts, but not before.● Put spaces around assignments & comparisons (except in argument lists).● No spaces just inside parentheses or just before argument lists.● No spaces just inside docstrings.● def make_squares(key, value=0): """Return a dictionary and a list...""" d = {key: value} l = [key, value] return d, l
  11. 11. Naming Convention● joined_lower for functions, methods, attributes● joined_lower or ALL_CAPS for constants● StudlyCaps for classes● Attributes: interface, _internal, __private●
  12. 12. More than PEP8...● Google Python Style Guide ● Google Python Style for vim ● For Emacs, the default settings should be fine.● Launchpad Python Style Guide ● Also provide configuration hit for vim class MyClass: class MyClass: def edit_number(self): def editNumber(self): pass pass
  13. 13. Long Lines & Continuations● Keep lines below 80 characters in length.● Use implied line continuation inside parentheses/brackets/braces: def __init__(self, first, second, third, fourth, fifth, sixth): output = (first + second + third + fourth + fifth + sixth)● Use backslashes as a last resort: VeryLong().left_hand_side = even_longer.right_hand_side()
  14. 14. Lone Strings>>> print o n "e"onetext = (Long strings can be made up of several shorter strings.)"""Tripledoublequotes"""Triplesinglequotes
  15. 15. Compound Statements (1)Good:if foo == blah: do_something()do_one()do_two()do_three()Bad:if foo == blah: do_something()do_one(); do_two(); do_three()
  16. 16. Docstrings & Comments● Docstrings = How to use code● Comments = Why (rationale) & how code works
  17. 17. pep8 in Emacspep8 - A tool to check your Python code against some of the styleconventions in PEP 8.
  18. 18. Pyflakes in Emacspyflakes - simple Python source checker
  19. 19. More powerful tool...● pychecker ● http://pychecker.sourceforge.net/ ● $ apt-get install pychecker● pylint ● http://www.logilab.org/857 ● $ apt-get install pylint
  20. 20. Generalidioms
  21. 21. Interactive "_">>> 1 + 12>>> _2_ stores the last printed expression.>>> import math>>> math.pi / 31.0471975511965976>>> angle = _>>> math.cos(angle)0.50000000000000011>>> _0.50000000000000011
  22. 22. Swap ValuesIn other languages:temp = aa=bb = tempIn Python:b, a = a, b- The comma is the tuple constructor syntax.- A tuple is created on the right (tuple packing).- A tuple is the target on the left (tuple unpacking).
  23. 23. Parallel assignmentvariable_one, variable_two = 10, 20variable_one, variable_two = [10, 20]variable_one, variable_two = (10, 20)
  24. 24. Return multiple values in function (1)def get_name(): # you code return first_name, last_namedef get_name(): # you code return (first_name, last_name)fst_name, lst_name = get_name()
  25. 25. Return multiple values in function (2)The return value is actually a tuple.def get_name(): # you code return first_name, last_nameprint get_name() # (first_name, last_name)print list(get_name()) # [first_name, last_name]
  26. 26. More about Tuple>>> 1,(1,)>>> (1,)(1,)>>> (1)1>>> ()()>>> tuple()()
  27. 27. Building Strings from Substringscolors = [red, blue, green, yellow]Dont do this:result = for s in colors: result += sInstead, do this:result = .join(colors)
  28. 28. Building Strings, Variations 1if you want spaces between your substrings:result = .join(colors)Or commas and spaces:result = , .join(colors)Heres a common case:colors = [red, blue, green, yellow]print Choose, , .join(colors[:-1]), or, colors[-1]Choose red, blue, green or yellow
  29. 29. Building Strings, Variations 2If you need to apply a function to generate the substrings:result = .join(map(fn, items)If function need more than 1 argumentresult = .join(fn(i, other_arg) for i in items)
  30. 30. Building Strings, Variations 3If you need to compute the substringsincrementally, accumulate them in a list first:Items = [first line, second line]...items.append(item) # many times...
  31. 31. Slicing StringString is like a immutable list.>>> s = "this is a string, a">>> s[0]t>>> s[0:4], s[-1](this, a)>>> s = u“Unicode 也行”>>> s[-1]“ 行”
  32. 32. String formation (1/2)str.format = format(...) S.format(*args, **kwargs) -> string Return a formatted version of S, usingsubstitutions from args and kwargs. The substitutions are identified by braces ({and }).
  33. 33. String formation (2/2)● “{0} {1} {2}”.format(1,2,3)● “{1} {0} {2}”.format(1,2,3)● “{a} {b} {c}”.format(a=1, b=2, c=3)● % is not recommend ● “%s %s” % (1,2)
  34. 34. String Template (1/2) ● string.Template ● Delimiter can not be changed in runtime, because string.Template is created by meta class.import string import stringtpl=string.Template("#a") class MyTpl(string.Template):tpl.delimiter = # delimiter = #print tpl.substitute(a=1)#a tpl = MyTpl("#a") print tpl.substitute(a=1) NG Work
  35. 35. String Template (2/2)Create a Template Class in runtime if we want to change delimiter.import stringdef templates(content, **tpl_config): if tpl_config: tplcls = type(CustomTemplate, (string.Template,), tpl_config) else: tplcls = string.Template return tplcls(content) Meta Class , we will talk it later if we havetpl = templates("#abcd", delimiter=#) timeprint tpl.substitute(abcd=1)
  36. 36. Pragmatic Unicode● Slide: http://farmdev.com/talks/unicode/● Video: http://pyvideo.org/video/948/pragmatic-unicode- or-how-do-i-stop-the-pain● Unicode Sand-watch ● Bytes on the outside, unicode on the inside ● Encode/decode at the edges● Know what you have ● Bytes or Unicode?● Test...
  37. 37. Unicode Sand-watch>>> chr=u" 我 ">>> chruu6211>>> chr.encode(utf-8)xe6x88x91>>> chr.encode(utf-8).decode(utf-8)uu6211>>> repr(chr)>>> print chr.encode(utf-8)我>>> print repr(chr.encode(utf-8))xe6x88x91
  38. 38. Notes for i18n● Use double quote for interface display message ● u“please input your password:”● Use single quote for internal debug, information message. ● uDEUBG: database is disconnected
  39. 39. Use in where possible (1)string = “this is a string”# do this:if “c” in string: ...do something# not this:if string.count(“c”): ...do something
  40. 40. Use in where possible (2)d = {key1: val1, key2: val2}# do this:if key in d: ...do something with d[key]# not this:if d.has_key(key): ...do something with d[key]
  41. 41. Use in where possible (3)● in is generally faster.● This pattern also works for items in arbitrary containers (such as lists, tuples, and sets).● Less typing ● chr in string v.s string.count(chr) ● key in d v.s d.has_key(key) ● No () !!!
  42. 42. Merge Dict>>> d={a: 1, b: 2, c: 3}>>> d.update({d: 4})>>> d{a: 1, c: 3, b: 2, d: 4}>>> d={a: 1, b: 2, c: 3}>>> d.update({a: 4})>>> d{a: 4, c: 3, b: 2}
  43. 43. Python has names (1/2)● a = [1,2,3] ● type(a) # list● a=1 ● type(a) # int
  44. 44. Python has names (2/2)● a = [1,2,3]● a, b = [1, 2, 3] ● a is b # True ● id(a) == id(b) # True● c=a ● c is a # True ● id(c) == id(b)
  45. 45. Dictionary setdefault Method (1)Initializing mutable dictionary values:equities = {}for (portfolio, equity) in data: if portfolio in equities: equities[portfolio].append(equity) else: equities[portfolio] = [equity]dict.setdefault(key, default) does the job muchmore efficiently:
  46. 46. Testing for NoneGood:if foo is None: do_something()Maybe:if not foo: do_someting()Bad:if foo == None: do_something()
  47. 47. Iterating a list without counterGood:for item in mylist: print itemBad:for i in range(len(mylist)): print mylist[i]
  48. 48. Iterating a list with indexGood:for i, item in enumerate(mylist): if i >= 1: print mylist[i-1] + itemBad:for i in range(len(mylist)): if i >= 1: print mylist[i-1] + itemAlso bad:i=0for item in mylist: if i >= 1: print mylist[i-1] + item i += 1
  49. 49. Use Generator instead of Iterator def items(self): ret = [] for pkgname, ctrlinfo in self.metadata.items(): if ctrlinfo and self._run_checker(ctrlinfo.get(checker)): ret.append(pkgname, ctrlinfo.get(require)) else: ret.append(pkgname, None)use generator instead...def items(self): for pkgname, ctrlinfo in self.metadata.items(): if ctrlinfo and self._run_checker(ctrlinfo.get(checker)): yield (pkgname, ctrlinfo.get(require)) else: yield (pkgname, None)
  50. 50. Another useful generatordef walkfiles(startdir, pattern=None): """Return generator for full paths of all files belowstartdir. Optionally filters out files not matching pattern. """ for dir, dirlist, filelist in os.walk(startdir): for fname in filelist: if pattern and not fnmatch.fnmatch(fname,pattern): continue yield os.path.join(dir, fname)
  51. 51. Read File (1)Open file with `with statment`, and always pass filedescriptor to functionGoodwith open(path, r) as fd: handle_fd(fd)Badhandle_fd(open(path, r).read())
  52. 52. Read File (2/2)with open(path, r) as fd: handle_fd(fd)好處* 只要是 file-like object, handle_fd 可以處理 * open * StringIO.StringIO * codec.open * any object has read interface* 另一個好處是惰性執行
  53. 53. Functions are first-class object
  54. 54. Function is First Class Object● 可當成參數傳給另一個 function● 可以在 funciton 中 return 一個 function● 也可以 assign function 給一個變數● Function 是 Singleton
  55. 55. A trickdef countme(): passprint countme() # 1print countme() # 2print countme() # 3 Can not use global variable Can not use closure Can not import any module
  56. 56. A trickdef countme(): try: countme._count += 1 except AttributeError: countme._count = 1 return countme._countprint countme() #1print countme() #2print countme() #
  57. 57. Default Parameter Values (1)This is a common mistake that beginners often make. Even more advancedprogrammers make this mistake if they dont understand Python names.def bad_append(new_item, a_list=[]): a_list.append(new_item) return a_list>>> print bad_append(one)[one]>>> print bad_append(two)[one, two]
  58. 58. Default Parameter Values (2)def bad_append(b=1, a_list=[]): passprint dir(bad_append)print bad_append.func_defaultsprint bad_append.func_dict
  59. 59. Unpack arguments● tuple->arguments● dict->keyword parameters● Arguements->tuple● Keyword parameters->arguments
  60. 60. tuple->argumentsdef f(a, b, c): print a, b, cargs = (1, 2, 3)f(*args)List also worksf(*[1, 2,3])
  61. 61. dict->keyword argumentsdef f(a, b, c, d=None, e=None): print a, b, cargs = (1, 2, 3)kwargs = {A: 0, B:1}f(*args, **kwargs)
  62. 62. Arguments → tupledef f(*args): print argsf(1, 2, 3, 4)
  63. 63. Keyword Arguments → Dictdef f(*args, **kwargs): print args, kwargsf(D=1, E=2)
  64. 64. Unpack argument exampleimport sysdef f1(a, b): print a, beval(sys.argv[1])(*sys.argv[2:]) f1 *[1, 2]
  65. 65. Closure 函式物件在建立時,綁定了當時作用範圍( Scope )下有效的自由變數( Free variable )
  66. 66. Pure Lambda calculus● A formal system in mathematical logic ● failed● Without Type● Fundamental of functional programming languages● Lambda calculus v.s. Turing machines λx. x Function body Function variable
  67. 67. Pure Lambda Calculus→ : evaluated In Pythonλx. 5 → 5 # lambda x : 5(λx. x+1) 2 → 3 # (lambda x : x + 1)(2)
  68. 68. Pure Lambda CalculusAssume we have a lambda functionλy λx. x+y x,y are freeand we assign 1 to y(λyλx. x+y)(1)So we now have a lambda function that y is bound to 1λx. 1+x x is free, y is boundThen if we assign 2 to x, function returns3 x, y are bound
  69. 69. As Python lambda functionAssume we have a lambda function(lambda y : lambda x : x + y) x,y are freeand we assign 1 to y(lambda y : lambda x : x + y)(1)So we now have a lambda function that y is bound to 1lambda x : x + 1 x is free, y is boundThen if we assign 2 to x, function returns3 x, y are bound# we can write `print (lambda y : lambda x : x + y)(1)(2)` in short
  70. 70. As Python nested functiondef f1(y): def f2(x): return x + y return f2print f1(1)(2) # 3print f1(2)(2) # 4
  71. 71. Closure Exampledef progress(self, *args, **kwds): kwds[stdin] = subprocess.PIPE p = self.__call(progress, as_process=True, *args, **kwds) def update(percent, message=): if type(percent) == float: percent = int(percent * 100) try: p.stdin.write(str(percent) + n) if message: p.stdin.write(# %sn % message) except IOError: exit() return p.returncode up = zenity.progress(text=hi) return update sleep(1) up(50, doing” sleep(1) up(100, “done”
  72. 72. Useful Function tools● map ● map(function, sequence[, sequence, ...]) -> list● filter ● filter(function or None, sequence) -> list, tuple, or string● reduce ● reduce(function, sequence[, initial]) -> value
  73. 73. Decorator without argumentsdef deprecated(func): print “warring” return func@deprecateddef oldfn(a, b): return aoldfn(1)
  74. 74. Decorator with arguments (1/3) func is bound to func in deprecated functoindef deprecated(func): print “warring” return lambda *args, **kwargs: func(*args, **kwargs)@deprecateddef oldfn(a, b): return aoldfn(1)
  75. 75. Decorator with arguments (2/3)def deprecated(func): print “warring” def wrapper(*args, **kwargs): return lambda *args, **kwargs: func(*args,**kwargs) return wrapper@deprecated() ← A decorator to create a decoratordef oldfn(a, b): return a
  76. 76. Decorator with Arguments (3/3)Lets see more detailed code!http://hychen.wuweig.org/blog/2011/12/18/recipe-deprecated-function-in-python/
  77. 77. Duck Typing
  78. 78. Strong Type? Weak Type?● Strong Type● ex. Python ● 1 + “a” → TypeError ● 1 + True → TypeError● Weak Type● ex. JavaScript ● 1 + “a” → “1a” ● 1 + 2rue → 2
  79. 79. Operator : +class A(object): passclass B(int): passA() + 1 # TypeError, because As type is objectB() + 1 # work, because Bs type is int
  80. 80. Duck Typingclass B(object): def __add__(self, x): return "x:" + str(x)print B is int # Falseprint B() + 1 # Workprint 1 + B() # TypeError
  81. 81. Support specified interface...● __call__ - make object callable● __iter__ for for..in● __add__ for + operator● __str__ for print● __sub__ for – operator● ….
  82. 82. 用 Duck Typing 去除不必要的繼承● 減少 Class 之間的耦合度● 專心在界面的實作,而非 Class 的歸類● 使繼承樹變得更扁平 ● 更容易理解 ● 更容易維護
  83. 83. Class are also first- class object
  84. 84. Getter/Setter (1/2)class Foo: def __init__(self, spamm, eggs): self.spamm = spamm self.eggs = eggs def get_spamm(self): return self.spamm def set_spamm(self, value): self.spamm = valuef = Foo(bar, baz)myspamm = f.get_spamm() Bad
  85. 85. Getter/Setter (2/2)class Foo: def __init__(self, spamm, eggs): self.spamm = spamm self.eggs = eggsf = Foo(bar, baz)myspamm = f.spamm Good
  86. 86. Getter/Setter (3/5)class Foo: # ... def get_spamm(self): return make_spamm()f = Foo()myspamm = f.get_spamm() Bad
  87. 87. Getter/Setter (4/5)class Foo: # ... @property def spamm(self): return make_spamm()f = Foo()myspamm = f.spamm Good
  88. 88. Getter/Setter (5/5)class Foo: def set_spamm(self, value): if is_valid(value): self.spamm = value else: raise ValueError(I want my spamm!)f = Foo()f.set_spamm = "Eggs" Bad
  89. 89. Property| property(fget=None, fset=None, fdel=None, doc=None) -> propertyattribute|| fget is a function to be used for getting an attribute value, and likewise| fset is a function for setting, and fdel a function for deling, an| attribute. Typical use is to define a managed attribute x:|class C(object): | def getx(self): return self._x | def setx(self, value): self._x = value | def delx(self): del self._x | x = property(getx, setx, delx, "Im the x property.")
  90. 90. Property (2/2)|| Decorators make defining new properties or modifying existing oneseasy:| class C(object):| @property| def x(self): return self._x| @x.setter| def x(self, value): self._x = value| @x.deleter| def x(self): del self._x
  91. 91. Decorators for Class● property ● property.fset ● property.fget ● property.fdel● staticmethod ● Convert a function to be a static method.● slassmethod ● Convert a function to be a class method
  92. 92. 組織你的程式碼
  93. 93. Project Layout● 常用的 code 寫成 Function● 把 function 用 Module 分類● Module 太大再改成 Package● 需要多個 instance 才用 class
  94. 94. Program Structure● (Shebang) ● Use /usr/bin/env python instend of /usr/bin/python● Source encoding declaration● Module docstring● __all__● Imports (stdlib, third-party, private modules)● Global constants and initialization code● Exceptions● Module-level functions● Classes● main function
  95. 95. __main____main__ is Top-level script environmentSometimes we dont want our code be executed while file is importedso we write a conditional script.if __name__ == __main__: import sys main(sys.argv)or testing codes of current moduleif __name__ == __main__: run_func1_test() run_func2_test()
  96. 96. Summary● Follow PEP 8● Read the standard library reference● Know built-in data structure● 少做多玩 :)
  97. 97. References● Yukuans Blog: Be Pythonic -- 字正腔圓說Python● How to Write "Pythonic" Code, Arndts talk● Code Like a Pythonista: Idiomatic Python, David Goodger● What can meta class do for you, Chen Hsin-Yi● Python Type and Object, Chen Hsin-Yi
  98. 98. Thanks謝謝聆聽

×