To be a Pythonista

1. assert

syntax: assert expression1 [",", expression2]
大致相当于
if __debug__:if not expression1:raise AssertionError(expression2)

例子1

def apply_discount(product, discount):price = int(product['price'] * (1.0 - discount))assert 0 <= price <= product['price']return price

例子2

if cond == 'x':do_x()
elif cond == 'y':do_y()
else:assert False, ('This should never happen, 如果出现Heisenbug, 可以用这样的方式去debug)

注意事项1: 可以用python -O .py去关闭assert, 所以assert只是辅助debugging, 而不能发现run-time errors

# 如果关闭assert, 很危险
def delete_product(prod_id, user):assert user.is_admin(), 'Must be admin'assert store.has_product(prod_id), 'Unknown product'store.get_product(prod_id).delete()

应该改为

def delete_product(product_id, user):if not user.is_admin():raise AuthError('Must be admin to delete')if not store.has_product(product_id):raise ValueError('Unknown product id')   store.get_product(product_id).delete()

注意事项2: assert后面跟元祖, 永远为true. 不过python3会有提示

def hello_assert():assert (1==2, 'This should fail')# SyntaxWarning: assertion is always true, perhaps remove parentheses?

2. String literal concatenation

这样就可以不用续行符了

my_str = ('This is a super long string constant ''spread out across multiple lines. ''And look, no backslash characters needed!')

双刃剑. Python’s string literal concatenation feature can work to your benefit, or introduce hard-to-catch bugs.

另外, 最好在容器最后的元素加上逗号

names = ['Alice','Bob','Dilbert',
]

3. Context manager. 上下文管理器

有基于Class(实现__enter__, __exit__)或者contextlib这个库和生成器

例子1. 基于Class

Class ManagedFile:def __init__(self, name):self.name = namedef __enter__(self):self.file = open(self.name, 'w')return self.filedef __exit__(self, exc_type, exc_val, exc_tb):if self.file:self.file.close()with ManagedFile('hello.txt') as f:f.write('hello, world\n')f.write('bye now\n')

例子2. 基于contextlib.contextmananger和generator-based factory function

from contextlib import contextmanager@contextmanager
def managed_file(name):try:f = open(name, 'w')yield ffinally:f.close()with managed_file('hello.txt') as f:f.write('hello, world\n')f.write('bye now\n')

例子3

what if the “resource” we wanted to manage was text indentation levels in some kind of report generator program

class Indenter:def __init__(self):self.level = -1def __enter__(self):self.level += 1return selfdef __exit__(self, exc_type, exc_val, exc_tb):self.level -= 1def print(self, text):print('  ' * self.level + text)with Indenter() as indent:indent.print('h1!')with indent:indent.print('hello')with indent:indent.print('bonjour')indent.print('hey')

练习1. 计算程序需要耗费的时间(还可以基于修饰器)

个人理解如果Timer基于context manager的话,可以计算一个context里多个函数的耗费时间, 而修饰器只能计算被修饰函数的耗费时间.

# 基于Class
import timeclass Timer:def __init__(self):self.start_time = 0def __enter__(self):self.start_time = time.time()def __exit__(self, exc_type, exc_val, exc_tb):end_time = time.time()print(end_time - self.start_time)with Timer() as timer:print('******' * 30)
# 基于contextlib.contextmanager和生成器
import time
from contextlib import contextmanager@contextmanager
def timer():try:start_time = time.time()yield finally:end_time = time.time()print(end_time - start_time)def do_something():time.sleep(2)with timer():do_something()

4. Underscores, Dunders, and More

看PEP8

• Single Leading Underscore: var
• Single Trailing Underscore: var

• Double Leading Underscore: __var
• Double Leading and Trailing Underscore: __var__
• Single Underscore: _

name mangling中要注意的点

_MangledGlobal__mangled = 23class MangledGlobal:def test(self):return __mangledMangledGlobal().test() # 23

5. A Shocking Truth About String Formatting

假设有两个变量

>>> errno = 50159747054
>>> name = 'Bob'

字符串格式化1, old style, 使用%

“old style” formatting has been de-emphasized, it hasn’t been deprecated.

'Hello %s' % name# 还可以加上format specifiers去控制输出的字符串
'%x' % errno # 输出16进制# 注意"#"只接收一个参数,所以多参数要包在一个tuple里
>>> 'Hey %s, there is a 0x%x error!' % (name, errno)
'Hey Bob, there is a 0xbadc0ffee error!

支持mapping

>>> 'Hey %(name)s, there is a 0x%(errno)x error!' % {
... "name": name, "errno": errno }
'Hey Bob, there is a 0xbadc0ffee error!'

字符串格式化2, new style, format()

>>> 'Hello, {}'.format(name)
'Hello, Bob'>>> 'Hey {name}, there is a 0x{errno:x} error!'.format(
... name=name, errno=errno)
'Hey Bob, there is a 0xbadc0ffee error!'

starting with Python 3.6 there’s an even better way to format your strings

字符串格式化3, f''

Python 3.6 adds yet another way to format strings, called Formatted String Literals

>>> f'Hello, {name}!'
'Hello, Bob!'>>> a = 5
>>> b = 10
>>> f'Five plus ten is {a + b} and not {2 * (a + b)}.'
'Five plus ten is 15 and not 30.'>>> def greet(name, question):
...         return f"Hello, {name}! How's it {question}?"
...
>>> greet('Bob', 'going')
"Hello, Bob! How's it going?"# 差不多相等
>>> def greet(name, question):
...         return ("Hello, " + name + "! How's it " +question + "?")
The real implementation is slightly faster than that because it uses the
BUILD_STRING opcode as an optimization.14 But functionally they’re
the same:
>>> import dis
>>> dis.dis(greet)
2 0 LOAD_CONST 1 ('Hello, ')
2 LOAD_FAST 0 (name)
4 FORMAT_VALUE 0
6 LOAD_CONST 2 ("! How's it ")
8 LOAD_FAST 1 (question)
10 FORMAT_VALUE 0
12 LOAD_CONST 3 ('?')
14 BUILD_STRING 5
16 RETURN_VALUE
# f''同样支持format specifiers
>>> f"Hey {name}, there's a {errno:#x} error!"
"Hey Bob, there's a 0xbadc0ffee error!"# Python’s new Formatted String Literals are similar to the JavaScript Template Literals added in ES2015.

字符串格式化4, Template Strings

It’s a simpler and less powerful mechanism.

>>> from string import Template
>>> t = Template('Hey, $name!')
>>> t.substitute(name=name)
'Hey, Bob!'
# Another difference is that template strings don’t allow format specifiers.
>>> templ_string = 'Hey $name, there is a $error error!'
>>> Template(templ_string).substitute(
... name=name, error=hex(errno))
'Hey Bob, there is a 0xbadc0ffee error!'# In my opinion, the best use case for template strings is when you’re handling format strings generated by users of your program. Due to their reduced complexity, template strings are a safer choice
# 有安全隐患的
>>> SECRET = 'this-is-a-secret'
>>> class Error:def __init__(self):pass
>>> err = Error()
>>> user_input = '{error.__init__.__globals__[SECRET]}'
# Uh-oh...
>>> user_input.format(error=err)
'this-is-a-secret'# Template String is much safer
>>> user_input = '${error.__init__.__globals__[SECRET]}'
>>> Template(user_input).substitute(error=err)
ValueError:
"Invalid placeholder in string: line 1, col 1"

Dan’s Python String Formatting Rule of Thumb:

If your format strings are user-supplied, use Template
Strings to avoid security issues. Otherwise, use Literal
String Interpolation if you’re on Python 3.6+, and “New
Style” String Formatting if you’re not.

6. “The Zen of Python” Easter Egg

Tim Peters’ Zen of Python

import this

Chapter 3 Effective Functions

7. Python’s Functions Are First-Class Citizens. 函数是一等公民

Python’s functions are first-class objects. You can assign them to variables, store them in data structures, pass them as arguments to other functions, and even return them as values from other functions.

假设

def yell(text):return text.upper() + '!'>>> yell('hello")
'HELLO!'

Functions are objects

# It takes the function object referenced by yell and creates a second name, bark, that points to it
bark = yell>>> bark('woof')
'WOOF!'# Function objects and their names are two separate concerns.(A variable pointing to a function and the function itself are really two separate concerns)
>>> del yell
>>> yell('hello?')
NameError: "name 'yell' is not defined"
>>> bark('hey')
'HEY!'# By the way, Python attaches a string identifier to every function at creation time for debugging purposes. You can access this internal
# identifier with the __name__ attribute
>>> bark.__name__
'yell'

Functions Can Be Stored in Data Structures. 函数可以存储在数据结构中

>>> funcs = [bark, str.lower, str.capitalize]
>>> funcs
[<function yell at 0x10ff96510>,
<method 'lower' of 'str' objects>,
<method 'capitalize' of 'str' objects>]>>> for f in funcs:
...        print(f, f('hey there'))
<function yell at 0x10ff96510> 'HEY THERE!'
<method 'lower' of 'str' objects> 'hey there'
<method 'capitalize' of 'str' objects> 'Hey there'>>> funcs[0]('heyho')
'HEYHO!'

Functions Can Be Passed to Other Functions. 函数可以传递给另外一个函数

Functions that can accept other functions as arguments are also called higher-order functions. They are a necessity for the functional programming style.

def greet(func):greeting = func('Hi, I am a Python program')print(greeting)>>> greet(bark)
'HI, I AM A PYTHON PROGRAM!'def whisper(text):return text.lower() + '...'
>>> greet(whisper)
'hi, i am a python program...'
# 典型的high order函数:map
>>> list(map(bark, ['hello', 'hey', 'hi']))
['HELLO!', 'HEY!', 'HI!']

Functions Can Be Nested 函数可以定义在另外一个函数里

def speak(text):def whisper(t):return t.lower() + '...'return whisper(text)
>>> speak('Hello, World')
'hello, world...'# 注意。Here’s the kicker though—whisper does not exist outside speak:
>>> whisper('Yo')
NameError:
"name 'whisper' is not defined"
>>> speak.whisper
AttributeError:
"'function' object has no attribute 'whisper'"
# 如果想访问内部函数怎么办?因为函数是一个对象,返回它就可以。
def get_speak_func(volume):def whisper(text):return text.lower() + '...'def yell(text):return rext.upper() + '!'if volume > 0.5:return yellelse:return whisperprint(get_speak_func(0.3))
print(get_speak_func(0.7))

Functions Can Capture Local State

Not only can functions return other functions, these inner functions can also capture and carry some of the parent function’s state with them. 闭包, lexical closures (or just closures, for short)

闭包解释

A closure remembers the values from its enclosing lexical scope even when the program flow is no longer in that scope.

闭包意义

In practical terms, this means not only can functions return behaviors but they can also pre-configure those behaviors

例子

def make_adder(n):def add(x):return x + nreturn addplus_3 = make_adder(3)
plus_5 = make_adder(5)print(plus_3(4))
print(plus_5(4))# In this example, make_adder serves as a factory to create and configure “adder” functions. Notice how the “adder” functions can still access the n argument of the make_adder function (the enclosing scope)

Objects Can Behave Like Functions

This is all powered by the call dunder method

class Adder:def __init__(self, n):self.n = ndef __call__(self, x):return self.n + x>>> plus_3 = Adder(3)
>>> plus_3(4)

8. Lambdas Are Single-Expression Functions

隐含return, 不用name绑定就可以用

add = lambda x, y: x + y
add(5, 3)(lambda x, y: x + y)(5, 3)

Lambdas You Can Use, 排序的时候

>>> tuples = [(1, 'd'), (2, 'b'), (4, 'a'), (3, 'c')]
>>> sorted(tuples, key=lambda x: x[1])
[(4, 'a'), (2, 'b'), (3, 'c'), (1, 'd')]>>> sorted(range(-5, 6), key=lambda x: x * x)
[0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]

Just like regular nested functions, lambdas also work as lexical closures. Lambda可以是闭包,也即是一个沙盒。

def make_adder(n):return lambda x: x + nplus_3 = make_adder(3)
plus_5 = make_adder(5)print(plus_3(4))
print(plus_5(4))

应该少用lambda

因为可读性和维护性差。Always ask yourself: Would using a regular (named) function or a list comprehension offer more clarity?

# Harmful:
>>> class Car:
...         rev = lambda self: print('Wroom!')
...         crash = lambda self: print('Boom!')
>>> my_car = Car()
>>> my_car.crash()
'Boom!'
# Harmful:
>>> list(filter(lambda x: x % 2 == 0, range(16)))
[0, 2, 4, 6, 8, 10, 12, 14]
# Better:
>>> [x for x in range(16) if x % 2 == 0]
[0, 2, 4, 6, 8, 10, 12, 14]

9. The Power of Decorators

可以用在以下情景

logging 日志
enforcing access control and authentication 访问与授权控制
计算耗费的时间
限流
缓存等等

基本

def uppercase(func):def wrapper():original_result = func()modified_result = original_result.upper()return modified_resultreturn wrapper@uppercase
def greet():return 'Hello!'
>>> greet()
'HELLO!'

多个装饰器

def strong(func):def wrapper():return '<strong>' + func() + '</strong>'return wrapperdef emphasis(func):def wrapper():return '<em>' + func() + '</em>'return wrapper@strong
@emphasis
def greet():return 'Hello!'>>> greet()
'<strong><em>Hello!</em></strong>'# 相当于 decorated_greet = strong(emphasis(greet))

修饰带参数的函数

def trace(func):def wrapper(*args, **kwargs):print(f'TRACE: calling {func.__name__}() 'f'with {args}, {kwargs}')original_result = func(*args, **kwargs)print(f'TRACE: {func.__name__}() 'f'returned {original_result!r}')return original_resultreturn wrapper@trace
def say(name, line):return f'{name}: {line}'print(say('Jane', 'Hello World'))

保持被修饰函数的metadata

import functoolsdef uppercase(func):@functools.wraps(func)def wrapper():return func().upper()return wrapper@uppercase
def greet():"""Return a friendly greeting"""return 'hello!'print(greet.__name__)
print(greet.__doc__)
print(greet())


10. 关于*args, **kwargs
They allow a
function to accept optional arguments, so you can create flexible APIs in your modules and classes

def foo(required, *args, **kwargs):print(required)if args:print(args)if kwargs:print(kwargs)>>> foo()
TypeError:
"foo() missing 1 required positional arg: 'required'"
>>> foo('hello')
hello
>>> foo('hello', 1, 2, 3)
hello
(1, 2, 3)
>>> foo('hello', 1, 2, 3, key1='value', key2=999)
hello
(1, 2, 3)
{'key1': 'value', 'key2': 999}

Forwarding Optional or Keyword Arguments(Function Argument Unpacking)

用*或**去unpack参数,传递给另外一个函数

def foo(x, *args, **kwargs):kwargs['name'] = 'Alice'new_args = args + ('extra', )bar(x, *new_args, **kwargs)

This technique can be useful for subclassing and writing wrapper functions.

class Car:def __init__(self, color, mileage):self.color = colorself.mileage = mileageclass AlwaysBlueCar(Car):def __init__(self, *args, **kwargs):super().__init__(*args, **kwargs)self.color = 'blue'>>> AlwaysBlueCar('green', 48392).color
'blue'

缺点就是接口不明确,传啥参数要看父类。所以一般不在自己写的类继承结构中(自己清楚接口的类)用。用在继承外部类(一些你不能控制、不清楚的类)中使用。但是在修饰器中,非常有用(维护性好)。

import functools
def trace(f):@functools.wraps(f)def decorated_function(*args, **kwargs):print(f, args, kwargs)result = f(*args, **kwargs)print(result)return decorated_function@trace
def greet(greeting, name):return '{}, {}!'.format(greeting, name)>>> greet('Hello', 'Bob')
<function greet at 0x1031c9158> ('Hello', 'Bob') {}
'Hello, Bob!'
With techniques like this one, it’s sometimes difficult to balance the
idea of making your code explicit enough and yet adhere to the Don’t
Repeat Yourself (DRY) principle. This will always be a tough choice to
make. If you can get a second opinion from a colleague, I’d encourage
you to ask for one.

例子 * unpack iterable, ** unpack dict

def print_vector(x, y, z):print('<%s, %s, %s>' % (x, y, z))tuple_vec = (1, 0, 1)
print_vector(*tuple_vec)>>> genexpr = (x * x for x in range(3))
>>> print_vector(*genexpr)dict_vec = {'y': 0, 'z': 1, 'x': 1}
>>> print_vector(**dict_vec)
<1, 0, 1>

11.关于函数的return. Python是隐式return None

默认return None

def foo1(value):if value:return valueelse:return Nonedef foo2(value):"""Bare return statement implies `return None`"""if value:return valueelse:returndef foo3(value):"""Missing return statement implies `return None`"""if value:return valuetype(foo3(0))
<class 'NoneType'># 作者建议如果一个函数不用return, 就不写return None. 这是一个Python core feature.

Chapter 4: Classes & OOP

12. 对象比较"is" vs "=="

is 比较引用是否指向同一个对象
== 比值

13. repr和str

class Car:def __init__(self, color, mileage):self.color = colorself.mileage = mileagedef __repr__(self):return '__repr__ for Car'def __str(self):return '__str__ for Car'>>> my_car = Car('red', 37281)
>>> print(my_car)
__str__ for Car
>>> '{}'.format(my_car)
'__str__ for Car'
>>> my_car
__repr__ for Car
Interestingly, containers like lists and dicts always use the result of
__repr__ to represent the objects they contain. Even if you call str
on the container itself:str([my_car])
'[__repr__ for Car]'
By the way, some people refer to Python’s “dunder” methods as
“magic methods.” But these methods are not supposed to be magical
in any way. The fact that these methods start and end in double
underscores is simply a naming convention to flag them as core
Python features.

差异

import datetime
today = datetime.date.today()
>>> str(today)
'2017-02-02'>>> repr(today)
'datetime.date(2017, 2, 2)'# __repr__ is for developers,  __str__ is for user. --- StackOverflow 

应该如何用

If you don’t add a __str__ method, Python falls back on the result
of __repr__ when looking for __str__. Therefore, I recommend that
you always add at least a __repr__ method to your classes.def __repr__(self):return (f'{self.__class__.__name__}('f'{self.color!r}, {self.mileage!r})')>>> repr(my_car)
'Car(red, 37281)'
class Car:def __init__(self, color, mileage):self.color = colorself.mileage = mileagedef __repr__(self):return (f'{self.__class__.__name__}({self.color!r}, {self.mileage!r})')def __str__(self):return f'a {self.color} car'car = Car('Red', 44444)
print(car)
print(repr(car))


14. Defining Your Own Exception Classes 自定义异常

Why

# 令stack trace更加清晰, 对debug更加友好
# 更好维护
# 例如比单纯地raise ValueError更好
class NameTooShortError(ValueError):passdef validate(name):if len(name) < 10:raise NameTooShortError(name)print(validate('allen'))

class BaseValidationError(ValueError):passclass NameTooShortError(BaseValidationError):passclass NameTooLongError(BaseValidationError):passtry:validate(name)
except BaseValidationError as err:handle_validation_error(err)

15. Cloning Objects. 复制(拷贝、克隆)对象

对于mutable objects(可变对象), 有时需要克隆整个对象。意义在于修改克隆出来的对象,而不修改原来的对象。

对于列表,字典,集合这些Python's built-in collections可以通过它们的工厂函数去克隆它们

# 注意,这是shallow copies.
new_list = list(original_list)
new_dict = dict(original_dict)
new_set = set(original_set)

浅复制,深复制

A shallow copy means constructing a new collection object and then
populating it with references to the child objects found in the original.
In essence, a shallow copy is only one level deep. The copying process
does not recurse and therefore won’t create copies of the child objects
themselves.

浅复制例子

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs) # Make a shallow copy>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]

深复制例子

>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
>>> zs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

复制(浅复制,深复制)任意对象,包括自定义类

浅复制对象

# 在这个例子中,因为用primitive types(基本类型)int去定义坐标,所以这个例子中浅复制和深复制没区别
import copyclass Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Point({self.x!r}, {self.y!r})'# 用copy.copy浅复制
a = Point(23, 42)
b = copy.copy(a)print(a is b)    #False
print(id(a), id(b)) 

深复制对象之前,再谈浅复制

# 在这个例子中,Rectangle用Point去作为坐标,这样就需要深复制
import copyclass Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Point({self.x!r}, {self.y!r})'class Rectangle:def __init__(self, topleft, bottomright):self.topleft = topleftself.bottomright = bottomrightdef __repr__(self):return (f'Rectangle({self.topleft!r}, {self.bottomright!r})')rect = Rectangle(Point(0, 1), Point(5, 6))
# 浅复制
shallow_rect = copy.copy(rect)print(rect is shallow_rect) # False
print(rect.topleft is shallow_rect.topleft) # True>>> rect.topleft.x = 999
>>> rect
Rectangle(Point(999, 1), Point(5, 6))
>>> srect
Rectangle(Point(999, 1), Point(5, 6))

深复制

import copyclass Point:def __init__(self, x, y):self.x = xself.y = ydef __repr__(self):return f'Point({self.x!r}, {self.y!r})'class Rectangle:def __init__(self, topleft, bottomright):self.topleft = topleftself.bottomright = bottomrightdef __repr__(self):return (f'Rectangle({self.topleft!r}, {self.bottomright!r})')rect = Rectangle(Point(0, 1), Point(5, 6))
shallow_rect = copy.deepcopy(rect)print(rect is shallow_rect) # False
print(rect.topleft is shallow_rect.topleft) # False

更深入复制

看copy模块
For example, objects can control
how they’re copied by defining the special methods __copy__() and
__deepcopy__() on them. 

总结

浅复制复制第一层,第一层独立。
深复制复制所有层,完全和原来的对象独立。

16. Abstract Base Classes 抽象类

Why使用抽象类。如果没有抽象类,如何实现相关的接口。

这个例子的坏处就是当调用的时候才得到error

class Base:def foo(self):raise NotImplementedError()def bar(self):raise NotImplementedError()class Concrete(Base):def foo(self):return 'foo called'c = Concrete()
c.foo()
c.bar() # NotImplementedError

更安全的做法是使用abc模块。令类继承结构更加可维护。

from abc import ABCMeta, abstractclassmethodclass Base(metaclass=ABCMeta):@abstractclassmethoddef foo(self):pass@abstractclassmethoddef bar(self):passclass Concrete(Base):def foo(self):passc = Concrete()


17. Namedtuples. 命名元组

namedtuple是tuple的拓展。

namedtuple解决tuple只能通过index访问、元祖内元素是随机的问题(例如很难去确定两个tuple拥有相同的元素和个数)。可提高可读性。

from collections import namedtupleCar1 = namedtuple('Car1', 'color mileage')
Car2 = namedtuple('Car2', ['Color','mileage'
])my_car = Car1('red', 44444)# 特点1. 可通过元素名访问
print(my_car.color)
print(my_car.mileage)>>> color, mileage = my_car1
>>> print(color, mileage)
red 44444
>>> print(*my_car)
red 44444# 特点2. 和元组一样。是不可变的。
>>> my_car.color = 'blue'
AttributeError: "can't set attribute"

namedtuples are a memoryefficient shortcut to defining an immutable class in Python manually.

即namedtuple是基于class的。所以可以继承它。但这个例子little clunky

Car = namedtuple('Car', 'color mileage')class MyCarWithMethods(Car):def hexcolor(self):if self.color == 'red':return '#ff0000'else:return '#000000'>>> c = MyCarWithMethods('red', 1234)
>>> c.hexcolor()
'#ff0000'#  It might be worth doing if you want a class with immutable properties, but it’s also easy to shoot yourself in the foot here

The easiest way to create hierarchies of namedtuples is to use the base tuple’s _fields property:

Car = namedtuple('Car', 'color mileage)
ElectricCar = namedtuple('ElectricCar', Car._fields + ('charge',))>>> ElectricCar('red', 1234, 45.0)
ElectricCar(color='red', mileage=1234, charge=45.0)

built-in helper methods。 内置的工具方法

namedtuple的built-in helper methods是以_开头。众所周知,_开头的方法是非公开接口。但是这里为了不和自定义的变量名冲突而在前面加_, 所以放心使用_开头的方法。它们是namedtuple的公共接口。

>>> my_car._asdict()
OrderedDict([('color', 'red'), ('mileage', 3812.4)])>>> json.dumps(my_car._asdict())
'{"color": "red", "mileage": 3812.4}'>>> my_car._replace(color='blue')
Car(color='blue', mileage=3812.4)>>> Car._make(['red', 999])
Car(color='red', mileage=999)

什么时候用

Using namedtuples over unstructured tuples and dicts can also make
my coworkers’ lives easier because they make the data being passed
around “self-documenting” (to a degree).On the other hand, I try not to use namedtuples for their own sake if
they don’t help me write “cleaner” and more maintainable code. Like
many other techniques shown in this book, sometimes there can be
too much of a good thing.However, if you use them with care, namedtuples can undoubtedly
make your Python code better and more expressive.

18. Class vs Instance Variable Pitfalls 类变量和实例变量的缺陷

# Class variables are for data shared by all instances of a class.class Dog:num_legs = 4 # <- Class variabledef __init__(self, name):self.name = name # <- Instance variable>>> jack = Dog('Jack')
>>> jill = Dog('Jill')
>>> jack.name, jill.name
('Jack', 'Jill')

缺陷1

实例中的__class__中的类变量不同步,因为这种行为会创造一个与类变量相同名字的变量(浅复制)

>>> jack.num_legs, jack.__class__.num_legs
(6, 4)

缺陷2

# Good
class CountedObject:num_instances = 0def __init__(self):self.__class__.num_instances += 1>>> CountedObject.num_instances
0
>>> CountedObject().num_instances
1
>>> CountedObject().num_instances
2
>>> CountedObject().num_instances
3
>>> CountedObject.num_instances
3
# 这里有bug, 注意construtor
class BuggyCountedObject:num_instances = 0def __init__(self):self.num_instances += 1 # !!!>>> BuggyCountedObject.num_instances
0
>>> BuggyCountedObject().num_instances
1
>>> BuggyCountedObject().num_instances
1
>>> BuggyCountedObject().num_instances
1
>>> BuggyCountedObject.num_instances
0原因: “shadowed” the
num_instance class variable by creating an instance variable of the
same name in the constructor.

19. Instance, Class, and Static Methods Demystified 实例方法、类方法、静态方法

class MyClass:# self访问实例本身def method(self):return 'instance method called', self# cls访问类本身@classmethoddef classmethod(cls):return 'class method called', cls@staticmethoddef staticmethod():return 'static method called'm = MyClass()
print(m.method())
print(m.classmethod())
print(m.staticmethod())

Chapter 5 Common Data Structures in Python

转载于:https://www.cnblogs.com/allen2333/p/10400379.html

读书笔记, Python - python-tricks-buffet-awesome-features相关推荐

  1. 读书笔记——《Python编程从入门到实践》第二章

    读书笔记--<Python编程从入门到实践>第二章 读书笔记--<Python编程从入门到实践>第二章 变量 如何使用变量 如何规范变量命名 字符串 字符串是什么 如何修改字符 ...

  2. 【读书笔记】Python编程:从入门到实践-埃里克·马瑟斯,python基础体系巩固和常见场景练习

    [概述] 书名:Python编程:从入门到实践 作者:埃里克·马瑟斯 日期:2021年09月01日 读书用时:1632页,100小时,27个笔记 [读书笔记] ◆ 第4章 操作列表 >> ...

  3. 【读书笔记】Python网络爬虫从入门到实践(第2版)-唐松,爬虫基础体系巩固和常见场景练习

    [概述] 书名:Python网络爬虫从入门到实践(第2版) 作者:唐松 日期:2021年08月01日 读书用时:1568页,100小时,59个笔记 [读书笔记] ◆ 1.2 网络爬虫是否合法 爬虫协议 ...

  4. 【读书笔记】Python编程-基础知识和案例讲解,“笨办法”学Python 3_2020.02.15

    [概述] --书名:"笨办法"学Python 3 --作者:泽德 A.肖 --日期:2020年02月15日 --大事件记录: 截至2月14日24时,据31个省(自治区.直辖市)和新 ...

  5. 读书笔记 -《Python 黑帽子》 ( 一 )

    读书笔记系列文章 一直都在读书,读了忘,忘了再读.不如把每次学到的东西都写下来 简介 内容不错,大部分领域都是浅尝而止,有种师傅领进门,修行看个人的感觉.就是书的排版有点问题,书一共不到200页,粘贴 ...

  6. 读书笔记 -《Python 黑帽子》 ( 三 )

    读书笔记系列文章 一直都在读书,读了忘,忘了再读.不如把每次学到的东西都写下来 第四章 Scapy: 网络的掌控者 Scapy 的十分强大的,前两章的东西可以用 Scapy 用简单的几行代码就能实现. ...

  7. python空间分析_读书笔记——《python地理空间分析指南》

    本文为<Python地理空间分析指南(第2版)>的读书摘录,顺便挖个坑,进一步对python的几个包做学习整理. 本笔记的用途:了解python地理空间处理的技术框架和实现途径. 第三章 ...

  8. python编程从入门到实践读书笔记-《Python编程:从入门到实践》项目部分读书笔记(二)...

    鸽了一个暑假没有更新,现在趁着还没开学更一下.咕咕咕 上期作业: 请创建一个Django项目,命名为Blog,建不建立虚拟环境随便你,最后本地跑成了就行. 步骤: ①在需要创建工程的文件夹下打开cmd ...

  9. python即时标记_【Python】读书笔记:Python基础教程-项目1-即时标记

    功能:给文本添加HTML标记,使得到的文档能够在浏览器中显示并能作为一个网页使用. 要求: 输入不应包含人工代码或标签: 应能处理不同的块,比如标题.段落.列表项.内嵌文本(比如被强调的文本.URL等 ...

  10. python编程从入门到实践书中出错的地方_读书笔记「Python编程:从入门到实践」_10.文件和异常...

    10.1 从文件中读取数据 10.1.1 读取整个文件 with open(~) as object: contents=object.read() with open('C:/Users/jou/D ...

最新文章

  1. npj Microbiomes|细菌群落的整体涌现特性诱导了拟南芥的干旱抗性(一作解读)
  2. 太有缘!和同专业师兄同名同姓同年同月同日生还是同导师是什么体验?
  3. mysql新建备份在哪里_navicat for MySQL创建备份计划的详细流程
  4. python loop call soon_python3-asyncio 学习笔记 1 -- call_soon
  5. 《集体智慧编程》第二章(一)
  6. FineReport连接mysql8.0.16
  7. [转]Android Service Test——简单测试例子
  8. cocoapods的安装使用
  9. css权威指南 读书笔记
  10. 十大热门编程语言:不死 Java、不朽 C/C ++、新贵 Python
  11. hdu 1728 逃离迷宫
  12. 解决ESXi识别加密狗U盾的问题
  13. java closed_有关Java中isClosed()和isConnected()的一些误解
  14. 关于查看nginx的访问量的部分总结
  15. C++实现装饰者模式Decorator Pattern
  16. 混凝土试块送检要求与时间
  17. Rod-cutting(动态规划)
  18. 第一周 Web开发入门(中)
  19. 蓝桥杯NE555模块编程
  20. TUTK[MediaSDK][Android] 如何在android系统上实现后台编码功能

热门文章

  1. java线上培训机构排名前十,重要概念一网打尽!
  2. 通信原理 | 通信的基本概念和通信系统的组成
  3. 机器学习模型的评价指标和方法(附代码)
  4. HTML页面添加背景音乐
  5. 一键装机tomcat脚本
  6. vue + elemen可远程搜索select选择器的封装(思路及源码分享)
  7. JavaSE----2
  8. gzip and deflate
  9. 2017.06.15-2016.06.18回顾 loc/iloc/ix dataframe相关 oracle无自增去重 correl
  10. python入门图谱_Python入门基础教程图