Python高级
日常读和写python项目时遇到的常用的高级python知识。
1. import的用法
绝对导入,主要用于导入sys.path的包,以及运行入口文件导入自己的模块。
-
import module_name
-
Python会在两个地方寻找这个模块,第一是sys.path(通过运行代码
import sys; print(sys.path)
查看),所以对于安装好的库,我们直接import即可。第二个地方就是运行文件所在的目录。 -
可以作为module的文件类型有".py"、".pyo"、".pyc"、".pyd"、".so"、".dll"。
-
当我们向文件导入某个模块时,导入的是该模块中那些名称不以下划线(单下划线“_”或者双下划线“__”)开头的变量、函数和类。
-
-
from package_name import module_name
- 与第一种写法类似,Python会在sys.path和运行文件目录这两个地方寻找包,然后导入包中名为module_name的模块。
- package_name 指的就是文件夹名,包目录下为首的一个文件便是
__init__.py
。如果一个模块定义有列表__all__
,则from module import *
语句只能导入__all__
列表中存在的对象。
相对导入,主要用于非运行入口文件导入自定义模块
from . import module_name
- 导入和自己同目录下的模块。
from .package_name import module_name
- 导入和自己同目录的包的模块。
from .. import module_name
- 导入上级目录的模块。
from ..package_name import module_name
- 导入位于上级目录下的包的模块。
- 当然还可以有更多的
.
,每多一个点就多往上一层目录。
其他用法
from module_name import function_name, variable_name, class_name
- 有时候我们只想使用模块中的某些函数、某些变量、某些类,用这种写法就可以了。使用逗号可以导入模块中的多个元素。
2. 定义类
class ClassName(Base1,Base2):
在类的定义中,括号中的为父类。__init__ :
构造函数,在生成对象时调用。双下划线开头的为私有属性或私有方法。所有方法的第一个参数都为self
3. __call__
允许一个类的实例像函数一样被调用。实质上说,这意味着 x() 与 x.__call__() 是相同的。
4. __dict__
类的静态函数、类函数、普通函数、全局变量以及一些内置的属性都是放在类__dict__里的
对象的__dict__中存储了一些self.xxx的一些东西
一些内置的数据类型是没有__dict__属性的
5. __name__
__name__是python内置的属性。
- 对于一个python模块来说。当一个py文件自己运行时,__name__就是__main__,当这个文件作为模块被调用时,__name__就是文件的名字。
- 对于一个类来说,__name__就是类的名字。
6. 装饰器
@a_new_decorator
def a_function_requiring_decoration():
"""Hey you! Decorate me!"""
print("I am the function which needs some decoration to remove my foul smell")
以上代码的意思为
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
(其中,a_new_decorator的定义如下)
from functools import wraps
def a_new_decorator(a_func):
@wraps(a_func) # 可以让我们在装饰器里面访问在装饰之前的函数的属性,如参数列表、__name__等
def wrapTheFunction():
print("I am doing some boring work before executing a_func()")
a_func()
print("I am doing some boring work after executing a_func()")
return wrapTheFunction
装饰器可以是函数,也可以是类。
详解:https://www.runoob.com/w3cnote/python-func-decorators.html
7. @property
Python内置的@property
装饰器就是负责把一个方法变成属性调用的。这样就能既能检查参数,又可以用类似属性这样简单的方式来访问类的变量(而不需要调用set和get方法)。
使用:把一个getter方法变成属性,只需要加上@property
就可以了,此时,@property
本身又创建了另一个装饰器@score.setter
,负责把一个setter方法变成属性赋值。还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性。
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
# 运行结果
>>> s = Student()
>>> s.score = 60 # OK,实际转化为s.set_score(60)
>>> s.score # OK,实际转化为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
...
ValueError: score must between 0 ~ 100!
8. *args 和 **kwargs
当函数的参数数量不确定时,可以使用*args 和**kwargs,*args 没有key值,**kwargs有key值。
*args 可以接收元组(tuple),**kwargs可以接收字典。
def test_var_args(f_arg, *argv):
print("first normal arg:", f_arg)
for arg in argv:
print("another arg through *argv:", arg)
>>> test_var_args('yasoob', 'python', 'eggs', 5)
# 结果
first normal arg: yasoob
another arg through *argv: python
another arg through *argv: eggs
another arg through *argv: 5
# 接收元组
args = ('python', 'eggs', 5)
test_var_args('yasoob',*args)
def greet_me(**kwargs):
for key, value in kwargs.items():
print("{0} == {1}".format(key, value))
>>> greet_me(arg1=5,arg2="two")
arg1 == 5
arg2 == two
# 接收字典
kwargs = {"arg1": 5, "arg2": "two"}
greet_me(**kwargs)
9. partial函数
该函数的形式:
functools.partial(func[,*args][, **kwargs])
示例:
from functools import partial
def multiply(x, y):
return x * y
double = partial(multiply, y=2)
partial 接收函数 multiply 作为参数,固定 multiply 的参数 y=2,并返回一个新的函数给 double。
简单而言,partial 函数的功能就是:把一个函数的某些参数给固定住,返回一个新的函数。
10. map函数
map()是 Python 内置的高阶函数,它接收一个函数 functon 和一系列可迭代对象(list, set, dir, tuple, str等),并通过把函数 function 依次作用在 iterable 的每个元素上,得到一个新的 map对象(map object at …)并返回。对于新的map对象,可用list(map_obj)或tuple(map_obj)转化为想要的数据类型。
示例:
def square(x) : # 计算平方数
return x ** 2
>>>map(square, [1,2,3,4,5]) # 计算列表各个元素的平方
[1, 4, 9, 16, 25]
11. zip函数
zip()
函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。
在 Python 3.x 中为了减少内存,zip() 返回的是一个对象。如需展示列表,需手动 list() 转换。
示例:
>>>a = [1,2,3]>>> b = [4,5,6]>>> c = [4,5,6,7,8]>>> zipped = zip(a,b) # 打包为元组的列表[(1, 4), (2, 5), (3, 6)]>>> zip(a,c) # 元素个数与最短的列表一致[(1, 4), (2, 5), (3, 6)]>>> zip(*zipped) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式[(1, 2, 3), (4, 5, 6)]
12. Typehint
typehint指为函数的参数和返回值设置数据类型。为函数写上typehint不仅可以增加代码的可读性,结合mypy进行静态类型检查还可以增加代码的鲁棒性。
对于输入类型的typehint,提供以下示例:
from typing import Union
from typing import Optional
a: int = 1
b: float = 0.5
c: Union[int, float] = 0.5
l: List[int] = [1, 2]
t: Tuple[int, int] = (1, 2)
n: Optional[str] = None # 除了None,只能是str
func: Callable # 参数为可调用的函数
对于返回值的typehint,示例如下:
def myadd(a: int, b: int) -> int:
return a+b
13. 数组切片
除了数字、冒号之外,数组的索引还可以是None
,None代表新增加一个维度,None放在哪一维,就会在哪一维上出现新的维度。
...
只能用于numpy的数组,而不能用于python自带的list
它是省略所有的冒号来用省略号代替,a[:, :, None]和a[…, None]的输出是一样的,就是因为…代替了前面两个冒号。