跳转至

Programming

PythonRegex

pattern

^   匹配字符串的开头
$   匹配字符串的末尾。
.   匹配任意字符,除了换行符
a| b    匹配a或b
[a-zA-Z0-9] 匹配任何字母及数字
\d  匹配数字。等价于[0-9][aeiou] 匹配中括号内的任意一个字母
[^aeiou]    除了aeiou字母以外的所有字符
\w  匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'(\s*) 或者 ([\t ]*)     来匹配任意TAB和空格的混合字符

\s  匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]\S  匹配任何非空白字符。等价于 [^ \f\n\r\t\v]\b  匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'\B  匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er'

重复

re* 匹配0个或多个的表达式。
re+ 匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n}  精确匹配 n 个前面表达式。
        例如, o{2} 不能匹配 "Bob" 中的 "o",
        但是能匹配 "food" 中的两个 o。
re{ n,} 匹配 n 个前面表达式。
        例如, o{2,} 不能匹配"Bob"中的"o",
        但能匹配 "foooood"中的所有 o。
        "o{1,}" 等价于 "o+"。
        "o{0,}" 则等价于 "o*"。
re{ n, m}   匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式

match exactlly str

# find should use \ to represent the (6|12|3)
$ find ~/github/gapbs/ -type f -regex '.*/kron-\(6\|12\|3\).*'
/staff/shaojiemike/github/gapbs/kron-12.wsg
/staff/shaojiemike/github/gapbs/kron-3.sg
/staff/shaojiemike/github/gapbs/kron-3.wsg
/staff/shaojiemike/github/gapbs/kron-6.sg
/staff/shaojiemike/github/gapbs/kron-6.wsg

re.match与re.search的区别

re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;

而re.search匹配整个字符串,直到找到一个匹配。

re.match函数

从字符串的起始位置匹配

re.match(pattern, string, flags=0)

flags

多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M被设置成 I 和 M 标志:

re.I    使匹配对大小写不敏感
re.M    多行匹配,影响 ^ 和 $
re.S    使 . 匹配包括换行在内的所有字符

group

matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)

if matchObj:
   print "matchObj.group() : ", matchObj.group()
   print "matchObj.group(1) : ", matchObj.group(1)
   print "matchObj.group(2) : ", matchObj.group(2)
else:
   print "No match!!"

打印部分内容

matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) :  Cats
matchObj.group(2) :  smarter

re.sub 替换

findall

返回元组,可以指定开始,与结束位置。

result = re.findall(r'(\w+)=(\d+)', 'set width=20 and height=10')
print(result)
# [('width', '20'), ('height', '10')]

实例:objdump结果只提取汇编的命令

import re      
# 打开x86汇编代码文件
with open(assembly) as f:
        # 读取文件内容
        content = f.read()

# 使用正则表达式匹配所有汇编指令,
pattern = r'\b([a-zA-Z]{3,6})\b.*'
# 匹配pattern,但是只将()内结果保存在matches中
matches = re.findall(pattern, content)

# 输出匹配结果
for match in matches:
        print(match)

re.split

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://blog.csdn.net/weixin_39594191/article/details/111611346

https://www.runoob.com/python/python-reg-expressions.html

Python Class

简介

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。

  • 实例化:创建一个类的实例,类的具体对象。

  • 方法:类中定义的函数。
    • 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
    • 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
  • 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
    • 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
    • 实例变量:在类的声明中,属性是用变量来表示的。这种变量就称为实例变量,是在类声明的内部但是在类的其他成员方法之外声明的。

何时使用类

  1. 数据与操作紧密相关
  2. 对象有许多状态需要维护,可以使用类中的属性来保存状态。
  3. 需要生成多个仅在部分属性不同的实例,可以使用类作为模板。
  4. 不同对象存在公共parent-child的层次关系,可以使用继承来复用代码。
  5. 隐藏对象的实现细节,只对外公开接口。

类变量 与 实例变量

在Python中,类变量和实例变量是两个不同的概念:

  1. 类变量(Class Variable)

  2. 定义在类内部,但不在任何方法之内

  3. 被该类的所有实例对象所共享
  4. 可以通过类名或实例对象访问
  5. 用于定义与这个类相关的特征或属性

  6. 实例变量(Instance Variable)

  7. 定义在类内部的方法之内

  8. 每个实例对象拥有属于自己的变量副本
  9. 只能通过实例对象访问
  10. 用于定义实例对象的个性化特征或状态

例如:

class Person:

    species = 'Human' # 类变量

    def __init__(self, name):
        self.name = name # 实例变量

p1 = Person('John')
p2 = Person('Mary')

print(p1.species) # Human
print(p2.species) # Human 

print(p1.name) # John 
print(p2.name) # Mary

综上,类变量用于定义类的通用属性,实例变量用于定义实例的独特属性。区分二者是理解Python面向对象的关键。

创建

class Employee:
   '所有员工的基类'
   empCount = 0 # 类变量

   def __init__(self, name, salary):
      self.name = name
      self.salary = salary
      Employee.empCount += 1

   def displayCount(self):
     print "Total Employee %d" % Employee.empCount

   def displayEmployee(self):
      print "Name : ", self.name,  ", Salary: ", self.salary

类函数必有参数 ‘self’

必须有一个额外的第一个参数名称, 按照惯例它的名称是 self,self 不是 python 关键字,换成其他词语也行。

创建实例对象与访问

emp1 = Employee("Zara", 2000)
emp1.displayEmployee()

继承

通过继承创建的新类称为子类或派生类,被继承的类称为基类、父类或超类。

继承语法 class 派生类名(基类名)

调用基类

调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数 ,这点在代码上的区别如下:

class Base:
    def base_method(self):
        print("Base method")

class Derived(Base):
    def derived_method(self):
        # 调用基类方法要加类名前缀
        Base.base_method(self)

        # 调用普通函数
        print("Hello")  

d = Derived()
d.derived_method()

# 输出
Base method  
Hello

在Derived类中:

  • 调用Base基类的方法base_method(),需要写成Base.base_method(self)

  • 调用普通函数print(),直接写函数名即可

区别在于:

  • 调用基类方法需要指明方法所属的基类
  • 基类方法需要传入self,指代实例自己

而对于普通函数,只需要直接调用即可,不需要self参数。

这与Python的名称空间和面向对象实现有关,是理解Python类继承的关键点。

运算符重载

__init__ : 构造函数在生成对象时调用
__del__ : 析构函数释放对象时使用
__repr__ : 打印转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 函数调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__truediv__: 除运算
__mod__: 求余运算
__pow__: 乘方

PyTorch 中如果继承torch.nn.Module,执行__call__会转接到forward方法

torch.nn.Module__call__ 方法会调用 forward 方法,并且在调用 forward 之前和之后还会执行一些其他的操作,比如设置钩子(hooks)和调用 _check_forward_hooks 等。

以下是 torch.nn.Module__call__ 方法的简化实现逻辑:

class Module:
    def __call__(self, *input, **kwargs):
        # 在调用 forward 之前执行一些操作
        # 例如,调用 forward pre-hooks
        for hook in self._forward_pre_hooks.values():
            result = hook(self, input)
            if result is not None:
                if not isinstance(result, tuple):
                    result = (result,)
                input = result

        # 调用 forward 方法
        result = self.forward(*input, **kwargs)

        # 在调用 forward 之后执行一些操作
        # 例如,调用 forward hooks
        for hook in self._forward_hooks.values():
            hook_result = hook(self, input, result)
            if hook_result is not None:
                result = hook_result

        return result
  1. __call__ 方法:当你实例化一个 Module 并调用它时(例如 model(input)),Python 会调用 __call__ 方法。
  2. forward 方法__call__ 方法内部会调用 forward 方法,这是你需要在子类中重写的方法,用于定义前向传播的逻辑。
  3. 钩子(Hooks):在调用 forward 之前和之后,__call__ 方法会处理一些钩子。这些钩子可以用于调试、可视化或其他目的。

+=

在Python中可以通过特殊方法__iadd__来对+=符号进行重载。

__iadd__需要定义在类中,用于指定+=操作时的具体行为。例如:

class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __iadd__(self, other):
        self.x += other.x
        self.y += other.y
        return self

v1 = Vector(1, 2)
v2 = Vector(3, 4)

v1 += v2
print(v1.x, v1.y) # 4, 6

这里我们定义了__iadd__方法,用于实现两个Vector对象使用+=时的相加操作。

__iadd__方法的参数是另一个要相加的对象,在方法内部我们实现了两个向量的分量相加,并返回self作为结果。这样就实现了+=的运算符重载。

此外,Python还提供了__add__特殊方法用于重载+符号,但是__iadd__和__add__有以下区别:

  • __add__返回一个新的对象,不改变原有对象。
  • __iadd__在原有对象的基础上进行操作,并返回对原对象的引用。

所以对可变对象进行+=操作时,通常需要实现__iadd__方法。

参考文献

https://www.runoob.com/python/python-object.html

Language

面向过程 VS 面向对象

面向过程

面向过程是一种以事件为中心的编程思想,编程的时候把解决问题的步骤分析出来,然后用函数把这些步骤实现,在一步一步的具体步骤中再按顺序调用函数。

面向对象

在日常生活或编程中,简单的问题可以用面向过程的思路来解决,直接有效,但是当问题的规模变得更大时,用面向过程的思想是远远不够的。所以慢慢就出现了面向对象的编程思想。世界上有很多人和事物,每一个都可以看做一个对象,而每个对象都有自己的属性和行为,对象与对象之间通过方法来交互。面向对象是一种以“对象”为中心的编程思想,把要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个对象在整个解决问题的步骤中的属性和行为。

优缺点

面向过程

优点:

  1. 流程化使得编程任务明确,在开发之前基本考虑了实现方式和最终结果,具体步骤清楚,便于节点分析。
  2. 效率高,面向过程强调代码的短小精悍,善于结合数据结构来开发高效率的程序。

缺点:

  1. 需要深入的思考,耗费精力,代码重用性低,扩展能力差,后期维护难度比较大。
面向对象

优点:

  1. 结构清晰,程序是模块化和结构化,更加符合人类的思维方式;
  2. 易扩展,代码重用率高,可继承,可覆盖,可以设计出低耦合的系统;
  3. 易维护,系统低耦合的特点有利于减少程序的后期维护工作量。

缺点:

  1. 开销大,当要修改对象内部时,对象的属性不允许外部直接存取,所以要增加许多没有其他意义、只负责读或写的行为。这会为编程工作增加负担,增加运行开销,并且使程序显得臃肿。
  2. 性能低,由于面向更高的逻辑抽象层,使得面向对象在实现的时候,不得不做出性能上面的牺牲,计算时间和空间存储大小都开销很大。

静态语言 vs 动态语言

  1. Dynamic Programming Language (动态语言或动态编程语言)
  2. 动态语言,准确地说,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化。
  3. 比如众所周知的ECMAScript(JavaScript)便是一个动态语言。
  4. 除此之外如Ruby、Python等也都属于动态语言,而C、C++等语言则不属于动态语言。
  5. Dynamically Typed Language (动态类型语言)
  6. 动态类型语言:是指在运行期间才去做数据类型检查的语言。
  7. 在用动态语言编程时,不用给变量指定数据类型,该语言会在你第一次赋值给变量时,在内部将数据类型记录下来。
  8. Statically Typed Language (静态类型语言)
  9. 静态类型语言:与动态类型语言刚好相反,它的数据类型检查发生在在编译阶段,也就是说在写程序时要声明变量的数据类型。
  10. C/C++、C#、JAVA都是静态类型语言的典型代表。

两者的优缺点

静态类型语言的

  1. 主要优点在于其结构非常规范,便于调试,方便类型安全;
  2. 缺点是为此需要写更多的类型相关代码,导致不便于阅读、不清晰明了。

动态类型语言的

  1. 优点在于方便阅读,不需要写非常多的类型相关的代码;
  2. 缺点自然就是不方便调试,命名不规范时会造成读不懂,不利于理解等。

runtime

runtime 描述了程序运行时候执行的软件/指令, 在每种语言有着不同的实现。

可大可小,在 C 中,runtime 是库代码, 等同于 C runtime library,一系列 C 程序运行所需的函数。

在 Java 中,runtime 还提供了 Java 程序运行所需的虚拟机等。

总而言之,runtime 是一个通用抽象的术语,指的是计算机程序运行的时候所需要的一切代码库,框架,平台等

Go中的 runtime

在 Go 中, 有一个 runtime 库,其实现了垃圾回收,并发控制, 栈管理以及其他一些 Go 语言的关键特性。 runtime 库是每个 Go 程序的一部分,也就是说编译 Go 代码为机器代码时也会将其也编译进来。所以 Go 官方将其定位偏向类似于 C 语言中的库。

Go 中的 runtime 不像 Java runtime (JRE, java runtime envirement ) 一样,jre 还会提供虚拟机, Java 程序要在 JRE 下 才能运行。

垃圾回收机制(garbage collection,GC)的设计

C/C++语言为什么没有对指针对象的垃圾回收机制

作为支持指针的编程语言,C++将动态管理存储器资源的便利性交给了程序员。在使用指针形式的对象时(请注意,由于引用在初始化后不能更改引用目标 的语言机制的限制,多态性应用大多数情况下依赖于指针进行),程序员必须自己完成存储器的分配、使用和释放,语言本身在此过程中不能提供任何帮助。

某些语言提供了垃圾回收机制,也就是说程序员仅负责分配存储器和使用,而由语言本身负责释放不再使用的存储器,这样程序员就从讨厌的存储器管理的工作中脱身了。

C++的设计者Bjarne Stroustrup对此做出过解释:

“我有意这样设计C++,使它不依赖于自动垃圾回收(通常就直接说垃圾回收)。这是基于自己对垃圾回收系统的经验,我很害怕那种严重的空间和时间开销,也害怕由于实现和移植垃圾回收系统而带来的复杂性。还有,垃圾回收将使C++不适合做许多底层的工作,而这却正是它的一个设计目标。但我喜欢垃圾回收 的思想,它是一种机制,能够简化设计、排除掉许多产生错误的根源。 需要垃圾回收的基本理由是很容易理解的:用户的使用方便以及比用户提供的存储管理模式更可靠。而反对垃圾回收的理由也有很多,但都不是最根本的,而是关于实现和效率方面的。 已经有充分多的论据可以反驳:每个应用在有了垃圾回收之后会做的更好些。类似的,也有充分的论据可以反对:没有应用可能因为有了垃圾回收而做得更好。 并不是每个程序都需要永远无休止的运行下去;并不是所有的代码都是基础性的库代码;对于许多应用而言,出现一点存储流失是可以接受的;许多应用可以管理自己的存储,而不需要垃圾回收或者其他与之相关的技术,如引用计数等。 我的结论是,从原则上和可行性上说,垃圾回收都是需要的。但是对今天的用户以及普遍的使用和硬件而言,我们还无法承受将C++的语义和它的基本库定义在垃圾回收系统之上的负担。”

强类型语言和弱类型语言

1.强类型语言:使之强制数据类型定义的语言。没有强制类型转化前,不允许两种不同类型的变量相互操作。强类型定义语言是类型安全的语言,如Rust, Java、C# 和 Python,比如Java中“int i = 0.0;”是无法通过编译的;

2.弱类型语言:数据类型可以被忽略的语言。与强类型语言相反, 一个变量可以赋不同数据类型的值,允许将一块内存看做多种类型,比如直接将整型变量与字符变量相加。C/C++、PHP都是弱类型语言,比如C++中“int i = 0.0;”是可以编译运行的;

注意,强类型语言在速度上略逊色于弱类型语言,使用弱类型语言可节省很多代码量,有更高的开发效率。而对于构建大型项目,使用强类型语言可能会比使用弱类型更加规范可靠。

ispc

a data-parallel languagedesigned specifically to target Intel’s vector extensions

Intel® Implicit SPMD Program Compiler

An open-source compiler for high-performance SIMD programming on the CPU and GPU

ispc is a compiler for a variant of the C programming language, with extensions for "single program, multiple data" (SPMD) programming.

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

https://blog.csdn.net/yuanmengong886/article/details/52572533

https://segmentfault.com/a/1190000022715733

Pytorch 3 :Model & Training

导言
  • 构建复杂模型:学习如何构建更复杂的神经网络模型,如卷积神经网络(CNN)、循环神经网络(RNN)等。
  • 损失函数与优化器:理解不同的损失函数(如交叉熵、均方误差)和优化器(如SGD、Adam)。
  • 训练与验证:编写训练循环,理解如何监控训练过程,防止过拟合。

Pytorch 4 :Save & Load & Pretrain

导言

  • 保存与加载模型:学习如何保存训练好的模型,并在需要时加载模型进行推理或继续训练。
  • 迁移学习:学习如何使用预训练模型进行迁移学习,微调模型以适应新的任务。
  • 常用预训练模型:介绍PyTorch中常用的预训练模型,如ResNet、VGG等。

Cuda Program Basic

CUDA编程水平高低的不同,会导致几十上百倍的性能差距。但是这篇将聚焦于CUDA的编程语法,编译与运行。