7月24日收到的书,外观比较完整,书脊上略有一些磨损和褶皱,不过不影响阅读
按照之前的测评计划,今天分享一下对本书第一部分“Python编程”的相关内容,包含一、二、三章。
第一章的内容涵盖了Python的基础语法,包括变量定义、运算操作以及函数的使用。这些概念与其他编程语言有着共通之处,个人体验来说Python相对来说是比较好上手的。之前在使用Python时,常常也是通过官方文档可以找到详尽的语法说明和应用方法。
最近重点学习一下第二章面向对象的相关内容。在之前的项目实践中(大多数情况下是参考或者套用开源的Python代码),频繁地遇到类的定义和实例化,但对其中的深层原理并不十分了解。
通过对第二章内容的学习,理解了类的概念,尤其是建立了面向对象的编程思路。在之前的认知里,“类”无非也是一个类似函数的封装,把具有相同特性的一组变量同统一定义,来方便调用。现在有了更加系统的认识,它定义了一组具有相同属性和行为的对象的结构。每个类都可以看作是一个模板,用来创建具有相同特征的多个实例,同时将数据(属性)和行为(方法)封装在一起,保护了数据的完整性和安全性。
对于类,在之前的接触中其实就有几个不太理解的问题(以之前最常使用的基于torch.nn来定义神经网络的类为例,假定定义的类为myClass,其中需要传入几个参数如para_a, para_b, ...):
1. 为什么定义类的时候括号里写的是def myClass(nn.Module),但是调用的时候同样的myClass(para_a,para_b,...),括号里写的是需要传入的参数变量?
这是因为定义的类继承自python构建神经网络模块的基础类nn.Module,自定义的新类myClass继承了nn.Module中所有属性和方法,也可以根据自己的需求,增加定义新的属性和方法,来获得所需的新网络;而在后续的调用,实际上是基于定义好的类(模板)实例化一个具体的对象,需要给这个把参数传递给具体对象的构造器__init__。
2. 所有class在定义过程中都会有def __init__(self, para_a, para_b, ...)这个过程,是什么作用?
__init__为构造器,用于在创建类的新实例时,初始化对象的属性。其需要传入的这些参数用于具体实例对象的创建,参数列表中的第一个参数总是self,它代表当前的实例对象本身。
3. 使用def myClass(nn.Module)定义网络的类的时候,def __init__(self, para_a, para_b, ...)初始化参数总是需要在下边第一行写super(myClass, self).init()?
super()函数在用于调用父类的方法,因为自定义的类继承自nn.Module,需要确保父类被正确地初始化。
4. 初始化有一些参数会在def __init__ (self, para_a, para_b)里面定义,但是在同一类后续的新方法def func()中,不能通过直接的para_a来传递参数,需要使用self.para_a=para_a 在__init__步骤中先赋值,这是为什么?
在类的__init__方法中定义参数时,实际上是在为类的对象实例设置属性。当你写self.para_a=para_a时,你不仅仅是在执行一个赋值操作,你还在定义了一个属性para_a,这个属性与创建的对象相关联,并且存储在对象的实例字典中。如果在__init__方法之外直接使用para_a,Python解释器会认为它是一个局部变量,只在__init__的作用域内是可见的。如果尝试在其他方法中直接使用,会因为Python在当前方法的作用域找不到这个变量而报错。
5. 为什么init前后需要加__,而后面定义的那些方法不需要?
__开头和结尾的方法或属性被为特殊方法。这些方法通常不需要直接调用,而是由Python解释器在特定的情况下自动调用。如果类名为myClass,那么__init__方法实际上在类内部被改写为_myClass__init__。这样做同时也能防止子类不小心覆盖父类的特殊方法。
另外有一些之前没有接触过的新知识,帮助更好的定义和使用类:
1. 可以通过__str__(self, 'myString')的方法,控制对象实例在被print()函数调用时所展示的内容。这个方法允许输出特定的字符串,而不是默认的对象内存地址。例如,之前曾遇到过想试试通过print查看对象的结果,打印输出默认的内存地址<object at 0x10e9e1be0>之类的,可以定义__str__方法来提供更有意义的信息,如对象的状态或属性值。
2. 使用@property装饰器,可以为类的属性定义只读访问器,或者在设置属性值之前添加逻辑限制。这不仅增强了数据的安全性,还提供了一种优雅的方式来实现属性的验证和封装。
3. 使用@total_ordering装饰器,可以更高效地实现类实例之间的比较运算。这个装饰器允许只定义一部分比较方法,Python会自动提供其他的比较方法。
第三章高级编程另外还涉及比如Python闭包、其他的装饰器、迭代器和生成器。比较重要的是迭代器和生成器,它们是Python中实现惰性求值的强大工具。通过使用迭代器,可以遍历大量数据而无需一次性将它们全部加载到内存中。生成器则是一种特殊的迭代器,它在每次迭代时计算下一个值,从而有效避免了不必要的内存占用。这种按需计算的方式,不仅优化了性能,也提高了程序的可扩展性。
从之前的经验来看,这部分暂时会被使用到的不多。等后续涉及具体的项目时,再回头来查看作为进阶的内容。
有一些小错误,还希望作者和编辑再仔细校对。另外一些概念的讲解并不是很容易理解,前后逻辑顺序读着略有些混乱,阅读体验并不是很好。