您现在的位置是:网站首页> PY&Rust

Python基本语法笔记

  • PY&Rust
  • 2024-09-08
  • 840人已阅读
摘要

Python基本语法笔记

Python常见的文件类型介绍

init.py文件

python在线教程

基本语法

py文件想做成本地库,在本机任何一个文件中直接import,怎么实现?

Python3包

Python3 基本数据类型

Python数据类型转换

Python算术运算符

Python3 列表

Python3 字典

Python3 集合

Python3 条件控制

Python3 循环语句

Python3 函数

Python3 模块

Python3 面向对象

Python3的标准库

Python开启新线程的代码

Python线程同步代码例子

Python线程的同步机制

使用Python UI编写事件

python中的with语句

Python调用C/C++动态链接库

Python界面生成器wxFormBuilder简单使用

Python  Tkinter GUI编程



Python常见的文件类型介绍


.py python的源代码文件,可以直接编辑,直接运行

.pyc Python源代码import后,编译生成的字节码

.pyd Python的动态链接库(Windows平台dll),需要通过其它程序调用运行。

.ipynb ipynb就是ipythonnotebook,是由jupyter插件生成的文件


Pycharm是一款流行的Python IDE,具有强大的代码编辑、调试和版本控制功能,因此,Pycharm作为Jupyter Notebook的替代品成为了一种趋势。在本文中,我们将从多个角度分析如何在Pycharm中运行ipynb文件。

1. 安装必要的插件

在Pycharm中运行ipynb文件之前,我们需要安装必要的插件。打开Pycharm,点击“File”-“Settings”-“Plugins”,搜索“Jupyter”,安装“Jupyter Notebook Integration”插件。此外,还需要安装“Python Scientific”插件,以便在Pycharm中使用科学计算库。


2. 导入ipynb文件

导入ipynb文件后,我们可以在Pycharm中直接编辑和运行代码。在Pycharm的“Project”视图中,右键单击要导入的文件夹,选择“New”-“Jupyter Notebook”,即可创建一个新的ipynb文件。然后,我们可以通过拖放或复制粘贴的方式将ipynb文件从Jupyter Notebook中导入到Pycharm中。


3. 运行ipynb文件

在Pycharm中运行ipynb文件有两种方法。一种是在Pycharm中打开ipynb文件,然后点击“Run”按钮。这将启动一个新的Jupyter Notebook服务器,并在默认浏览器中打开该文件。另一种方法是使用Pycharm的“Python Console”功能。在Pycharm中打开ipynb文件后,我们可以在“Python Console”中执行代码。要在“Python Console”中运行ipynb文件,请先选择“Cell”-“Run All”或“Cell”-“Run Selected Cell(s)”,然后在“Python Console”中查看结果。


4. 配置Pycharm与Jupyter Notebook服务器

我们还可以将Pycharm与现有的Jupyter Notebook服务器连接起来,以便在Pycharm中编辑和运行代码。要实现这一点,我们需要在Pycharm的“Settings”中配置远程服务器。首先,我们需要在Jupyter Notebook服务器上设置一个密码,然后在Pycharm中选择“File”-“Settings”-“Project:xxxx”-“Project Interpreter”-“Add”-“SSH Interpreter”。在这里,我们需要配置服务器的IP地址、用户名和密码。配置完成后,我们可以在Pycharm中直接连接到Jupyter Notebook服务器,并在Pycharm中编辑和运行代码。



init.py文件

__init__.py 文件在 Python 包中扮演着重要的角色,它标识一个目录为包,并允许你执行初始化操作、导入模块以及定义包级别的变量和函数

首先执行该文件里的内容



py文件想做成本地库,在本机任何一个文件中直接import,怎么实现?

通常,一个Python库至少包含一个__init__.py文件,这个文件可以为空,但它的存在告诉Python这个目录应该被视为一个包。


mylib/

├── __init__.py

├── module1.py

└── module2.py


编写setup.py接下来,你需要一个setup.py文件,这是Python包的安装脚本。这个文件会告诉Python你的库需要哪些依赖,以及如何安装它。from setuptools import setup, find_packages


setup(

    name='mylib',

    version='0.1',

    packages=find_packages(),

    install_requires=[

        # 依赖列表

    ],

)

安装库

有了setup.py,你就可以安装你的库了。在库的根目录下运行:pip install .或者,如果你想在开发时即时反映代码更改,可以使用:pip install -e .这样,你的库就被安装到本地了,可以在任何地方import。


如何在任何地方使用?一旦安装完成,你就可以在任何Python脚本中import你的库了。

from mylib.module1

import some_function







Python3包

什么是包

包就是一个包含__init__.py文件的文件夹,文件夹内可以包含子包或者模块

1.png


ui_hello.py内容

from PySide2.QtCore import *

from PySide2.QtGui import *

from PySide2.QtWidgets import *



class Ui_Form(object):

    def setupUi(self, Form):

        if not Form.objectName():

            Form.setObjectName(u"Form")

        Form.resize(400, 300)

        self.label = QLabel(Form)

        self.label.setObjectName(u"label")

        self.label.setGeometry(QRect(120, 80, 54, 12))


        self.retranslateUi(Form)


        QMetaObject.connectSlotsByName(Form)

    # setupUi


    def retranslateUi(self, Form):

        Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))

        self.label.setText(QCoreApplication.translate("Form", u"TextLabel", None))




基本语法

注释代码:

# 第一个注释

# 第二个注释

 

'''

第三注释

第四注释

'''

 

"""

第五注释

第六注释

"""

print ("Hello, Python!")


行与缩进

python最具特色的就是使用缩进来表示代码块,不需要使用大括号 {} 。

缩进的空格数是可变的,但是同一个代码块的语句必须包含相同的缩进空格数。实例如下:


实例(Python 3.0+)

if True:

    print ("True")

else:

    print ("False")


多行语句

Python 通常是一行写完一条语句,但如果语句很长,我们可以使用反斜杠 \ 来实现多行语句,例如:


total = item_one + \

        item_two + \

        item_three


同一行显示多条语句

Python 可以在同一行中使用多条语句,语句之间使用分号 ; 分割,以下是一个简单的实例:

实例(Python 3.0+)

#!/usr/bin/python3

 

import sys; x = 'runoob'; sys.stdout.write(x + '\n')


多个语句构成代码组

缩进相同的一组语句构成一个代码块,我们称之代码组。

像if、while、def和class这样的复合语句,首行以关键字开始,以冒号( : )结束,该行之后的一行或多行代码构成代码组。


我们将首行及后面的代码组称为一个子句(clause)。

如下实例:


if expression : 

   suite

elif expression : 

   suite 

else : 

   suite


在Python中,有三种主要的循环语句:for循环、while循环和do-while循环(在Python中没有原生的do-while循环,但可以使用while循环实现类似的功能)。下面是这些循环语句的示例


for循环:

for循环用于遍历可迭代对象(如列表、元组、字符串等)中的元素。


示例:

fruits = ['apple', 'banana', 'cherry']

for fruit in fruits:

    print(fruit)


# 输出:

# apple

# banana

# cherry


while循环

while循环在条件为真时重复执行代码块,直到条件为假。

示例:

count = 0

while count < 5:

    print(count)

    count += 1


# 输出:

# 0

# 1

# 2

# 3

# 4


do-while循环(使用while循环实现):

do-while循环首先执行代码块,然后在条件为真时重复执行。


示例:

count = 0

while True:

    print(count)

    count += 1

    if count >= 5:

        break


# 输出:

# 0

# 1

# 2

# 3

# 4


Python中无switch语句


import 与 from...import

在 python 用 import 或者 from...import 来导入相应的模块。


将整个模块(somemodule)导入,格式为: import somemodule

从某个模块中导入某个函数,格式为: from somemodule import somefunction

从某个模块中导入多个函数,格式为: from somemodule import firstfunc, secondfunc, thirdfunc

将某个模块中的全部函数导入,格式为: from somemodule import *


导入 sys 模块

import sys

print('================Python import mode==========================')

print ('命令行参数为:')

for i in sys.argv:

    print (i)

print ('\n python 路径为',sys.path)



导入 sys 模块的 argv,path 成员

from sys import argv,path  #  导入特定的成员

 

print('================python from import===================================')

print('path:',path) # 因为已经导入path成员,所以此处引用时不需要加sys.path



Python3 基本数据类型

Python 中的变量不需要声明。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建


多个变量赋值

Python允许你同时为多个变量赋值。例如:


a = b = c = 1

以上实例,创建一个整型对象,值为 1,从后向前赋值,三个变量被赋予相同的数值。


您也可以为多个对象指定多个变量。例如:


a, b, c = 1, 2, "runoob"

以上实例,两个整型对象 1 和 2 的分配给变量 a 和 b,字符串对象 "runoob" 分配给变量 c。


标准数据类型

Python3 中常见的数据类型有


Number(数字)

String(字符串)

bool(布尔类型)

List(列表)

Tuple(元组)

Set(集合)

Dictionary(字典)

Python3 的六个标准数据类型中:


不可变数据(3 个):Number(数字)、String(字符串)、Tuple(元组);

可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

此外还有一些高级的数据类型,如: 字节数组类型(bytes)。


List(列表)

变量[头下标:尾下标]

索引值以 0 为开始值,-1 为从末尾的开始位置。


list = [ 'abcd', 786 , 2.23, 'runoob', 70.2 ]

tinylist = [123, 'runoob']


print (list)            # 输出完整列表

print (list[0])         # 输出列表第一个元素

print (list[1:3])       # 从第二个开始输出到第三个元素

print (list[2:])        # 输出从第三个元素开始的所有元素

print (tinylist * 2)    # 输出两次列表

print (list + tinylist) # 连接列表


注意:

1、List写在方括号之间,元素用逗号隔开。

2、和字符串一样,list可以被索引和切片。

3、List可以使用+操作符进行拼接。

4、List中的元素是可以改变的


Tuple(元组)

元组(tuple)与列表类似,不同之处在于元组的元素不能修改。元组写在小括号 () 里,元素之间用逗号隔开。

元组中的元素类型也可以不相同:

实例

#!/usr/bin/python3


tuple = ( 'abcd', 786 , 2.23, 'runoob', 70.2  )

tinytuple = (123, 'runoob')


print (tuple)             # 输出完整元组

print (tuple[0])          # 输出元组的第一个元素

print (tuple[1:3])        # 输出从第二个元素开始到第三个元素

print (tuple[2:])         # 输出从第三个元素开始的所有元素

print (tinytuple * 2)     # 输出两次元组

print (tuple + tinytuple) # 连接元组



Set(集合)

集合(set)是由一个或数个形态各异的大小整体组成的,构成集合的事物或对象称作元素或是成员。


基本功能是进行成员关系测试和删除重复元素。


可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。


创建格式:


parame = {value01,value02,...}

或者

set(value)

实例

#!/usr/bin/python3


sites = {'Google', 'Taobao', 'Runoob', 'Facebook', 'Zhihu', 'Baidu'}


print(sites)   # 输出集合,重复的元素被自动去掉


# 成员测试

if 'Runoob' in sites :

    print('Runoob 在集合中')

else :

    print('Runoob 不在集合中')



# set可以进行集合运算

a = set('abracadabra')

b = set('alacazam')


print(a)


print(a - b)     # a 和 b 的差集


print(a | b)     # a 和 b 的并集


print(a & b)     # a 和 b 的交集


print(a ^ b)     # a 和 b 中不同时存在的元素

以上实例输出结果:


{'Zhihu', 'Baidu', 'Taobao', 'Runoob', 'Google', 'Facebook'}

Runoob 在集合中

{'b', 'c', 'a', 'r', 'd'}

{'r', 'b', 'd'}

{'b', 'c', 'a', 'z', 'm', 'r', 'l', 'd'}

{'c', 'a'}

{'z', 'b', 'm', 'r', 'l', 'd'}



Dictionary(字典)

字典(dictionary)是Python中另一个非常有用的内置数据类型。


列表是有序的对象集合,字典是无序的对象集合。两者之间的区别在于:字典当中的元素是通过键来存取的,而不是通过偏移存取。


字典是一种映射类型,字典用 { } 标识,它是一个无序的 键(key) : 值(value) 的集合。


键(key)必须使用不可变类型。


在同一个字典中,键(key)必须是唯一的。



在Python中,你可以使用字典的各种方法来添加、编辑和删除元素。下面是一些常用的操作示例:


添加元素:

使用赋值操作将新的键值对添加到字典中。

示例:

复制

my_dict = {'name': 'Alice', 'age': 25}

my_dict['city'] = 'New York'     # {'name': 'Alice', 'age': 25, 'city': 'New York'}


编辑元素:

通过键来访问字典中的元素,并对其进行赋值操作。

示例:


my_dict = {'name': 'Alice', 'age': 25}

my_dict['age'] = 26              # {'name': 'Alice', 'age': 26}


删除元素:

使用del语句删除指定的键值对。

使用pop()方法删除指定键的键值对,并返回该值。

示例:


my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}

del my_dict['age']               # {'name': 'Alice', 'city': 'New York'}

age = my_dict.pop('age')         # {'name': 'Alice', 'city': 'New York'}, age = 25


实例

#!/usr/bin/python3


dict = {}

dict['one'] = "1 - 菜鸟教程"

dict[2]     = "2 - 菜鸟工具"


tinydict = {'name': 'runoob','code':1, 'site': 'www.runoob.com'}



print (dict['one'])       # 输出键为 'one' 的值

print (dict[2])           # 输出键为 2 的值

print (tinydict)          # 输出完整的字典

print (tinydict.keys())   # 输出所有键

print (tinydict.values()) # 输出所有值

以上实例输出结果:


1 - 菜鸟教程

2 - 菜鸟工具

{'name': 'runoob', 'code': 1, 'site': 'www.runoob.com'}

dict_keys(['name', 'code', 'site'])

dict_values(['runoob', 1, 'www.runoob.com'])

构造函数 dict() 可以直接从键值对序列中构建字典如下:


实例

>>> dict([('Runoob', 1), ('Google', 2), ('Taobao', 3)])

{'Runoob': 1, 'Google': 2, 'Taobao': 3}

>>> {x: x**2 for x in (2, 4, 6)}

{2: 4, 4: 16, 6: 36}

>>> dict(Runoob=1, Google=2, Taobao=3)

{'Runoob': 1, 'Google': 2, 'Taobao': 3}

{x: x**2 for x in (2, 4, 6)} 该代码使用的是字典推导式,更多推导式内容可以参考:Python 推导式。


另外,字典类型也有一些内置的函数,例如 clear()、keys()、values() 等。


注意:


1、字典是一种映射类型,它的元素是键值对。

2、字典的关键字必须为不可变类型,且不能重复。

3、创建空字典使用 { }。


bytes 类型

在 Python3 中,bytes 类型表示的是不可变的二进制序列(byte sequence)。


与字符串类型不同的是,bytes 类型中的元素是整数值(0 到 255 之间的整数),而不是 Unicode 字符。


bytes 类型通常用于处理二进制数据,比如图像文件、音频文件、视频文件等等。在网络编程中,也经常使用 bytes 类型来传输二进制数据。


创建 bytes 对象的方式有多种,最常见的方式是使用 b 前缀:


此外,也可以使用 bytes() 函数将其他类型的对象转换为 bytes 类型。bytes() 函数的第一个参数是要转换的对象,第二个参数是编码方式,如果省略第二个参数,则默认使用 UTF-8 编码:


x = bytes("hello", encoding="utf-8")

与字符串类型类似,bytes 类型也支持许多操作和方法,如切片、拼接、查找、替换等等。同时,由于 bytes 类型是不可变的,因此在进行修改操作时需要创建一个新的 bytes 对象。例如:


实例


x = b"hello"

y = x[1:3]  # 切片操作,得到 b"el"

z = x + b"world"  # 拼接操作,得到 b"helloworld"

需要注意的是,bytes 类型中的元素是整数值,因此在进行比较操作时需要使用相应的整数值。例如:


实例

x = b"hello"

if x[0] == ord("h"):

    print("The first element is 'h'")

其中 ord() 函数用于将字符转换为相应的整数值。



字符串转bytes

字符串转bytes, 是用 encode() 方法

data = str_data.encode(encoding="utf-8")


int 转 bytes

用int对象的to_bytes()方法


# int variable

num = 7

# int to bytes

num_bytes = num.to_bytes(2, byteorder='big')

# display result and type

print(num_bytes)

print(type(num_bytes))

第2个参数,表示双字节整数中高低字符顺序,big 表示正常顺序,即低字节在前,高字节在后 b'\x00\x07'

little 表示,高字节在前,低字节在后。上例中,将2个参数改为little, 则显示出的数字为b’\x07\x00’

bytes 转int , 使用 int.from_bytes()方法

>>> d=3324

>>> byte_data=d.to_bytes(5,"big")

>>> byte_data

b'\x00\x00\x00\x0c\xfc'

>>> int_data = int.from_bytes(byte_data,"big")

>>> int_data

3324


dict, tuple, list 转bytes

dict, list, tuple 转bytes, 通常使用pickle序列化, 或用 json序列化



bytes 变量内容的操作

基本上字符串支持的操作,bytes 字节串也都支持,只不过是二进制方式,可读性较差。 .

如在字符串中查找、替换字符等

>>> a=b"alibaba"

>>> a.count(b'a')

3

>>> a.find(b'a',3)

4

>>> chr(a[4])

'a'

>>> b=a.replace(b'a',b'x')

>>> b

b'xlibxbx'



Python数据类型转换

下几个内置的函数可以执行数据类型之间的转换。这些函数返回一个新的对象,表示转换的值。


函数 描述

int(x [,base])

将x转换为一个整数


float(x)

将x转换到一个浮点数


complex(real [,imag])

创建一个复数


str(x)

将对象 x 转换为字符串


repr(x)

将对象 x 转换为表达式字符串


eval(str)

用来计算在字符串中的有效Python表达式,并返回一个对象


tuple(s)

将序列 s 转换为一个元组


list(s)

将序列 s 转换为一个列表


set(s)

转换为可变集合


dict(d)

创建一个字典。d 必须是一个 (key, value)元组序列。


frozenset(s)

转换为不可变集合


chr(x)

将一个整数转换为一个字符


ord(x)

将一个字符转换为它的整数值


hex(x)

将一个整数转换为一个十六进制字符串


oct(x)

将一个整数转换为一个八进制字符串



Python算术运算符

以下假设变量 a=10,变量 b=21:


运算符 描述 实例

+ 加 - 两个对象相加 a + b 输出结果 31

- 减 - 得到负数或是一个数减去另一个数 a - b 输出结果 -11

* 乘 - 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 210

/ 除 - x 除以 y b / a 输出结果 2.1

% 取模 - 返回除法的余数 b % a 输出结果 1

** 幂 - 返回x的y次幂 a**b 为10的21次方

// 取整除 - 往小的方向取整数

>>> 9//2

4

>>> -9//2

-5


Python比较运算符

以下假设变量a为10,变量b为20:


运算符 描述 实例

== 等于 - 比较对象是否相等 (a == b) 返回 False。

!= 不等于 - 比较两个对象是否不相等 (a != b) 返回 True。

> 大于 - 返回x是否大于y (a > b) 返回 False。

< 小于 - 返回x是否小于y。所有比较运算符返回1表示真,返回0表示假。这分别与特殊的变量True和False等价。注意,这些变量名的大写。 (a < b) 返回 True。

>= 大于等于 - 返回x是否大于等于y。 (a >= b) 返回 False。

<= 小于等于 - 返回x是否小于等于y。 (a <= b) 返回 True。


Python赋值运算符

以下假设变量a为10,变量b为20:


运算符 描述 实例

= 简单的赋值运算符 c = a + b 将 a + b 的运算结果赋值为 c

+= 加法赋值运算符 c += a 等效于 c = c + a

-= 减法赋值运算符 c -= a 等效于 c = c - a

*= 乘法赋值运算符 c *= a 等效于 c = c * a

/= 除法赋值运算符 c /= a 等效于 c = c / a

%= 取模赋值运算符 c %= a 等效于 c = c % a

**= 幂赋值运算符 c **= a 等效于 c = c ** a

//= 取整除赋值运算符 c //= a 等效于 c = c // a

:= 海象运算符,可在表达式内部为变量赋值。Python3.8 版本新增运算符。

在这个示例中,赋值表达式可以避免调用 len() 两次:


if (n := len(a)) > 10:

    print(f"List is too long ({n} elements, expected <= 10)")


Python位运算符

& 按位与运算符:参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0 (a & b) 输出结果 12 ,二进制解释: 0000 1100

| 按位或运算符:只要对应的二个二进位有一个为1时,结果位就为1。 (a | b) 输出结果 61 ,二进制解释: 0011 1101

^ 按位异或运算符:当两对应的二进位相异时,结果为1 (a ^ b) 输出结果 49 ,二进制解释: 0011 0001

~ 按位取反运算符:对数据的每个二进制位取反,即把1变为0,把0变为1。~x 类似于 -x-1 (~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。

<< 左移动运算符:运算数的各二进位全部左移若干位,由"<<"右边的数指定移动的位数,高位丢弃,低位补0。 a << 2 输出结果 240 ,二进制解释: 1111 0000

>> 右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,">>"右边的数指定移动的位数


Python逻辑运算符

Python语言支持逻辑运算符,以下假设变量 a 为 10, b为 20:


运算符 逻辑表达式 描述 实例

and x and y 布尔"与" - 如果 x 为 False,x and y 返回 x 的值,否则返回 y 的计算值。 (a and b) 返回 20。

or x or y 布尔"或" - 如果 x 是 True,它返回 x 的值,否则它返回 y 的计算值。 (a or b) 返回 10。

not not x 布尔"非" - 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 not(a and b) 返回 False

以上实例输出结果:


实例(Python 3.0+)

#!/usr/bin/python3

 

a = 10

b = 20

 

if ( a and b ):

   print ("1 - 变量 a 和 b 都为 true")

else:

   print ("1 - 变量 a 和 b 有一个不为 true")

 

if ( a or b ):

   print ("2 - 变量 a 和 b 都为 true,或其中一个变量为 true")

else:

   print ("2 - 变量 a 和 b 都不为 true")

 

# 修改变量 a 的值

a = 0

if ( a and b ):

   print ("3 - 变量 a 和 b 都为 true")

else:

   print ("3 - 变量 a 和 b 有一个不为 true")

 

if ( a or b ):

   print ("4 - 变量 a 和 b 都为 true,或其中一个变量为 true")

else:

   print ("4 - 变量 a 和 b 都不为 true")

 

if not( a and b ):

   print ("5 - 变量 a 和 b 都为 false,或其中一个变量为 false")

else:

   print ("5 - 变量 a 和 b 都为 true")


Python成员运算符

除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。


运算符 描述 实例

in 如果在指定的序列中找到值返回 True,否则返回 False。 x 在 y 序列中 , 如果 x 在 y 序列中返回 True。

not in 如果在指定的序列中没有找到值返回 True,否则返回 False。 x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。

以下实例演示了Python所有成员运算符的操作:


实例(Python 3.0+)

#!/usr/bin/python3

 

a = 10

b = 20

list = [1, 2, 3, 4, 5 ]

 

if ( a in list ):

   print ("1 - 变量 a 在给定的列表中 list 中")

else:

   print ("1 - 变量 a 不在给定的列表中 list 中")

 

if ( b not in list ):

   print ("2 - 变量 b 不在给定的列表中 list 中")

else:

   print ("2 - 变量 b 在给定的列表中 list 中")

 

# 修改变量 a 的值

a = 2

if ( a in list ):

   print ("3 - 变量 a 在给定的列表中 list 中")

else:

   print ("3 - 变量 a 不在给定的列表中 list 中")


以上实例输出结果:


1 - 变量 a 不在给定的列表中 list 中

2 - 变量 b 不在给定的列表中 list 中

3 - 变量 a 在给定的列表中 list 中


Python身份运算符

身份运算符用于比较两个对象的存储单元


运算符 描述 实例

is is 是判断两个标识符是不是引用自一个对象 x is y, 类似 id(x) == id(y) , 如果引用的是同一个对象则返回 True,否则返回 False

is not is not 是判断两个标识符是不是引用自不同对象 x is not y , 类似 id(x) != id(y)。如果引用的不是同一个对象则返回结果 True,否则返回 False。

注: id() 函数用于获取对象内存地址。


以下实例演示了Python所有身份运算符的操作:


实例(Python 3.0+)

#!/usr/bin/python3

 

a = 20

b = 20

 

if ( a is b ):

   print ("1 - a 和 b 有相同的标识")

else:

   print ("1 - a 和 b 没有相同的标识")

 

if ( id(a) == id(b) ):

   print ("2 - a 和 b 有相同的标识")

else:

   print ("2 - a 和 b 没有相同的标识")

 

# 修改变量 b 的值

b = 30

if ( a is b ):

   print ("3 - a 和 b 有相同的标识")

else:

   print ("3 - a 和 b 没有相同的标识")

 

if ( a is not b ):

   print ("4 - a 和 b 没有相同的标识")

else:

   print ("4 - a 和 b 有相同的标识")

以上实例输出结果:


1 - a 和 b 有相同的标识

2 - a 和 b 有相同的标识

3 - a 和 b 没有相同的标识

4 - a 和 b 没有相同的标识



Python3 列表

访问列表中的值

与字符串的索引一样,列表索引从 0 开始,第二个索引是 1,依此类推。

实例

#!/usr/bin/python3


list = ['red', 'green', 'blue', 'yellow', 'white', 'black']

print( list[0] )

print( list[1] )

print( list[2] )

以上实例输出结果:


red

green

blue



在Python中,你可以使用列表的各种方法来添加、删除和编辑元素。下面是一些常用的操作示例:


添加元素:

使用append()方法在列表末尾添加一个元素。

使用insert()方法在指定位置插入一个元素。

示例:

my_list = [1, 2, 3]

my_list.append(4)        # [1, 2, 3, 4]

my_list.insert(1, 5)     # [1, 5, 2, 3, 4]


删除元素:

使用remove()方法删除列表中的特定元素。

使用del语句删除指定位置的元素。

示例:


my_list = [1, 2, 3, 4]

my_list.remove(3)        # [1, 2, 4]

del my_list[0]           # [2, 4]


编辑元素:

直接通过索引对列表中的元素进行赋值操作。

示例:

my_list = [1, 2, 3]

my_list[1] = 5           # [1, 5, 3]


索引也可以从尾部开始,最后一个元素的索引为 -1,往前一位为 -2,以此类推

实例

#!/usr/bin/python3


list = ['red', 'green', 'blue', 'yellow', 'white', 'black']

print( list[-1] )

print( list[-2] )

print( list[-3] )

以上实例输出结果:


black

white

yellow



使用下标索引来访问列表中的值,同样你也可以使用方括号 [] 的形式截取字符,如下所示


实例

#!/usr/bin/python3


nums = [10, 20, 30, 40, 50, 60, 70, 80, 90]

print(nums[0:4])

以上实例输出结果:


[10, 20, 30, 40]

使用负数索引值截取:


实例

#!/usr/bin/python3

 

list = ['Google', 'Runoob', "Zhihu", "Taobao", "Wiki"]

 

# 读取第二位

print ("list[1]: ", list[1])

# 从第二位开始(包含)截取到倒数第二位(不包含)

print ("list[1:-2]: ", list[1:-2])

以上实例输出结果:


list[1]:  Runoob

list[1:-2]:  ['Runoob', 'Zhihu']


删除列表元素

可以使用 del 语句来删除列表的的元素,如下实例:


实例(Python 3.0+)

#!/usr/bin/python3

 

list = ['Google', 'Runoob', 1997, 2000]

 

print ("原始列表 : ", list)

del list[2]

print ("删除第三个元素 : ", list)

以上实例输出结果:


原始列表 :  ['Google', 'Runoob', 1997, 2000]

删除第三个元素 :  ['Google', 'Runoob', 2000]


Python列表脚本操作符

列表对 + 和 * 的操作符与字符串相似。+ 号用于组合列表,* 号用于重复列表。


如下所示:


Python 表达式 结果 描述

len([1, 2, 3]) 3 长度

[1, 2, 3] + [4, 5, 6] [1, 2, 3, 4, 5, 6] 组合

['Hi!'] * 4 ['Hi!', 'Hi!', 'Hi!', 'Hi!'] 重复

3 in [1, 2, 3] True 元素是否存在于列表中

for x in [1, 2, 3]: print(x, end=" ") 1 2 3 迭代


嵌套列表

使用嵌套列表即在列表里创建其它列表,例如:


>>>a = ['a', 'b', 'c']

>>> n = [1, 2, 3]

>>> x = [a, n]

>>> x

[['a', 'b', 'c'], [1, 2, 3]]

>>> x[0]

['a', 'b', 'c']

>>> x[0][1]

'b'

列表比较

列表比较需要引入 operator 模块的 eq 方法(详见:Python operator 模块):


实例

# 导入 operator 模块

import operator


a = [1, 2]

b = [2, 3]

c = [2, 3]

print("operator.eq(a,b): ", operator.eq(a,b))

print("operator.eq(c,b): ", operator.eq(c,b))

以上代码输出结果为:


operator.eq(a,b):  False

operator.eq(c,b):  True

Python列表函数&方法

Python包含以下函数:


序号 函数

1 len(list)

列表元素个数

2 max(list)

返回列表元素最大值

3 min(list)

返回列表元素最小值

4 list(seq)

将元组转换为列表

Python包含以下方法:


序号 方法

1 list.append(obj)

在列表末尾添加新的对象

2 list.count(obj)

统计某个元素在列表中出现的次数

3 list.extend(seq)

在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)

4 list.index(obj)

从列表中找出某个值第一个匹配项的索引位置

5 list.insert(index, obj)

将对象插入列表

6 list.pop([index=-1])

移除列表中的一个元素(默认最后一个元素),并且返回该元素的值

7 list.remove(obj)

移除列表中某个值的第一个匹配项

8 list.reverse()

反向列表中元素

9 list.sort( key=None, reverse=False)

对原列表进行排序

10 list.clear()

清空列表

11 list.copy()

复制列表



Python3 字典

访问字典里的值

把相应的键放入到方括号中,如下实例:


实例

#!/usr/bin/python3

 

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

 

print ("tinydict['Name']: ", tinydict['Name'])

print ("tinydict['Age']: ", tinydict['Age'])

以上实例输出结果:


tinydict['Name']:  Runoob

tinydict['Age']:  7



修改字典

向字典添加新内容的方法是增加新的键/值对,修改或删除已有键/值对如下实例:


实例

#!/usr/bin/python3

 

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

 

tinydict['Age'] = 8               # 更新 Age

tinydict['School'] = "菜鸟教程"  # 添加信息

 

 

print ("tinydict['Age']: ", tinydict['Age'])

print ("tinydict['School']: ", tinydict['School'])

以上实例输出结果:

tinydict['Age']:  8

tinydict['School']:  菜鸟教程



删除字典元素

能删单一的元素也能清空字典,清空只需一项操作。


显式删除一个字典用del命令,如下实例:


实例

#!/usr/bin/python3

 

tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

 

del tinydict['Name'] # 删除键 'Name'

tinydict.clear()     # 清空字典

del tinydict         # 删除字典

 

print ("tinydict['Age']: ", tinydict['Age'])

print ("tinydict['School']: ", tinydict['School'])

但这会引发一个异常,因为用执行 del 操作后字典不再存在:


Traceback (most recent call last):

  File "/runoob-test/test.py", line 9, in <module>

    print ("tinydict['Age']: ", tinydict['Age'])

NameError: name 'tinydict' is not defined



字典内置函数&方法

Python字典包含了以下内置函数:


序号 函数及描述 实例

1 len(dict)

计算字典元素个数,即键的总数。

>>> tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

>>> len(tinydict)

3

2 str(dict)

输出字典,可以打印的字符串表示。

>>> tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

>>> str(tinydict)

"{'Name': 'Runoob', 'Class': 'First', 'Age': 7}"

3 type(variable)

返回输入的变量类型,如果变量是字典就返回字典类型。

>>> tinydict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

>>> type(tinydict)

<class 'dict'>

Python字典包含了以下内置方法:


序号 函数及描述

1 dict.clear()

删除字典内所有元素

2 dict.copy()

返回一个字典的浅复制

3 dict.fromkeys()

创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值

4 dict.get(key, default=None)

返回指定键的值,如果键不在字典中返回 default 设置的默认值

5 key in dict

如果键在字典dict里返回true,否则返回false

6 dict.items()

以列表返回一个视图对象

7 dict.keys()

返回一个视图对象

8 dict.setdefault(key, default=None)

和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default

9 dict.update(dict2)

把字典dict2的键/值对更新到dict里

10 dict.values()

返回一个视图对象

11 pop(key[,default])

删除字典 key(键)所对应的值,返回被删除的值。

12 popitem()

返回并删除字典中的最后一对键和值。



Python3 集合

集合(set)是一个无序的不重复元素序列

可以使用大括号 { } 或者 set() 函数创建集合,注意:创建一个空集合必须用 set() 而不是 { },因为 { } 是用来创建一个空字典。


创建格式:


parame = {value01,value02,...}

或者

set(value)


集合的基本操作

1、添加元素

语法格式如下:


s.add( x )

将元素 x 添加到集合 s 中,如果元素已存在,则不进行任何操作


2、移除元素

语法格式如下:


s.remove( x )

将元素 x 从集合 s 中移除,如果元素不存在,则会发生错误


3、计算集合元素个数

语法格式如下:


len(s)

计算集合 s 元素个数。



4、清空集合

语法格式如下:


s.clear()



5、判断元素是否在集合中存在

语法格式如下:


x in s

判断元素 x 是否在集合 s 中,存在返回 True,不存在返回 False。


集合内置方法完整列表

方法 描述

add() 为集合添加元素

clear() 移除集合中的所有元素

copy() 拷贝一个集合

difference() 返回多个集合的差集

difference_update() 移除集合中的元素,该元素在指定的集合也存在。

discard() 删除集合中指定的元素

intersection() 返回集合的交集

intersection_update() 返回集合的交集。

isdisjoint() 判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。

issubset() 判断指定集合是否为该方法参数集合的子集。

issuperset() 判断该方法的参数集合是否为指定集合的子集

pop() 随机移除元素

remove() 移除指定元素

symmetric_difference() 返回两个集合中不重复的元素集合。

symmetric_difference_update() 移除当前集合中在另外一个指定集合相同的元素,并将另外一个指定集合中不同的元素插入到当前集合中。

union() 返回两个集合的并集

update() 给集合添加元素


Python3 条件控制

if 语句

Python中if语句的一般形式如下所示:


if condition_1:

    statement_block_1

elif condition_2:

    statement_block_2

else:

    statement_block_3


a = 50

if (a< 100 and a > 10 or (a >20 and a<100):

 print "a is true"

else:

 print 'a is false'



4.png



5.png


match...case

Python 3.10 增加了 match...case 的条件判断,不需要再使用一连串的 if-else 来判断了。


match 后的对象会依次与 case 后的内容进行匹配,如果匹配成功,则执行匹配到的表达式,否则直接跳过,_ 可以匹配一切。


语法格式如下:


match subject:

    case <pattern_1>:

        <action_1>

    case <pattern_2>:

        <action_2>

    case <pattern_3>:

        <action_3>

    case _:

        <action_wildcard>


Python3 循环语句

while 循环

Python 中 while 语句的一般形式:


while 判断条件(condition):

    执行语句(statements)……



#!/usr/bin/env python3

 

n = 100

 

sum = 0

counter = 1

while counter <= n:

    sum = sum + counter

    counter += 1

 

print("1 到 %d 之和为: %d" % (n,sum))

执行结果如下:


1 到 100 之和为: 5050



无限循环

我们可以通过设置条件表达式永远不为 false 来实现无限循环,实例如下:


实例

#!/usr/bin/python3

 

var = 1

while var == 1 :  # 表达式永远为 true

   num = int(input("输入一个数字  :"))

   print ("你输入的数字是: ", num)



while 循环使用 else 语句

如果 while 后面的条件语句为 false 时,则执行 else 的语句块。


语法格式如下:


while <expr>:

    <statement(s)>

else:

    <additional_statement(s)>

expr 条件语句为 true 则执行 statement(s) 语句块,如果为 false,则执行 additional_statement(s)。


循环输出数字,并判断大小:


实例

#!/usr/bin/python3

 

count = 0

while count < 5:

   print (count, " 小于 5")

   count = count + 1

else:

   print (count, " 大于或等于 5")

执行以上脚本,输出结果如下:


0  小于 5

1  小于 5

2  小于 5

3  小于 5

4  小于 5

5  大于或等于 5

 

print ("Good bye!")



for 语句

Python for 循环可以遍历任何可迭代对象,如一个列表或者一个字符串。


for循环的一般格式如下:


for <variable> in <sequence>:

    <statements>

else:

    <statements>


Python for 循环实例:


实例

#!/usr/bin/python3

 

sites = ["Baidu", "Google","Runoob","Taobao"]

for site in sites:

    print(site)

以上代码执行输出结果为:


Baidu

Google

Runoob

Taobao



for...else

在 Python 中,for...else 语句用于在循环结束后执行一段代码。


语法格式如下:


for item in iterable:

    # 循环主体

else:

    # 循环结束后执行的代码

当循环执行完毕(即遍历完 iterable 中的所有元素)后,会执行 else 子句中的代码,如果在循环过程中遇到了 break 语句,则会中断循环,此时不会执行 else 子句。


实例

for x in range(6):

  print(x)

else:

  print("Finally finished!")

执行脚本后,输出结果为:


0

1

2

3

4

5

Finally finished!

以下 for 实例中使用了 break 语句,break 语句用于跳出当前循环体,不会执行 else 子句:


实例

#!/usr/bin/python3

 

sites = ["Baidu", "Google","Runoob","Taobao"]

for site in sites:

    if site == "Runoob":

        print("菜鸟教程!")

        break

    print("循环数据 " + site)

else:

    print("没有循环数据!")

print("完成循环!")

执行脚本后,在循环到 "Runoob"时会跳出循环体:


循环数据 Baidu

循环数据 Google

菜鸟教程!

完成循环!


range() 函数

如果你需要遍历数字序列,可以使用内置 range() 函数。它会生成数列,例如:


实例

>>>for i in range(5):

...     print(i)

...

0

1

2

3

4


break 和 continue 语句及循环中的 else 子句

break 语句可以跳出 for 和 while 的循环体。如果你从 for 或 while 循环中终止,任何对应的循环 else 块将不执行。

continue 语句被用来告诉 Python 跳过当前循环块中的剩余语句,然后继续进行下一轮循环。


pass 语句

Python pass是空语句,是为了保持程序结构的完整性。

pass 不做任何事情,一般用做占位语句



Python3 函数

定义一个函数

你可以定义一个由自己想要功能的函数,以下是简单的规则:


函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。

任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。

函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。

函数内容以冒号 : 起始,并且缩进。

return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。


1.png

参数

以下是调用函数时可使用的正式参数类型:


必需参数

关键字参数

默认参数

不定长参数


以下实例中演示了函数参数的使用不需要使用指定顺序:


实例(Python 3.0+)

#!/usr/bin/python3

 

#可写函数说明

def printinfo( name, age ):

   "打印任何传入的字符串"

   print ("名字: ", name)

   print ("年龄: ", age)

   return

 

#调用printinfo函数

printinfo( age=50, name="runoob" )



默认参数

调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:


实例(Python 3.0+)

#!/usr/bin/python3

 

#可写函数说明

def printinfo( name, age = 35 ):

   "打印任何传入的字符串"

   print ("名字: ", name)

   print ("年龄: ", age)

   return

 

#调用printinfo函数

printinfo( age=50, name="runoob" )

print ("------------------------")

printinfo( name="runoob" )



不定长参数


如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。如下实例:

实例(Python 3.0+)

#!/usr/bin/python3

 

# 可写函数说明

def printinfo( arg1, *vartuple ):

   "打印任何传入的参数"

   print ("输出: ")

   print (arg1)

   for var in vartuple:

      print (var)

   return

 

# 调用printinfo 函数

printinfo( 10 )

printinfo( 70, 60, 50 )



加了两个星号 ** 的参数会以字典的形式导入。


实例(Python 3.0+)

#!/usr/bin/python3

  

# 可写函数说明

def printinfo( arg1, **vardict ):

   "打印任何传入的参数"

   print ("输出: ")

   print (arg1)

   print (vardict)

 

# 调用printinfo 函数

printinfo(1, a=2,b=3)



Python3 模块

标准库的方法。

下面是一个使用 python 标准库中模块的例子。


实例(Python 3.0+)

#!/usr/bin/python3

# 文件名: using_sys.py

 

import sys 

print('命令行参数如下:')

for i in sys.argv:

   print(i)

 

print('\n\nPython 路径为:', sys.path, '\n')

执行结果如下所示:


$ python using_sys.py 参数1 参数2

命令行参数如下:

using_sys.py

参数1

参数2



Python 路径为: ['/root', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages'] 

1、import sys 引入 python 标准库中的 sys.py 模块;这是引入某一模块的方法。

2、sys.argv 是一个包含命令行参数的列表。

3、sys.path 包含了一个 Python 解释器自动查找所需模块的路径的列表。


import 语句

想使用 Python 源文件,只需在另一个源文件里执行 import 语句,语法如下:


import module1[, module2[,... moduleN]

当解释器遇到 import 语句,如果模块在当前的搜索路径就会被导入。


搜索路径是一个解释器会先进行搜索的所有目录的列表。如想要导入模块 support,需要把命令放在脚本的顶端:


support.py 文件代码

#!/usr/bin/python3

# Filename: support.py

 

def print_func( par ):

    print ("Hello : ", par)

    return

test.py 引入 support 模块:


test.py 文件代码

#!/usr/bin/python3

# Filename: test.py

 

# 导入模块

import support

 

# 现在可以调用模块里包含的函数了

support.print_func("Runoob")

以上实例输出结果:


$ python3 test.py 

Hello :  Runoob



from … import 语句

Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中,语法如下:


from modname import name1[, name2[, ... nameN]]

例如,要导入模块 fibo 的 fib 函数,使用如下语句:


>>> from fibo import fib, fib2

>>> fib(500)

1 1 2 3 5 8 13 21 34 55 89 144 233 377

这个声明不会把整个fibo模块导入到当前的命名空间中,它只会将fibo里的fib函数引入进来。



from … import * 语句

把一个模块的所有内容全都导入到当前的命名空间也是可行的,只需使用如下声明:


from modname import *

这提供了一个简单的方法来导入一个模块中的所有项目。然而这种声明不该被过多地使用。



Python3 面向对象

面向对象技术简介

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

方法:类中定义的函数。

类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。

数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。

方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。

局部变量:定义在方法中的变量,只作用于当前实例的类。

实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。

继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。

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

对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。



Python的类函数区分私有公共吗

Python中的类函数可以区分私有和公共。在Python中,使用双下划线(__)作为类函数或属性的前缀表示私有,外部调用时无法直接访问,需要通过类内部的函数实现访问;不使用双下划线作为前缀的函数或属性表示公共,可以在类的任何地方被访问。示例代码如下

class MyClass:

    def __init__(self):

        self.__private_var = 1

        self.public_var = 2


    def __private_func(self):

        print("This is a private function")


    def public_func(self):

        print("This is a public function")

        self.__private_func()


在上面的代码中,__init__函数中定义了一个私有变量__private_var和一个公共变量public_var。同时,类中还定义了一个私有函数__private_func和一个公共函数public_func。从外部调用时,私有变量和函数无法直接访问,但公共变量和函数可以通过类的实例进行访问。


# 创建实例

mc = MyClass()


# 访问公共变量和函数

print(mc.public_var)  # 输出:2

mc.public_func()      # 输出:This is a public function

                      #      This is a private function


# 无法直接访问私有变量和函数

print(mc.__private_var)    # 报错:'MyClass' object has no attribute '__private_var'

mc.__private_func()        # 报错:'MyClass' object has no attribute '__private_func'


类定义

语法格式如下


class ClassName:

    <statement-1>

    .

    .

    .

    <statement-N>

类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。


类对象

类对象支持两种操作:属性引用和实例化。

属性引用使用和 Python 中所有的属性引用一样的标准语法:obj.name。

类对象创建后,类命名空间中所有的命名都是有效属性名。所以如果类定义是这样:

实例(Python 3.0+)

#!/usr/bin/python3

 

class MyClass:

    """一个简单的类实例"""

    i = 12345

    def f(self):

        return 'hello world'

 

# 实例化类

x = MyClass()

 

# 访问类的属性和方法

print("MyClass 类的属性 i 为:", x.i)

print("MyClass 类的方法 f 输出为:", x.f())


self代表类的实例,而非类

类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称, 按照惯例它的名称是 self。


class Test:

    def prt(self):

        print(self)

        print(self.__class__)

 

t = Test()

t.prt()


self 不是 python 关键字,我们把他换成 runoob 也是可以正常执行的:

class Test:

    def prt(runoob):

        print(runoob)

        print(runoob.__class__)

 

t = Test()

t.prt()



类的方法

在类的内部,使用 def 关键字来定义一个方法,与一般函数定义不同,类方法必须包含参数 self, 且为第一个参数,self 代表的是类的实例。


实例(Python 3.0+)

#!/usr/bin/python3

 

#类定义

class people:

    #定义基本属性

    name = ''

    age = 0

    #定义私有属性,私有属性在类外部无法直接进行访问

    __weight = 0

    #定义构造方法

    def __init__(self,n,a,w):

        self.name = n

        self.age = a

        self.__weight = w

    def speak(self):

        print("%s 说: 我 %d 岁。" %(self.name,self.age))

 

# 实例化类

p = people('runoob',10,30)

p.speak()

执行以上程序输出结果为:


runoob 说: 我 10 岁。

继承

Python 同样支持类的继承,如果一种语言不支持继承,类就没有什么意义。派生类的定义如下所示:


class DerivedClassName(BaseClassName):

    <statement-1>

    .

    .

    .

    <statement-N>

子类(派生类 DerivedClassName)会继承父类(基类 BaseClassName)的属性和方法。


BaseClassName(实例中的基类名)必须与派生类定义在一个作用域内。除了类,还可以用表达式,基类定义在另一个模块中时这一点非常有用:

class DerivedClassName(modname.BaseClassName):

实例(Python 3.0+)

#!/usr/bin/python3

 

#类定义

class people:

    #定义基本属性

    name = ''

    age = 0

    #定义私有属性,私有属性在类外部无法直接进行访问

    __weight = 0

    #定义构造方法

    def __init__(self,n,a,w):

        self.name = n

        self.age = a

        self.__weight = w

    def speak(self):

        print("%s 说: 我 %d 岁。" %(self.name,self.age))

 

#单继承示例

class student(people):

    grade = ''

    def __init__(self,n,a,w,g):

        #调用父类的构函

        people.__init__(self,n,a,w)

        self.grade = g

    #覆写父类的方法

    def speak(self):

        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

 

 

 

s = student('ken',10,60,3)

s.speak()

执行以上程序输出结果为:


ken 说: 我 10 岁了,我在读 3 年级

多继承

Python同样有限的支持多继承形式。多继承的类定义形如下例:


class DerivedClassName(Base1, Base2, Base3):

    <statement-1>

    .

    .

    .

    <statement-N>

需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。


实例(Python 3.0+)

#!/usr/bin/python3

 

#类定义

class people:

    #定义基本属性

    name = ''

    age = 0

    #定义私有属性,私有属性在类外部无法直接进行访问

    __weight = 0

    #定义构造方法

    def __init__(self,n,a,w):

        self.name = n

        self.age = a

        self.__weight = w

    def speak(self):

        print("%s 说: 我 %d 岁。" %(self.name,self.age))

 

#单继承示例

class student(people):

    grade = ''

    def __init__(self,n,a,w,g):

        #调用父类的构函

        people.__init__(self,n,a,w)

        self.grade = g

    #覆写父类的方法

    def speak(self):

        print("%s 说: 我 %d 岁了,我在读 %d 年级"%(self.name,self.age,self.grade))

 

#另一个类,多重继承之前的准备

class speaker():

    topic = ''

    name = ''

    def __init__(self,n,t):

        self.name = n

        self.topic = t

    def speak(self):

        print("我叫 %s,我是一个演说家,我演讲的主题是 %s"%(self.name,self.topic))

 

#多重继承

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)

 

test = sample("Tim",25,80,4,"Python")

test.speak()   #方法名同,默认调用的是在括号中参数位置排前父类的方法

执行以上程序输出结果为:


我叫 Tim,我是一个演说家,我演讲的主题是 Python

方法重写

如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法,实例如下:


实例(Python 3.0+)

#!/usr/bin/python3

 

class Parent:        # 定义父类

   def myMethod(self):

      print ('调用父类方法')

 

class Child(Parent): # 定义子类

   def myMethod(self):

      print ('调用子类方法')

 

c = Child()          # 子类实例

c.myMethod()         # 子类调用重写方法

super(Child,c).myMethod() #用子类对象调用父类已被覆盖的方法

super() 函数是用于调用父类(超类)的一个方法。


执行以上程序输出结果为:

调用子类方法

调用父类方法



Python3标准库


Python 标准库非常庞大,所提供的组件涉及范围十分广泛,使用标准库我们可以让您轻松地完成各种任务。

以下是一些 Python3 标准库中的模块:


os 模块:os 模块提供了许多与操作系统交互的函数,例如创建、移动和删除文件和目录,以及访问环境变量等。

sys 模块:sys 模块提供了与 Python 解释器和系统相关的功能,例如解释器的版本和路径,以及与 stdin、stdout 和 stderr 相关的信息。

time 模块:time 模块提供了处理时间的函数,例如获取当前时间、格式化日期和时间、计时等。

datetime 模块:datetime 模块提供了更高级的日期和时间处理函数,例如处理时区、计算时间差、计算日期差等。

random 模块:random 模块提供了生成随机数的函数,例如生成随机整数、浮点数、序列等。

math 模块:math 模块提供了数学函数,例如三角函数、对数函数、指数函数、常数等。

re 模块:re 模块提供了正则表达式处理函数,可以用于文本搜索、替换、分割等。

json 模块:json 模块提供了 JSON 编码和解码函数,可以将 Python 对象转换为 JSON 格式,并从 JSON 格式中解析出 Python 对象。

urllib 模块:urllib 模块提供了访问网页和处理 URL 的功能,包括下载文件、发送 POST 请求、处理 cookies 等。



Python开启新线程的代码

以下是Python开启新线程的代码示例:


```python

import threading


# 定义一个函数作为线程的执行内容

def thread_function():

    print("This is a new thread.")


# 创建一个新的线程并启动它

new_thread = threading.Thread(target=thread_function)

new_thread.start()






print("Main thread continues here.")

```


在这个例子中,我们首先定义了一个函数`thread_function()`,这个函数表示线程的执行内容。然后,使用`threading.Thread()`创建了一个新的线程对象`new_thread`,传入`target=thread_function`参数表示该线程的执行内容为`thread_function()`函数。接着,使用`new_thread.start()`启动新线程。最后,在主线程中输出一条信息表示主线程继续执行。


需要注意的是,开启新线程会消耗一定的系统资源,如果线程过多,可能会导致系统负荷过重。因此,需要谨慎使用多线程技术


import threading

import time


exitFlag = 0


class myThread (threading.Thread):

    def __init__(self, threadID, name, delay):

        threading.Thread.__init__(self)

        self.threadID = threadID

        self.name = name

        self.delay = delay

    def run(self):

        print ("开始线程:" + self.name)

        print_time(self.name, self.delay, 5)

        print ("退出线程:" + self.name)


def print_time(threadName, delay, counter):

    while counter:

        if exitFlag:

            threadName.exit()

        time.sleep(delay)

        print ("%s: %s" % (threadName, time.ctime(time.time())))

        counter -= 1


# 创建新线程

thread1 = myThread(1, "Thread-1", 1)

thread2 = myThread(2, "Thread-2", 2)


# 开启新线程

thread1.start()

thread2.start()

thread1.join()

thread2.join()

print ("退出主线程")



Python3 通过两个标准库 _thread 和 threading 提供对线程的支持。


_thread 提供了低级别的、原始的线程以及一个简单的锁,它相比于 threading 模块的功能还是比较有限的。


threading 模块除了包含 _thread 模块中的所有方法外,还提供的其他方法:


threading.currentThread(): 返回当前的线程变量。

threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。

threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。

除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:


run(): 用以表示线程活动的方法。

start():启动线程活动。

join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生。

isAlive(): 返回线程是否活动的。

getName(): 返回线程名。

setName(): 设置线程名。



Python线程同步代码例子

下面是一个简单的Python线程同步代码例子:


```

import threading

 

class Counter:

    def __init__(self):

        self.lock = threading.Lock()

        self.count = 0

 

    def increment(self):

        with self.lock:

            self.count += 1

 

def worker(counter):

    for i in range(100):

        counter.increment()

 

# 创建一个计数器对象

counter = Counter()

 

# 创建10个线程

threads = []

for i in range(10):

    t = threading.Thread(target=worker, args=(counter,))

    threads.append(t)

    t.start()

 

# 等待所有线程结束

for t in threads:

    t.join()

 

# 输出计数器的值

print(counter.count)

```


在这个例子中,我们创建了一个计数器对象,它有一个 `increment` 方法可以对计数器进行加1的操作,同时使用了一个 `Lock` 对象来保证线程安全。然后我们创建了10个线程,每个线程都会对计数器进行100次加1操作。最后输出计数器的值,应该是1000。。



Python线程的同步机制

Python线程的同步机制包括:


1. Lock(锁):只允许一个线程访问共享资源,其他线程需要等待锁被释放后才能访问。


2. RLock(可重入锁):可以被同一个线程多次获得,并且不会被其它线程所获取的锁。


3. Semaphore(信号量):用于控制同时访问共享资源的线程数量。


4. Event(事件):用于线程之间的通信,一个线程可以设置事件,其他线程可以等待事件。


5. Condition(条件变量):用于线程之间的协调,一个或多个线程等待某个条件变量的可用性,并在可用时修改条件变量以通知其他线程。


6. Barrier(屏障):用于同步多个线程,要求在所有线程都到达屏障之前,不能继续执行。


7. Queue(队列):用于线程之间的通信,可以实现生产者-消费者模型。


以下是 Python Lock 的实例代码,包括锁定、释放锁定和使用锁定:


```python

import threading


lock = threading.Lock()


# 锁定

lock.acquire()


# 临界区代码

# ...


# 释放锁定

lock.release()


# 使用 with 语句自动锁定和释放

with lock:

    # 临界区代码

    # ...


# 在函数中使用锁定

def some_func():

    with lock:

        # 临界区代码

        # ...



下面是一个简单的 Python RLock 示例代码:


```python

import threading


class SharedResource:

    def __init__(self):

        self._lock = threading.RLock()

        self.counter = 0


    def increment(self):

        with self._lock:

            self.counter += 1


    def decrement(self):

        with self._lock:

            self.counter -= 1


if __name__ == "__main__":

    # 创建共享资源对象

    sr = SharedResource()


    # 创建增加计数器线程

    t1 = threading.Thread(target=sr.increment)

    t2 = threading.Thread(target=sr.increment)

    t3 = threading.Thread(target=sr.increment)


    # 创建减少计数器线程

    t4 = threading.Thread(target=sr.decrement)

    t5 = threading.Thread(target=sr.decrement)


    # 启动线程

    t1.start()

    t2.start()

    t3.start()

    t4.start()

    t5.start()


    # 等待线程结束

    t1.join()

    t2.join()

    t3.join()

    t4.join()

    t5.join()


    # 打印计数器值

    print("Counter value is %d" % sr.counter)

```


这个例子中,我们创建了一个名为 `SharedResource` 的对象,其中包含了一个计数器属性和一个 RLock 对象。我们使用 `with` 语句来确保在修改计数器属性时只有一个线程可以访问该属性。我们还创建了几个线程来增加和减少计数器的值,并使用 `join()` 方法等待所有线程结束。最后,我们打印计数器属性的值。

```



以下是一个使用Semaphore的Python示例代码:


```python

import threading


# 创建Semaphore对象,初始值为5,表示最多只能有5个线程同时执行

semaphore = threading.Semaphore(5)


def worker(num):

    # 获取锁定(如果锁定的计数器值<=0,则阻塞等待)

    semaphore.acquire()

    print("Worker {} is working...".format(num))

    # 模拟工作

    for i in range(5):

        print("Worker {} is processing...".format(num))

    # 释放锁定

    semaphore.release()


# 创建10个线程

threads = []

for i in range(10):

    t = threading.Thread(target=worker, args=(i,))

    threads.append(t)

    t.start()


# 等待所有线程完成

for t in threads:

    t.join()

```


这个示例代码创建了一个Semaphore对象,并将其初始化为5。然后创建了10个线程,并执行worker函数。在每个线程中,使用acquire方法获取Semaphore锁定。如果Semaphore的计数器值<=0,则该线程被阻塞等待锁定。当线程获取锁定后,执行一些工作,并使用release方法释放锁定。由于Semaphore的初始值为5,因此最多只能有5个线程同时运行。当有一个线程释放了锁定时,将允许其他阻塞的线程获取锁定并继续执行。


以下是一个使用 Python 实现 Event 的示例代码:


```python

from threading import Thread, Event

import time


# 线程1

def worker1(event, num):

    print("Worker 1 is starting...")

    time.sleep(num)  # 模拟任务执行时间

    event.set()  # 任务完成,设置 event


# 线程2

def worker2(event):

    print("Worker 2 is starting...")

    event.wait()  # 等待 event 被设置

    print("Worker 2 is done.")


if __name__ == "__main__":

    event = Event()  # 实例化 event

    thread1 = Thread(target=worker1, args=(event, 3))  # 传入 event 和任务执行时间

    thread2 = Thread(target=worker2, args=(event,))


    thread1.start()  # 启动线程1

    thread2.start()  # 启动线程2


    thread1.join()  # 等待线程1执行完毕

    thread2.join()  # 等待线程2执行完毕

```


这个示例代码中,我们实例化了一个 Event 对象,然后启动了两个线程,线程1执行一个模拟任务,执行完毕之后设置了 event,而线程2一直等待 event 被设置,一旦 event 被设置,就退出了。在这个示例中,我们可以看到在两个线程之间通过 event 来进行同步,线程2需要等待线程1执行完毕之后才能执行。



以下是一个使用 Python Queue 的实例代码。

python

import queue


# 创建一个队列,最大容量为 3

q = queue.Queue(maxsize=3)


# 向队列中添加元素

q.put(1)

q.put(2)

q.put(3)


# 获取队列中的元素,并打印队列长度

print(q.get())

print(q.get())

print(q.get())

print("队列长度为", q.qsize())


# 尝试向已满的队列中添加元素,结果会被阻塞

#q.put(4)


# 判断队列中是否还有元素

if q.empty():

    print("队列为空")

else:

    print("队列不为空")

```


输出结果为:


```

1

2

3

队列长度为 0

队列为空

```


代码中我们创建了一个最大容量为 3 的队列,并向其中添加了 3 个元素,然后依次获取了队列中的元素,并打印了队列的长度。最后判断队列是否为空,并输出相应的信





使用Python UI编写事件

以下是一个使用Python编写事件的示例代码:


```python

import tkinter as tk


def on_button_click():

    print("Button clicked")


def on_key_press(event):

    print("Key pressed: " + event.char)


def on_mouse_move(event):

    print("Mouse moved to: x=" + str(event.x) + ", y=" + str(event.y))


root = tk.Tk()


button = tk.Button(root, text="Click me", command=on_button_click)

button.pack()


root.bind("<Key>", on_key_press)


canvas = tk.Canvas(root, width=400, height=400)

canvas.pack()


canvas.bind("<Motion>", on_mouse_move)


root.mainloop()

```


在此示例中,有三个事件被绑定到不同的组件上:


- 当按钮被点击时,`on_button_click`函数将被调用。

- 当任何键被按下时,在窗口上调用`on_key_press`函数并打印按下的字符。

- 当鼠标移动到画布上时,`on_mouse_move`函数将被调用并打印鼠标的位置。


这只是一个简单的示例,你可以根据自己的需要编写更复杂的事件代码。



python中的with语句


with表达式其实是try-finally的简写形式。但是又不是全相同。


使用方法:

with context [as var]:

    pass


其中的context是一个表达式,返回的是一个对象,var用来保存context表达式返回的对象,可以有单个或者多个返回值。


例子1:


with open('a.txt') as f:

    print(f.read())

    

表达式open('a.txt')返回是一个_io.TextIOWrapper 类型的变量用f接收。在with语句块中就可以使用这个变量操作文件。执行with这个结构之后。f会自动关闭。相当于自带了一个finally。


但是with本身并没有异常捕获的功能,但是如果发生了运行时异常,它照样可以关闭文件释放资源。


例子2:

with open('b.txt') as f:

    print(f.read())


Traceback (most recent call last):

  File "E:/Python/pythoncode/lab_X/demo08.py", line 28, in <module>

    with open('b.txt') as f:

FileNotFoundError: [Errno 2] No such file or directory: 'b.txt'


这个例子可以看出with没有捕获异常的功能。


例子3:


try:

    with open('b.txt') as f:

        print(f.read())

except Exception as e:

    print("error")


输出:error


这个例子可以看出with发生了异常也会关闭程序。









Python调用C/C++动态链接库


最近需要使用Python调用C/C++功能,于是进行了一些相关调研。总体来说,Python调用C功能还算是相对比较简单,主要涉及ctypes这个函数库。

ctypes 是 Python 的外部函数库。它提供了与 C 兼容的数据类型,并允许调用C共享库中的函数。可使用该模块以纯 Python 形式对这些库进行封装。

基本数据类型的使用

ctypes定义了一些与C兼容的数据类型:


1.png


本篇主要关注跨语言调用时指针的处理方法,对于更全面的介绍,可参考:ctypes --- Python 的外部函数库 — Python 3.7.13 文档


下面用一个小例子来介绍Python调用C/C++动态库的方法。


C代码:


#include "stdio.h"

#include <iostream>

 

#ifdef __cplusplus

extern "C"

{

#endif

 

using namespace std;

 

// test for input char pointer

void print_string(char* str)

{

    printf("This is c code: print_string().\n");

    printf("%s\n", str);

}

 

// test for input integers and return an integer

int add_func(int a, int b)

{

    printf("This is c code: add_func()\n");

    return a + b;

}

 

// test for pointer as return value

int* get_array()

{

    int *pa = new int[10];

for(int i = 0; i < 10; i++)

{

pa[i] = i;

}

return pa;

}

 

void free_array(int *pa)

{

if(pa)

delete [] pa;

 

}

 

#ifdef __cplusplus

}

#endif

上面测试代码定义了普通整数的计算并返回整数、输入字符指针并打印、输出整型指针、释放指针等操作。需要注意的是,由于ctypes只与C兼容,而C++因为支持函数重载而在编译时修改函数名,因此,对于C++代码,需要使用C的方式编译。不了解的同学可自行搜索extern "C"的用法,本篇不做过多展开。


将以上代码编译成动态链接库:


g++ -std=c++11 test_c.c -shared -fPIC -o test_c.so

接着,我们使用Python来调用该动态库。Python代码:


#!/usr/bin/python

 

from ctypes import *

import os

 

# Load dynamic library

#lib_path = os.getcwd() + '/test_c.so'

lib_path = './test_c.so'

solib = cdll.LoadLibrary(lib_path)

 

# Indicate the function arguments type and return value type

solib.print_string.argtypes = [c_char_p]

solib.print_string.restype = c_void_p

 

# Call print_string function in C library

solib.print_string(b"Hello Python!")

 

# Call add function in C library

solib.add_func.argtypes = [c_int, c_int]

solib.add_func.restype = c_int

sum = solib.add_func(100,200)

print('Python code: sum = {}'.format(sum))

 

 

# Call get_array function in C library, the return value is a pointer of integer

solib.get_array.restype = POINTER(c_int)

p_array = solib.get_array()

int_array = [p_array[i] for i in range(10)]

 

print("Python code: ")

for x in int_array:

    print(x, end = ' ')

 

# Free the pointer

solib.free_array.argtypes = [POINTER(c_int)]

solib.free_array.restype = c_void_p

solib.free_array(p_array)

 

print('\nEnd Python')

运行结果:

1.png



在Python代码调用C动态库时,C库函数的参数和返回值必须是ctypes类型,参数类型使用关键字argtypes定义,对参数的定义必须是以序列的形式,如上面代码中的参数类型定义:


solib.add_func.argtypes = [c_int, c_int]


solib.print_string.argtypes = [c_char_p]


返回值参数类型使用restype定义,如上面代码中的语句:


solib.add_func.restype = c_int


solib.get_array.restype = POINTER(c_int)


其中,get_array函数的返回值使用POINTER(c_int)关键字定义成了int型的指针。


用户自定义类型的使用

除了基本数据类型,用户还可以使用自定义类型,下面给出一个自定义结构体的测试例子:


C代码:


typedef struct _point

{

        int x;

        int y;

        char desc[50];

}Point;

 

int get_point(Point point)

{

        printf("x = %d, y = %d, desc = %s\n", point.x, point.y, point.desc);

        return 0;

}

Python代码:


class Point(Structure):

        _fields_ = [

                ("x", c_int),

                ("y", c_int),

                ("desc", c_char * 50)

        ]

 

 

pt = Point(5, 10, b'I am a point.')

print(pt.x, pt.y, pt.desc)

 

solib.get_point.argtypes = [Point]

solib.get_point.restype = c_int

 

 

solib.get_point(pt)

Python中定义结构体时,必须继承Structure类,其成员的定义必须使用_fields_属性,否则无法调用C结构体。_fields_属性是一个list,其成员均为2个值的tuple,分别对应结构体成员的名称(C结构体成员名称)和类型,类型为ctypes类型,或者是由ctypes组合而成的新类型(如自己定义的结构体)。


以上代码的运行结果:

1.png



字符指针及数组类型


c端代码:


void arrayTest(char* pStr, unsigned char* puStr)

{

    cout << pStr << endl;

    cout << puStr << endl;

    for(int i = 0; i < 10; i++)

        printf("%c ", puStr[i]);

    printf("\n");

}

python端代码:


# python2默认都是ASCII编码,python3中str类型默认是Unicode类型,而ctypes参数需传入bytes-like object。因此python3中的字符串都需要转换编码

def c_array_test():

    library.arrayTest.argtype = [c_char_p, POINTER(c_ubyte*16)]

    library.arrayTest.restype = c_void_p


    # create_string_buffer函数会分配一段内存,产生一个c_char类型的字符串,并以NULL结尾

    # create_unicode_buffer函数,返回的是c_wchar类型

    str_info = create_string_buffer(b"Fine,thank you")


    # from_buffer_copy函数则是创建一个ctypes实例,并将source参数内容拷贝进去

    u_str_info = (c_ubyte*16).from_buffer_copy(b'0123456789abcdef')


    library.arrayTest(str_info, byref(u_str_info))




指针


从上面的表格中,我们可以看到char*和void*已经有专用类型了,直接使用即可,对于其他类型的指针,ctypes提供了两种定义方式pointer和POINTER。POINTER必须传入ctypes类型,创建出新的ctypes指针类型(pointer type),而pointer传入一个对象,创建出一个新的指针实例。(POINTER创建出了pointer)。


传输地址,ctypes提供了byref函数,ctypes.byref(obj[, offset]),该函数返回一个指向ctypes实例对象的轻量级指针,函数中还可以通过参数(必须是int)来设置偏移地址,这个返回的对象只能用于外部函数调用的参数。


C端代码:


void pointerTest(int* pInt, float* pFloat)

{

    *pInt = 10;

    *pFloat = 12.34;

}

python端代码:


def c_pointer_test():

    library.pointerTest.argtypes = [POINTER(c_int), POINTER(c_float)]

    library.pointerTest.restype = c_void_p


    int_a = c_int(0)

    float_b = c_float(0)


    # byref()函数用于传输地址

    library.pointerTest(byref(int_a), byref(float_b))

    print("out_a:", int_a.value)

    print("out_b", float_b.value)




外部传输字符空间,在函数内部进行操作


C端代码:


void mallocTest(char* pszStr)

{

    strcpy(pszStr, "Happay Children's day");

}

python端代码:


# 外部传输地址空间,在函数内部进行操作

def c_malloc_test():

    library.mallocTest.argtypes = [c_char_p]

    library.mallocTest.restype = c_void_p


    word = (c_char * 32)()

    library.mallocTest(word)

    print("out_word:", word.value)



结构体

结构体是C/C++中常用类型,使用前要先定义其成员类型,在python中也是同样处理,python中的结构体必须继承Structure类,定义其成员必须使用_field_属性。该属性是一个list,其成员都是2个值的tuple,分别是每个结构体成员的类型和长度,而且定义类型必须使用ctypes类型或者由ctype组合而成的新类型。


C端代码:


//结构体

typedef struct _rect

{

    int index;

    char info[16];

} Rect;

python端代码:


class Rect(Structure):

    _fields_ = [

        ('index', c_int),

        ('info', c_char * 16)

    ]

(1)读取结构体


c端代码:


int readRect(Rect rect)

{

    printf("value===========================\n");

    printf("index:%d info:%s\n",rect.index, rect.info);

    return 0;

}

python端代码:


def c_read_rect():

    library.readRect.argtypes = [Rect]

    library.readRect.restype = c_void_p


    rect_a = Rect(10, b"hello")

    library.readRect(rect_a)


(2)读取结构体,传参为结构体指针


C端代码:


int readRectPoint(Rect* pRect)

{

    printf("value===========================\n");

    printf("index:%d info:%s\n",pRect->index, pRect->info);

    return 0;

}

python端代码:


def c_read_rect_point():

    library.readRectPoint.argtypes = [POINTER(Rect)]

    library.readRectPoint.restype = c_void_p


    rect_a = Rect(10, b"hello")

    library.readRectPoint(byref(rect_a))



(3)传输结构体数组给动态库,实质是传输结构体数组指针,也就是首元素指针


C端代码:


void readRectArray(Rect* pRectArray)

{

    for(int i = 0; i < 5; i++)

        printf("RectArray[%d], index:%d, info:%s\n", i, pRectArray[i].index, pRectArray[i].info);

}


python端代码:


def c_read_rect_array():

    library.readRectArray.argtypes = [POINTER(Rect)]

    library.readRectArray.restype = c_void_p


    rect_array = (Rect * 5)()

    for i in range(5):

        rect_array[i] = Rect(i, bytes("Hello_" + str(i), encoding='utf-8'))


    # 以下两种方法皆可

    # library.readRectArray(rect_array)

    library.readRectArray(byref(rect_array[0]))



(4)从动态库中获取结构体数组内容


C端代码:


Rect* obtainRectArray(int *pArrayNum)

{

    int num = 5;

    *pArrayNum = num;

    Rect* pArray = (Rect*)malloc(num*sizeof(Rect));

    for(int i = 0; i < num; i++)

    {

        pArray[i].index = i;

        sprintf(pArray[i].info, "%s_%d", "hello", i);

    }

    

    return pArray;

}


void freeRect(Rect* pRect)

{

    free(pRect);

}

python端代码:


  def c_obtain_rect_array_and_free():

    library.obtainRectArray.argtypes = [POINTER(c_int)]

    library.obtainRectArray.restype = POINTER(Rect)


    library.freeRect.argtypes = [POINTER(Rect)]

    library.freeRect.restype = c_void_p


    num = c_int(10)


    rect_pt = library.obtainRectArray(byref(num))

    print("num:", num.value)


    # 结构体数组初始化

    # rect_pt.contents只能输出首元素的内容,rect_pt.contents.index

    rect_array = [rect_pt[i] for i in range(num.value)]


    for item in rect_array:

        print("index:", item.index, "info:", item.info)


    library.freeRect(rect_pt)



(5)嵌套结构体数组的处理


C端结构体定义:


struct UserStruct

{

    long user_id;

    char name[21];

};


struct CompanyStruct

{

    long com_id;

    char name[21];

    UserStruct users[100];

    int count;

};

python端结构体定义:


class UserStruct(Structure):

    _fields_ = [

        ('user_id', c_long),

        ('name', c_char * 21)

    ]



class CompanyStruct(Structure):

    _fields_ = [

        ('com_id', c_long),

        ('name', c_char * 21),

        ('users', UserStruct * 100),

        ('count', c_int)

    ]

对于python而言嵌套的自定义结构体跟普通类型一样处理。


C端函数实现:


void Print_Company(CompanyStruct* com)

{

    cout << com->com_id << "," << com->name << "," << com->count << endl;

    for(int i = 0; i < com->count; i++)

    {

        cout << com->users[i].user_id << "," << com->users[i].name << endl;

    }

    

    memset(com, 0, sizeof(CompanyStruct));

    com->com_id = 1001;

    strncpy(com->name, "esunny_sh", sizeof(com->name));

    com->count = 10;

    for(int i = 0; i < com->count; i++)

    {

        com->users[i].user_id = i;

        char key[21] = {0};

        snprintf(key, sizeof(key), "user_%d", i);

        strncpy(com->users[i].name, key, sizeof(com->users[i].name));

    }

}

python端函数实现:


def c_print_company():

    library.Print_Company.argtypes = [POINTER(CompanyStruct)]

    library.Print_Company.restype = c_void_p


    user_array = (UserStruct * 100)()

    for i in range(5):

        user_array[i] = UserStruct(i, bytes("user_" + str(i), encoding='utf-8'))


    company = CompanyStruct(1, b"esunny", user_array, 5)


    library.Print_Company(byref(company))


    print(company.com_id, company.name, company.count)

    for i in range(company.count):

        print(company.users[i].user_id, company.users[i].name)

这里需要注意初始化Company结构体时用到的user_array,user_array声明必须跟结构体中声明的长度一致。

可见传入的company结构体指针可以在动态库输出,并且动态库做的修改可以传出到python端。


Python  Tkinter GUI编程

Tkinter讲义.pdf








Top