a byte of python读后总结
A BYTE OF PYTHON
Python中万物皆对象
变量
对应在计算机内存开辟的部分空间,以便保存数据,赋值时不需要指定类型,可以随意改变(类似指针)。为了访问变量,用标识符取名。给变量赋值的数字和字符串都叫字面值常量。实际上赋值时是先创建对应数据类型的对象,再让变量引用(指向)它。复制序列或复杂对象时记得用切片[:]
数据类型
变量中存储的数据的类型:
-
数字(不可变)
- 整形
5 - 浮点
3.2352.3E-4
- 整形
-
复数
9.32e-36j -
字符串(不可变)
format()格式化方法-
print('{0} was {1} years old when he wrote this book'.format(name, age)):0、1可省略,name、age为变量 -
print('{name} was {age} years old when he wrote this book'.format(name=name, age=age)) -
print(f'{name} was {age} years old when he wrote this book')
-
-
列表(可变)
-
元组(可变)
一组字符串可以通过
链接字符串.join()合并成一个 -
字典(可变)
函数
函数参数
对于不可变类型数据的变量传递类似Java的值传递,可变的类似为引用传递。但严格来说都是传递了值(变量赋值时所对应的内存空间),只是在函数域内对不可变类型重新赋值时,会新开辟一个空间给局部变量,所以不会影响传进去的变量本身。
关键字参数
传实参的时候指明形参的名字func(1,a=2, c=3)
可变参数
*参数名:收集从该点到最后的所有位置参数以tuple形式传入**参数名:收集从该点到最后的所有关键字参数以dictionary形式传入
作用域
局部变量、全局变量的概念和其他语言差不多,如果在局部作用域内(函数、类)想用最外层变量(全局变量),要用global声明一下。最好少用,会使变量定义变得混乱。
模块
-
模块是复用的函数、类、变量的集合,可以用直接
.py文件编写后使用或者解释器的编写语言编写后编译后使用。 -
模块存放应该考虑目录的问题:如果是内置模块,解释器知道在哪找;如果不是,解释器会在
sys.path包含的目录列表中找(第一个是空的,表示当前目录(程序启动目录))。找到后会先将模块的代码第一次import时运行一次,这样在使用模块的文件中就可以使用模块的功能了。 -
字节码
.pyc文件:每次import太耗时耗力,将模块先编译成.pyc文件,使用时免去很多处理工作(python文件先转换为字节文件再变为原生机器语言) -
__name__是Python的内置变量,用于指代当前模块。当哪个模块被直接执行时,该模块__name__的值就是__main__,当被导入另一模块时,__name__的值就是模块的真实名称。通过__name__属性可以确定模块是单独跑的还是被载入,以此添加一些测试代码。if __name__ == '__main__': print('This program is being run by itself') else: print('I am being imported from another module')对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。C 和 C++ 都需要有一个 main 函数来作为程序的入口,也就是程序的运行会从 main 函数开始。同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。而 Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
包
包只是带有特殊__init__.py文件的模块文件夹,该文件向Python表明这个文件夹是特殊的,它包含Python模块。当import该目录时,就会执行__init.py__里的代码,因此可以用来控制模块的导入1.在该文件中指定默认import的模块,这样就不用一个一个导入模块了。(注意:执行import时当前目录是不会变得,所以需要输入完整的包名)。2.另外当使用 from xxxpackage import *时实际上是根据__init__.py里定义的__all__=['xxxmodule, 'yyymodule']变量
面向对象
变量
对象可以使用属于该对象的普通变量来存储数据。 属于对象或类的变量(对象变量:用self修饰;类变量:在所有函数外定义)称为字段
- 对象变量(实例属性):用
self修饰赋值,与类变量同名时会隐藏掉类变量(当然类变量声明后在函数也是用self.var访问的)。 - 类变量(类属性):
共享单车(不是)所有对象都能访问。在类定义中所有函数外定义
约定俗成:任何仅在类或对象中使用的变量都应该以双下划线开头,所有其他名称都是公共的。在内部,python使用一种 name mangling 技术,将
__membername替换成_classname__membername,所以你在外部使用原来的私有成员的名字时,会提示找不到。
self
对象方法的第一个形参必须为self(虽然实际上什么名字都行),调用时不需要给出该参数的值,Python自己会提供这个值(引用对象本身)(和C++、Java的this一样)myobject.method(arg1, arg2)➡MyClass.method(myobject, arg1, arg2)
同时self.__class__代表类的名字
__init__(self,...)
构造函数
方法
-
对象(实例)方法:没有修饰,最少包含一个self参数
-
类方法:
@classmethod修饰,它最少也要包含一个参数,通常将其命名为cls,Python 会自动将类本身绑定给cls参数(注意,绑定的不是实例对象)。可以访问类属性,无法访问实例属性 -
静态方法:
@staticmethod修饰,不需要特殊参数。无法访问类属性、实例属性。类的专有方法(可重载):
__init__: 构造函数,在生成对象时调用__del__: 析构函数,释放对象时使用__repr__: 打印,转换__setitem__: 按照索引赋值时调用__getitem__: 按照索引获取值时调用__len__: len()方法调用以获得序列长度__cmp__: 比较运算__call__: 函数调用__add__: 加运算__sub__: 减运算__mul__: 乘运算__truediv__: 除运算__mod__: 求余运算__pow__: 乘方
返回多个值可以用元组
继承
class Classname(Father1,Father2...)
为了使用继承,在类定义中的类名之后的元组中指定基类名。接下来,我们观察到使用 self 变量作为参数显式调用基类的__init__方法,这样我们就可以在子类中初始化实例的基类部分。因为如果子类中定义了 构造函数,所以 Python 不会自动调用基类的构造函数,您必须自己显式地调用它。
#多重继承
class sample(speaker,student):
a =''
def __init__(self,n,a,w,g,t):
student.__init__(self,n,a,w,g)
speaker.__init__(self,n,t)
命名空间及作用域
命名空间是从名称到对象的映射,大部分的命名空间都是通过Python字典实现的。
- 内置名称:Python 语言内置的名称,比如函数名 abs、char 和异常名称 BaseException、Exception 等等。
- 全局名称:模块中定义的名称,记录了模块的变量,包括函数、类、其它导入的模块、模块级的变量和常量。
- 局部名称:函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量。(类中定义的也是)
Python 的查找顺序为:局部的命名空间去 -> 全局命名空间 -> 内置命名空间。
命名空间的生命周期:取决于对象的作用域,如果对象执行完成,则该命名空间的生命周期就结束。因此,我们无法从外部命名空间访问内部命名空间的对象。
作用域就是一个 Python 程序可以直接访问命名空间的文字区域,即作用域限制了是否可以访问到对应命名空间内的东西。在一个 python 程序中,直接访问一个变量,会从内到外依次访问所有的作用域直到找到,否则会报未定义的错误。
L(Local):最内层,包含局部变量,比如一个函数/方法内部。x
E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。
G(Global):当前脚本的最外层,比如当前模块的全局变量。
B(Built-in): 包含了内建的变量/关键字等。,最后被搜索
规则顺序: L –> E –> G –>B。
注意:内层函数可以访问外层函数中定义的变量,但不能重新赋值,除非使用nolocal(闭包作用域)或global(全局作用域)
异常
python中异常没有catch,直接
try:
operations...;
except xxError:
operations...;
finally:
operations...;
try中获取的资源要在finally中释放,或者使用
with语句
with
with 语句使用了一个协议。它获取 open 语句返回的对象thefile。它总是在启动下面的代码块之前调用调用thefile.__enter__函数,在完成代码块之后调用thefile.__exit__函数。因此,我们在 finally 块中编写的代码应该由__exit__方法自动处理。
with open("poem.txt") as f:
for line in f:
print(line, end='')
其他
lambda
Lambda 语句用于创建新的函数对象。实际上,lambda 接受一个或几个参数,后面跟一个表达式,成为函数的主体,返回值就是该表达式的结果
- 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率
- lambda函数拥有自己的命名空间,且不能访问自有参数列表之外或全局命名空间里的参数。
points = [{'x': 2, 'y': 3},
{'x': 4, 'y': 1}]
points.sort(key=lambda i: i['y'])
print(points)
列表推导式
用于从现有列表生成新列表
listone = [2, 3, 4]
listtwo = [2*i for i in listone if i > 2]
装饰器
如果想要扩展一个函数的功能,并且不改变函数内部代码。很自然的,我们就会想到把这个函数以及增添功能所对应的代码包起来,然后这个新的函数就是原函数进化版。为了方便以及规范这种改造,可使用装饰器。装饰器函数的形数参是想要升级的函数,在装饰器函数中定义新函数(函数+添加的功能),并且返回新函数。
def log(func):
def wrapper(*args, **kw):
print('call %s():' % func.__name__)
return func(*args, **kw)
return wrapper
@log
def now():
print('2015-3-25')
如果装饰器还要传参数,将装饰器函数再包一层(三层)
def log(text):
def decorator(func):
def wrapper(*args, **kw):
print('%s %s():' % (text, func.__name__))
return func(*args, **kw)
return wrapper
return decorator
- 装饰器 @log 不带参数的情况下,实际上是直接调用
now = log(now) - 装饰器 @log 带参数的情况下,实际上是调用
now = log(text)(now) - 函数的
__name__属性会从原函数变为装饰器函数中的wrapper函数(返回就是这个函数)。import functools,在定义wrapper()的前面加上@functools.wraps(func)即可。 - 最内层函数一般return是因为防止内层函数return的值丢失,毕竟外面可能会用到。

浙公网安备 33010602011771号