1.被装饰的函数的关键字参数使用默认值时,装饰器在不定长关键字参数(**kwargs)中取不到这个参数
这是在开发过程中遇到的问题,探究后发现的。
示例:
先构造一个打印入参的装饰器和一个被装饰函数
1
2
3
4
5
6
7
8
9
10
def decorator(f):
def wrapper(*arg,**kwargs):
print("args:",args)
print("kwargs",kwargs)
return f(*args,**kwargs)
return wrapper
@decorator
def test(a,b,c=1,d=2,f=3):
print(a,b,c,d,e,f)
测试:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In [3]: test(1,2)
...:
---->args: (1, 2)
---->kwargs {}
in test: 1 2 1 2 3
In [4]: test(1,2,c=3)
...:
---->args: (1, 2)
---->kwargs {'c': 3}
in test: 1 2 3 2 3
In [5]: test(1,2,c=3,d=4,e=5)
...:
---->args: (1, 2)
---->kwargs {'c': 3, 'd': 4, 'e': 5}
in test: 1 2 3 4 5
在元类中使用__call__方法时也是如此:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class M(type):
def __init__(self, *args, **kwargs):
self.a = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwds):
print("-------", kwds)
return super().__call__(*args, **kwds)
class A(metaclass=M):
def __init__(self, a, b=1):
self.a = a
self.b = b
测试:
1
2
3
4
5
6
In [2]: a = A(1)
------- {}
In [3]: b = A(1, b=2)
...:
------- {'b': 2}
结论:装饰器获取入参或者元类预处理时,不定长关键字参数(keyword Variable Arguments)的字典里,如果没有显式地传递,默认值是获取不到。所有中途拦截到的参数都是实际传递的,不包括默认值,因为默认值本质上是方法的内在属性。如果要获取该值,只能去被装饰函数的元数据里取。在利用装饰器/元类开发时,要注意判断,否则会取到错误的None值。
2. -O 和 __debug__搭配使用,有优化效果
You can use the -O or -OO switches on the Python command to reduce the size of a compiled module. The -O switch removes assert statements, the -OO switch removes both assert statements and doc strings. Since some programs may rely on having these available, you should only use this option if you know what you’re doing. “Optimized” modules have an opt- tag and are usually smaller. Future releases may change the effects of optimization.
3. Iterator Types
有 __iter__ 方法只是iterable,而不是iterator,要升级必须有 __next__ 方法。即 __iter__方法必须返回一个iterator,可以是self,也可以是其他类
4. import 的细节
all packages are modules, but not all modules are packages.any module that contains a path attribute is considered a package.
During import, the module name is looked up in sys.modules and if present, the associated value is the module satisfying the import, and the process completes. However, if the value is None, then a ModuleNotFoundError is raised. If the module name is missing, Python will continue searching for the module.
Beware though, as if you keep a reference to the module object, invalidate its cache entry in sys.modules, and then re-import the named module, the two module objects will not be the same. By contrast, importlib.reload() will reuse the same module object, and simply reinitialise the module contents by rerunning the module’s code.
- module中没有__all__时,
from module import *不导单下划线开头的变量,但手动指明(import _a)可以导入- 有
__all__时,from module import *只导__all__中的变量,手动依然可以导所有。 - 如果
__all__中有不存在的变量,会在导包时报AttributeError: module '<module>' has no attribute '<attr>',__all__所在文件本身不会报错,即使-O也会报
from module import *只能在module层级用,在方法或类用会直接报SyntaxError: import * only allowed at module level
5. Data model相关
- int 类型范围无限,取决于内存空间
- float 机器级别的双精度浮点数,溢出由底层实现处理,python不支持单精度浮点数
- set类型中,1 和1.0 是一样的。数字类型都是这样
- dict
Dictionaries preserve insertion order, meaning that keys will be produced in the same order they were added sequentially over the dictionary. Replacing an existing key does not change the order, however removing a key and re-inserting it will add it to the end instead of keeping its old place. … Changed in version 3.7: Dictionaries did not preserve insertion order in versions of Python before 3.6. In CPython 3.6, insertion order was preserved, but it was considered an implementation detail at that time rather than a language guarantee.
__new__If
__new__()does not return an instance of cls, then the new instance’s init() method will not be invoked.__del__del xdoesn’t directly callx.__del__()— the former decrements the reference count for x by one, and the latter is only called when x’s reference count reaches zero.__hash__hash值一样,hash值一定一样The only required property is that objects which compare equal have the same hash value
If a class does not define an
__eq__()method it should not define a__hash__()operation either; if it defines__eq__()but not__hash__(), its instances will not be usable as items in hashable collections. If a class defines mutable objects and implements an__eq__()method, it should not implement__hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket). User-defined classes have__eq__()and__hash__()methods by default; with them, all objects compare unequal (except with themselves) andx.__hash__()returns an appropriate value such thatx == yimplies both thatx is yandhash(x) == hash(y). A class that overrides__eq__()and does not define__hash__()will have its__hash__()implicitly set to None. When the__hash__()method of a class is None, instances of the class will raise an appropriate TypeError when a program attempts to retrieve their hash value, and will also be correctly identified as unhashable when checkingisinstance(obj, collections.abc.Hashable). If a class that overrides__eq__()needs to retain the implementation of__hash__()from a parent class, the interpreter must be told this explicitly by setting__hash__ = <ParentClass>.__hash__. If a class that does not override__eq__()wishes to suppress hash support, it should include__hash__ = Nonein the class definition. A class which defines its own__hash__()that explicitly raises aTypeErrorwould be incorrectly identified as hashable by anisinstance(obj, collections.abc.Hashable)call.__bool__未定义时调用__len__(),都没定义则该类所有实例判为true__missing__用于dict缺项时
6.with as语句的逻辑
根据PEP 343的解释,with…as…会被翻译成以下语句:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mgr = (EXPR)
exit = type(mgr).__exit__ # Not calling it yet
value = type(mgr).__enter__(mgr)
exc = True
try:
try:
VAR = value # Only if "as VAR" is present
BLOCK
except:
# The exceptional case is handled here
exc = False
if not exit(mgr, *sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally:
# The normal and non-local-goto cases are handled here
if exc:
exit(mgr, None, None, None)