流畅的python笔记(十九)动态属性和特性

目录

前言

一、使用动态属性转换数据

接下来示例中使用JSON格式数据源

使用动态属性访问JSON类数据

处理无效属性名

使用__new__方法以灵活的方式创建对象

使用shelve模块调整OSCON的JSON数据源的结构

使用特性获取链接的记录

二、使用特性验证属性

LineItem类第一版:表示订单中商品的类

LineItem类第二版:能验证值的特性

三、特性全解析

property类

特性会覆盖实例属性

特性的文档

四、定义一个特性工厂

五、处理属性删除操作

六、处理属性的重要属性和函数

影响属性处理方式的特殊属性

处理属性的内置函数

处理属性的特殊方法


前言

python中,数据的属性和处理数据的方法统称属性attribute,即方法只是可调用的属性。除了这二者之外,我们还可以创建特性property,在不改变类接口的前提下,使用存取方法(即读值方法和设值方法)修改数据属性。

        python使用点号访问属性时,比如obj.attr,python解释器会调用特殊的方法(如__getattr__和__setattr__)计算属性。用户自定义的类可以通过__getattr__方法实现虚拟属性,当访问不存在的属性时,即时计算属性的值。

        动态创建属性是一种元编程,框架的作者经常这么做。然而在python中相关的技术十分简单,任何人都可以使用。

一、使用动态属性转换数据

接下来示例中使用JSON格式数据源

图示JSON数据源中只列出了4条记录。整个数据集是一个JSON对象,里边有一个键"Schedule",这个键对应的值也是一个映像(相当于字典),有四个键:"conferences"、"events"、"speakers"和"venues"。这4个键对应的值都是一个记录列表,示例中各个列表中只有一条记录,每条记录都是一个字典。在完整的数据集中,列表中有成百上千条记录。不过"conferences"键对应的列表中只有一条记录。这四个列表中每条记录都有一个名为"serial"的字段,这是元素在各个列表中的唯一标识符。

        第一个脚本:下载JSON数据源。

  1.  如果需要下载,就发出提醒信息。
  2.  在with语句中使用两个上下文管理器,分别用于读取和保存远程文件。即把url的远程内容读取出来然后写入本地的JSON文件。
  3.  json.load函数解析JSON文件,返回python原生对象。在这个数据源中有这几种数据类型:dict、list、str、int。

有了以上代码,就可以审查JSON数据源中的任何字段:

  1.  feed = json.load(fp),feed是JSON的解析结果,feed本质是python的原生类型对象,即一个字典,里边嵌套着字典和列表,存储着字符串和整数。
  2.  列出"Schedule"键中的4个记录集合。
  3.  显示4个记录集合中的记录数量。
  4.  深入嵌套的字典和列表,获取最后一个演讲者的名字。
  5.  获取那位演讲者的编号。
  6.  每个事件都有一个'speakers'字段,列出0个或多个演讲者的编号。

使用动态属性访问JSON类数据

上边示例中feed字典要用feed['Schedule']['events'][40]['name']来获取到具体的某个字段值,这种句法很冗长。JavaScript中,可以使用feed.Schedule.events[40].name获取那个值。下面用python实现了一个FrozenJson类可达到同样效果,但是只支持读取数据,该类能递归,自动处理嵌套的字典和列表。

  1. 传入嵌套的字典和列表组成的raw_feed,创建一个FrozenJSON实例。
  2. FrozenJSON实例能使用属性表示法遍历嵌套的字典,这里我们speakers列表中的元素数量,其中的元素都是字典。
  3. 使用底层字典的方法,.keys(),获取字典中所有的键。
  4. 使用items方法,获取字典中各个元素组成的列表 [key, value],然后显示各个集合中的元素数量,这里的value是一个列表,列表中的各个元素都是字典。
  5. feed.Schedule.speakers仍是列表,但如果列表里的元素是映射,即speakers[-1]是映射,则会被转换成FrozenJSON对象。
  6. events列表中的40号元素是一个字典,现在变成了一个FrozenJSON实例。
  7. talk是events列表中的第40个元素,talk本质是字典,其有一个speakers键,对应值是列表。
  8. 读取不存在的属性会抛出KeyError异常,而不是通常抛出的AttributeError异常。

下边是FrozenJSON对象的实现:

  1. 使用mapping参数创建一个字典,作为FrozenJSON类的实例属性。这样做目的有二:一是确保传入的是字典或者能转成成字典的对象,二是为安全起见创建了一个副本。
  2. 仅当按实例属性---类属性---继承树搜寻不到指定名称的属性(数据属性和方法统称为属性)时才调用__getattr__方法。
  3. 如果name是FrozenJSON类的实例属性__data的属性,返回那个属性。
  4. 否则,从self.__data中获取name键对应的元素,返回调用FrozenJSON.build()方法得到的结果。
  5. 用@classmethod修饰的方法是类方法,经常用这种方法来实现一个备选构造方法,比如这里的build就是一个备选构造方法。
  6. 如果obj是映射,那么就构建一个FrozenJSON对象,
  7. 如果是MutableSequence对象,这里必然是列表,因此把列表obj中的每个元素递归地传给build方法,列表推导式构建出一个列表。
  8. 如果既不是字典也不是列表,那么原封不动地返回元素。

处理无效属性名

FrozenJSON类有个缺陷:没有对名称为python关键字地属性做特殊处理,比如以如下方式构建一个对象:

此时用grad.class是无法读取对应的值的,因为在python中class是保留字:

这个时候可以用getattr(grad, 'class')来读取对应的属性:

但是Frozen类的目的是为了便于用 '.' 来访问数据,因此更好的方法是检查传给FrozenJSON.__init__方法的映射中是否有键的名称是关键字,如果有,那么在键名后加上_,然后就可以通过以下方式读取了:

FrozenJSON类的__init__方法改成如下所示:

 

  1.  先导入keyword模块,然后用keyword.iskeyword()来判断某个键是不是python保留的关键字。

除了JSON对象中的键是不是python保留的关键字外还有一个问题,传入的键可能不是合法的标识符:

这种不合法的标识符在python3中很容易检测,因为str类提供了s.isidentifier()方法能判断s是否是有效的python标识符,但是把标识符变成有效的属性名不容易,有两种解决方案,一是抛出异常,二是把无效的键换成通用的名称,例如attr_0、attr_1等等。

 

使用__new__方法以灵活的方式创建对象

我们通常把__init__成为构造方法,但实际上用于构建实例的是特殊方法__new__:这是个类方法(使用特殊方式处理,因此不必使用@classmethod装饰器),必须返回一个实例。__new__返回的实例会作为第一个参数self传给__init__方法,调用__init__方法要传入实例,而且禁止返回任何值,所以__init__方法其实是初始化方法,真正的构造方法是__new__。一般情况下不需要自己编写__new__,因为从object类继承的实现已经够用了。python构建对象的过程可以用下面伪代码表示:

        __new__方法也可以返回其他类的实例,此时解释器不会调用__init__方法。可以把FrozenJSON类中的类方法build改成用__new__方法实现。

 

  1.  __new__是类方法,第一个参数是类本身,余下的参数与__init__方法一样,只不过没有self。
  2. 默认的行为是委托给超类的__new__方法,这里调用的是object基类的__new__方法,唯一的参数cls是FrozenJSON。
  3. __new__方法中余下的代码与原来的build一样。
  4. 这里之前调用的是FrozenJSON.build方法,现在只需调用FrozenJSON构造方法即可。

使用shelve模块调整OSCON的JSON数据源的结构

shelve.open高阶函数返回一个shelve.Shelf实例,这是简单的键值对象数据库,背后由dbm模块支持,具有以下特点:

  • shelve.Shelf是abc.MutableMapping的子类,因此提供了处理映射类型的重要方法。
  • shelve.Shelf类提供了几个管理IO的方法,如sync和close;它也是一个上下文管理器。
  • 只要把新值赋予键,就会保存键和值。
  • 键必须是字符串。
  • 值必须是pickle模块能处理的对象。

我们讲从JSON文件中读取所有记录,讲其存在一个shelve.Shelf对象中,键由记录类型和编号组成(例如'event.33590'或'speaker.3471'),而值是我们即将定义的Record类的实例。

        以下是schedule1.py脚本的doctest,主要工作由load_db函数完成:调用osconfeed.load方法读取JSON数据,把通过db传入的Shelf对象中的各条记录存储为一个个Record实例,这样处理之后获取演讲者的内容:speaker = db['speaker.3471']

  1. shelve.open函数打开现有的数据库文件,或者新建一个。
  2. 判断数据库是否填充的简便方法是,检查某个已知的键是否存在,这里检查的是conference.115,即conference记录的键。
  3. 如果数据库是空的,就调用load_db(db),加载数据。
  4. 获取一条speaker记录。
  5. speaker是Record类的实例。
  6. 各个Record实例都有一系列自定义的属性,对应于底层JSON记录里的字段。
  7. 一定要关闭shelve.Shelf对象,如果可以,使用with块确保Shelve对象会关闭。

 schedule1.py脚本的代码如下所示:

  1.  导入osconfeed模块,用于解析JSON文件,返回python原生对象。
  2.  这是使用关键字参数传入的属性构建实例的常用方式。因为__dict__属性中存储着实例的所有属性及对应值,这里直接传入映射对象来更新__dict__可以快速添加大量属性。
  3.  如果本地没有副本,从网上下载JSON数据源。
  4.  迭代Schedule关键字对应的值,该值也是个字典,其键包括'conferences'、'events'等。
  5.  record_type的值是去掉尾部's'后的名字,即把'events'变成'event'。
  6.  使用record_type和‘serial’字段构成key。
  7.  把'serial'字段的值设成完整的键。
  8.  构建Record实例,存储在数据库的key键名下。

使用特性获取链接的记录

下一版本目标:对于从Shelf对象中获取的event记录来说,读取它的venue或speakers属性时返回的不是编号,而是完整的对象。用法如下所示:

  1. DbRecord类扩展Record类,添加对数据库的支持:为了操作数据库,必须为DbRecord提供一个数据库的引用。
  2. DbRecord.fetch类方法能获取任何类型的记录。
  3. event时Event类的实例,而Event类扩展DbRecord类。
  4. event.venue返回一个DbRecord实例。
  5. 获取event.venue的名称。
  6. 还可以迭代event.speakers列表,获取表示各位演讲者的DbRecord对象。

本节使用的主要类如下:

  • Record,__init__方法与schedule1.py脚本中的一样,为了辅助测试,增加__eq__方法。
  • DbRecord,Record的子类,添加__db类属性,用于设置和获取__db属性的set_db和get_db静态方法,用于从数据库中获取记录的fetch类方法,以及辅助调试和测试的__repr__实例方法。
  • Event,DbRecord类的子类,添加了用于获取所链接记录的venue和speakers属性,以及特殊的__repr__方法。

DbRecord.__db被设置为私有类属性,然后定义了普通的读值与设值方法,以防不小心覆盖__db属性的值,之所以没有使用特性去管理__db属性,是因为:特性是用于管理实例属性的类属性。 即特性本身是类属性,但是是用来管理实例属性的。

  1. 导入inspect模块,在load_db函数中使用。
  2. 数据库文件。
  3. 定义__eq__方法。

 

  1. 自定义的异常通常是标志类,没有定义体。写一个文档字符串,说明异常的用途,比只写一个pass语句要好。
  2. DbRecord类扩展Record类。
  3. __db类属性存储一个打开的shelve.Shelf数据库引用。
  4. set_db是静态方法。
  5. 设置__dp属性。
  6. get_db是静态方法。
  7. fetch是类方法。
  8. 从数据库中获取ident键对应的记录。
  9. 弱捕获到TypeError异常,并且db变量的值是None,抛出自定义的异常,说明必须设置数据库。
  10. 否则重新抛出TypeError异常,因为我们不知道怎么处理。
  11. 如果记录有serial属性,在字符串表示形式中使用。
  12. 否则调用继承的__repr__方法。

  1. Event类扩展DbRecord类。
  2. 在venue特性中使用venue_serial属性构建key,然后传给继承自DbRecord类的fetch类方法。
  3. speakers特性检查记录是否有_speaker_objs属性。
  4. 如果没有,直接从__dict__实例属性中获取'speakers'属性的值,防止无线递归,因为这个特性的公开名称也是speakers。
  5. 获取fetch类方法的引用。
  6. 使用fetch获取speaker记录列表,然后赋值给self._speaker_objs。
  7. 返回前边获取的列表。
  8. 如果记录有name属性,在字符串表示形式中使用。
  9. 否则,调用继承的__repr__方法。

 

 

二、使用特性验证属性

我们已知使用@property装饰器可以实现只读特性,本节要创建一个可读写的特性。

LineItem类第一版:表示订单中商品的类

这个实现中,如果错误地把重量设为负值,则计算出的金额为负值。解决这个问题有两种方案,一是使用读值方法和设值方法管理weight属性,二是把数值属性换成特性。

LineItem类第二版:能验证值的特性

 

  1.  这里已经使用特性的设值方法了,确保所创建实例的weight属性不能为负值。
  2. @property装饰器修饰读值方法。
  3. 实现特性的方法,其名称与公开属性的名称一样------weight。
  4. 真正的值存储在私有属性__weight中。
  5. 被装饰的读值方法有个.setter属性,这个属性也是装饰器,这个装饰器把读值方法和设值方法绑定在一起。
  6. 如果值大于0,设置私有属性__weight。
  7. 否则,抛出ValueError异常。

三、特性全解析

property类

虽然内置的property经常用作装饰器,但它本质上是一个类。在python中,类和函数通常可以互换,因为二者都是都是可调用的对象(调用类即实例化一个对象),由于python没有实例化对象的new运算符,因此调用构造函数和调用工厂函数没有区别。只要能返回新的可调用对象,代替被装饰的函数,二者都可以用作装饰器。

由于@装饰器语法比property出现的晚,因此最早的时候都是通过把读值与设值函数传给property类的前两个参数来实现特性。

 

  1. 普通的读值方法。
  2. 普通的设值方法。
  3. 构造property对象,然后赋值给公开的类属性。

特性会覆盖实例属性

特性都是类属性(有点奇怪,特性中明明使用了self,却还是类属性),但是特性管理的是实例属性的存取

第一个例子:实例属性遮盖类属性

  1. 定义Class类,其有两个类属性:data数据属性和prop特性。
  2. vars函数返回对象obj的__dict__属性,结果显示没有实例属性。
  3. 读取obj.data,获取的是Class.data类属性的值。
  4. 为obj.data赋值,创建了一个实例属性。
  5. 用vars函数审查实例,查看实例属性。
  6. 再次读取obj.data,获取的是实例属性的值。即实例属性data遮盖了类属性data。
  7. Class.data的值完好无损。

第二个例子:实例属性不会遮盖类特性

  1.  直接从Class中读取prop特性,获取的是特性对象本身,不会运行特性的读值方法。
  2.  读取obj.prop会执行特性的读值方法。
  3.  尝试设置prop实例属性,结果失败了。
  4.  但是可以直接把‘prop’存入obj.__dict__,从而创建prop实例属性。
  5.  审查对象,看到了data和prop两个实例属性。
  6.  但是读取obj.prop时仍会运行特性的读值方法,特性并没有被同名的实例属性覆盖。
  7.  直接在类属性上覆盖Class.prop,销毁特性对象。
  8.  现在,obj.prop获取的是实例属性,因为Class.prop变成了普通的类属性,不再是特性了,因此被实例属性所覆盖。

第三个例子:为Class类新添一个特性,覆盖实例属性

  1. obj.data获取实例属性data。
  2. Class.data获取类属性。
  3. 使用新特性覆盖Class.data。
  4. 现在,obj.data被Class.data特性覆盖了。
  5. 删除特性。
  6. obj.data恢复原样,仍然获取实例属性。

本节主要观点:obj.attr这样的表达式不是从obj开始寻找attr的,而是从obj.__class__开始。仅当类中没有名为attr的特性时,python才会在obj实例中寻找。

特性的文档

控制台中help()函数或者IDE工具要显示特性的文档时,会从特性的__doc__属性中提取信息。

  • 可以在调用property类的时候直接为特性对象设置文档字符串,只需传入__doc__参数即可:

  •  使用装饰器创建property对象时,读值方法的文档字符串作为一个整体,变成特性的文档。

四、定义一个特性工厂

如果我们的类中有两个实例属性都需要用特性来管理,那么对两个属性都分别实现读值与设值方法会使得代码重复,因此需要定义特性工厂函数quantity。比如下边例子中self.weight和self.price都需要用特性进行管理:

  1. 使用工厂函数把第一个自定义的特性weight定义为类属性。
  2. 第二次调用,构建另一个自定义的特性price。
  3. 这里,特性已经激活,确保不能把weight设为负数或零。
  4. 这里也用到了特性,使用特性获取实例中存储的值。

下面是quantity特性工厂函数的实现:

  1.  storage_name参数确定各个特性的数据存在哪里,其实就是对应实例的数据属性的变量名。
  2. qty_getter函数的第一个参数instance直到要把属性存储其中的LineItem实例(即存储特性的管理的数据属性的那个实例)。
  3. qty_getter引用了storage_name,将其保存在qty_getter的闭包中,值直接从instance.__dict__中获取,为的是跳过特性,防止无线递归。因为直接instance.attr搜寻属性时会先找特性然后才是实例属性、类属性等。
  4. 定义qty_setter函数,第一个参数也是instance。
  5. 值直接存到instance.__dict__中,这也是为了跳过特性。
  6. 传入读值方法与取值方法,构建一个自定义的特性对象,然后将其返回。

        值得注意的一点是,引用self.weight或obj.weight都由特性函数处理,只有直接存取__dict__属性才能跳过特性。

        下面示例创建并审查一个LineItem示例,说明存储值的是哪个属性:

  1. 通过特性读取weight和price,这会遮盖同名实例属性。
  2. 使用vars函数审查nutmeg示例,表明真正用于存储值的是实例属性。

五、处理属性删除操作

对象的属性可以使用del语句删除:

使用python时不常删除属性,通过特性删除属性更少见,但是允许这么做。可以使用@my_property.deleter装饰器装饰一个方法,负责删除特性管理的属性。

 

 

六、处理属性的重要属性和函数

影响属性处理方式的特殊属性

  • __class__,对象所属类的引用(即obj.__class__与type(obj)的作用相同)。python的某些特殊方法比如__getattr__,只在对象的类中寻找,而不在实例中寻找。
  • __dict__,一个映射,存储对象或类的可写属性。有__dict__属性的对象,任何时候都能随意设置新属性。如果类有__slots__属性,它的实例可能没有__dict__属性。
  • __slots__,类可以定义这个属性,限制实例能有哪些属性。__slots__属性的值是一个字符串组成的元素,指明允许有的属性。如果__slots__中没有__dict__,那么该类的实例中没有__dict__属性,实例只允许有指定名称的属性。

处理属性的内置函数

  • dir([object]),列出对象的大多数属性。dir函数的目的是交互式使用,因此没有提供完整的属性列表。dir函数能审查有或没有__dict__属性的对象。dir函数不会列出__dict__属性本身,但会列出其中的键。dir函数也不会列出类的几个特殊属性,例如__mro__、__bases__和__name__。如果没有指定的object参数,dir函数会列出当前作用域中的名称。
  • getattr(object, name[, default]),从object对象中获取name字符串对应的属性。获取的属性可能来自对象所属的类或超类。如果没有指定的属性,getattr函数抛出AttributeError异常,或者返回default参数的值。
  • hasattr(object, name),如果object函数中存在指定的属性,或者能以某种方式(如继承)通过object对象获取指定的属性,返回True。这个函数的实现方法是调用getattr(object, name)函数,看是否抛出AttributeError异常。
  • setattr(object, name, value),把object对象指定属性的值设为value,前提是object对象能接受那个值,这个函数可能会创建一个新属性,或者覆盖现有的属性。
  • vars([object]),返回object对象的__dict__属性,如果实例所属的类定义了__slots__属性,实例没有__dict__属性,那么vars函数不能处理那个实例,但是dir函数可以处理。如果没有指定参数,则vars函数与locals函数一定:返回表示本地作用域的字典。

处理属性的特殊方法

在用户自定义类中,使用点号或内置的getattr、hasattr、setattr函数存取属性都会触发下列对应的特殊方法,但是直接通过实例的__dict__属性读取属性不会触发这些特殊方法。

  • __delattr__(self, name),只要使用del语句删除属性,就会调用这个方法。例如 del obj.attr语句会触发 Class.__delattr__(obj, 'attr')。
  • __dir__(self),把对象传给dir函数时调用,dir(obj)触发Class.__dir__(obj)。
  • __getattr__(self, name),仅当获取指定属性失败,搜索过特性、obj、Class和超类之后调用。表达式obj.no_such_attr、getattr(obj, 'no_such_attr')和hasattr(obj, 'no_such_attr')可能会触发Class.__getattr__(obj, 'no_such_attr')方法,但是仅当找不到指定的属性时才会触发。
  • __getattribute__(self, name),尝试获取指定的属性时总会调用这个方法,不过寻找的属性时特殊属性或特殊方法时除外。点号与getattr和hasattr内置函数会触发这个方法,调用__getattribute__方法且抛出AttributeError异常时,才会调用__getattr__方法。为了在获取obj实例的属性时不导致无限递归,__getattribute__方法的实现要使用super().__getattribute(obj, name)。
  • __setattr__(self, name, value),尝试设置指定的属性时会调用这个方法,点号和setattr内置函数会触发这个方法。例如obj.attr = 42和setattr(obj, 'attr', 42)都会触发Class.__setattr__(obj, 'attr', 42)方法。

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Python笔记.md 是一个用于记录Python编程相关内容的markdown文档。 在Python学习过程中,学习者通常会遇到各种问题和疑惑,需要有一个地方来记录学习笔记和重要概念,以方便日后复习和查阅。Python笔记.md 就是一个很好的选择。 Python笔记.md 可以按照自己的需要来组织内容,比如可以分为不同的章节或主题,并使用markdown语法来格式化文档,使其更加清晰易读。 在Python笔记.md中,可以记录Python的基础语法、常用数据结构、函数、类、模块等内容。此外,还可以记录一些常见的错误和解决方法,以便日后遇到类似问题时能够快速找到解决方案。 Python笔记.md 还可以用来记录自己的思考和理解。在学习过程中,我们常常会思考某个概念或代码背后的原理,这时候可以将自己的思考记录在笔记中,以便后续复习和回顾。 使用Python笔记.md 还可以方便与他人分享学习心得。可以在文档中加入注释或标题,使得文档更加易读和友好。同时,也可以将Python笔记.md 推送到版本控制系统中,与他人共享和共同编辑。 总之,Python笔记.md 是一个非常有用的工具,可以帮助学习者系统地记录、整理和复习Python编程相关的知识和经验。无论是初学者还是有经验的开发者,都可以从中受益,并提高自己的编程技能。 ### 回答2: Python笔记.md是一个使用Markdown语法编写的Python笔记文档。Markdown语法是一种轻量级的标记语言,可以快速地编辑和排版文档。 在Python笔记.md中,可以记录Python程序设计的相关知识、概念和技巧。通过使用Markdown语法,可以方便地插入代码块、链接、图片以及其他强调和排版格式,使得笔记更加直观和易读。 Python笔记.md可以按照不同的章节和主题组织内容,方便快速查找和阅读。在每个章节中,可以记录不同的Python编程概念,如数据类型、控制结构、函数、类等。可以通过示例代码和解释说明来详细解释这些概念的用法和特点。 在笔记中,还可以记录一些Python的常见问题和解决方案,例如常见错误、调试技巧等。这些内容可以帮助初学者更好地理解和掌握Python语言。 此外,Python笔记.md还可以连接到其他的Python资源,如官方文档、教程、在线代码编辑器等。这样可以提供更多的学习和参考资料。 总之,Python笔记.md是一个有条理、易读和方便编辑的Python学习笔记文档,可以帮助人们更好地学习和理解Python编程语言。 ### 回答3: Python笔记md是一种用来记录Python编程语言相关内容的文本文件格式。它使用Markdown语法来快速、简洁地编写和格式化笔记Python笔记md的优点是: 1. 简单易懂:Markdown语法简洁明了,使用起来非常简单,即便没有编程背景的人也能快速上手。 2. 跨平台兼容:无论是在Windows、Mac还是Linux系统中,Python笔记md都可以轻松使用。 3. 可读性强:Python笔记md的文本格式使得代码和说明可以同时显示,方便读者理解和学习。 4. 方便分享和发布:Python笔记md可以导出为HTML或PDF格式,方便分享给其他人或者发布到网络上。 5. 与开发工具兼容:大多数集成开发环境(IDE)和文本编辑器都支持Markdown语法,可以实时预览和编辑笔记。 使用Python笔记md可以帮助程序员记录代码和相关的解释和说明,方便复习和查看。它还可以用于编写技术博客、文档和教育材料等。而且由于其文本格式的特点,Python笔记md也非常适合使用版本控制系统进行版本管理。 总而言之,Python笔记md是一种简单、灵活且易于分享的笔记格式,可以有效提高编程学习和开发的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值