Jean's Blog

一个专注软件测试开发技术的个人博客

0%

Python变量及数据类型

变量

  • 变量是一种存储数据的载体。计算机中的变量是实际存在的数据或者说是存储器中存储数据的一块内存空间

  • 变量的值可以被读取和修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    lvjing@lvjingdeMacBook-Pro ~ % python3
    Python 3.8.2 (default, Jun 8 2021, 11:59:35)
    [Clang 12.0.5 (clang-1205.0.22.11)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> a = 1
    >>> a
    1
    >>> a = 2
    >>> a
    2
  • 命名规则

    • 变量名由字母(广义的Unicode字符,不包括特殊字符)、数字和下划线构成,数字不能开头
    • 大小写敏感(大写A和小写a是两个不同的变量)
    • 不要跟关键字(有特殊含义的单词)和系统保留字(如函数、模块等的名字)冲突
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    >>> a_1 = 0
    >>> a_1
    0
    >>> 1_a = 9
    File "<stdin>", line 1
    1_a = 9
    ^
    SyntaxError: invalid decimal literal
    >>> A = 5
    >>> a = 6
    >>> A
    5
    >>> a
    6

数据类型

计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值。但是,计算机能处理的远不止数值,还可以处理文本、图形、音频、视频、网页等各种各样的数据,不同的数据,需要定义不同的数据类型。

标准数据类型

有6个

  • 不可变数据(3个):Number(数字)、String(字符串)、Tuple(元组)
  • 可变数据(3个):List(列表)、Dictionary(字典)、Set(集合)

数值型

整数

Python可以处理任意大小的整数,当然包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1100-80800,等等。

计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用0x前缀和0-9,a-f表示,例如:0xff000xa5b4c3d2,等等。

对于很大的数,例如10000000000,很难数清楚0的个数。Python允许在数字中间以_分隔,因此,写成10_000_000_00010000000000是完全一样的。十六进制数也可以写成0xa1b2_c3d4

image-20230524104845755

浮点数

浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.23x109和12.3x108是完全相等的。浮点数可以用数学写法,如1.233.14-9.01,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把10用e替代,1.23x109就是1.23e9,或者12.3e8,0.000012可以写成1.2e-5,等等。

整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差。

容器型

可容纳多个元素的容器对象,常用的如下:

  • list 列表
  • tuple 元组
  • dict 字典
  • set 集合

list 列表

使用一对中括号 [],创建一个 list 型变量

1
2
# 创建一个list变量
lst = [1, 3, 5]

示意图看出,右侧容器为开环的,意味着可以向容器中增加和删除元素:

image-20230524104914328

tuple 元组

使用一对括号 (),创建一个 tuple 型对象

1
2
# 创建一个tuple对象
tup = (1, 3, 5)

示意图看出,右侧容器为闭合的,意味着一旦创建元组后,便不能再向容器中增删元素:

image-20230524104958147

但需要注意,含单个元素的元组后面必须保留一个逗号,才被解释为元组,否则会被认为元素本身。

image-20230524111107763

dict 字典

使用一对花括号 {} 另使用冒号 :,创建一个 dict 对象

1
2
# 创建一个dict对象
dic = {'a':1, 'b':3, 'c':5}

字典是一个哈希表,下面的示意图形象的表达出字典的 “形”。

image-20230524111128491

set 集合

仅使用一对花括号 {},创建一个 set 对象

1
2
# 创建一个set对象
s = {1, 3, 5}

字符串

字符串是以单引号'或双引号"括起来的任意文本,比如'abc'"xyz"等等。请注意,''""本身只是一种表示方式,不是字符串的一部分,因此,字符串'abc'只有abc这3个字符。如果'本身也是一个字符,那就可以用""括起来,比如"I'm OK"包含的字符是I'm,空格,OK这6个字符。

如果字符串内部既包含'又包含"怎么办?可以用转义字符\来标识,比如:

1
'I\'m \"OK\"!'

表示的字符串内容是:I’m “OK”!

转义字符\可以转义很多字符,比如\n表示换行,\t表示制表符,字符\本身也要转义,所以\\表示的字符就是\,可以在Python的交互式命令行用print()打印字符串看看:

image-20230524111153897

如果字符串里面有很多字符都需要转义,就需要加很多\,为了简化,Python还允许用r’’表示‘’内部的字符串默认不转义:

image-20230524111209635

如果字符串内部有很多换行,用\n写在一行里不好阅读,为了简化,Python允许用'''...'''的格式表示多行内容

image-20230524111233475

上面是在交互式命令行内输入,注意在输入多行内容时,提示符由>>>变为...,提示你可以接着上一行输入,注意...是提示符,不是代码的一部分。当输入完结束符````和括号)`后,执行该语句并打印结果。

如果写成程序并存为.py文件,就是:

1
2
3
print('''line1
line2
line3''')

多行字符串'''...'''还可以在前面加上r使用

image-20230524111317706

字符串高频常用方法

  • strip 用于去除字符串前后的空格

    1
    2
    >>> ' I love python\t\n'.strip()
    'I love python'
  • replace 用于字符串的替换

    1
    2
    >>> 'I love python'.replace(' ','_')
    'I_love_python'
  • join 用于合并字符串

    1
    2
    >>> '_'.join(['book', 'store', 'count'])
    'book_store_count'
  • title 用于单词的首字符大写

    1
    2
    >>> 'i love python'.title()
    'I Love Python'
  • find 用于返回匹配字符串的起始位置索引

    1
    2
    >>> 'i love python'.find('python')
    7

字符串应用案例

判断 str1 是否由 str2 旋转而来。字符串 stringbook 旋转后得到 bookstring,写一段代码验证 str1 是否为 str2 旋转得到。

转化为判断:str1 是否为 str2+str2 的子串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def is_rotation(s1: str, s2: str) -> bool:
if s1 is None or s2 is None:
return False
if len(s1) != len(s2):
return False

def is_substring(s1: str, s2: str) -> bool:
return s1 in s2

return is_substring(s1, s2 + s2)


# 测试
r = is_rotation('stringbook', 'bookstring')
print(r) # True

r = is_rotation('greatman', 'maneatgr')
print(r) # False

布尔值

布尔值和布尔代数的表示完全一致,一个布尔值只有TrueFalse两种值,要么是True,要么是False,在Python中,可以直接用TrueFalse表示布尔值(请注意大小写),也可以通过布尔运算计算出来:

image-20230524111419294

布尔值可以用andornot运算

  • and运算是与运算,只有所有都为Trueand运算结果才是True

    image-20230524111453636

  • or运算是或运算,只要其中有一个为Trueor运算结果就是True

    image-20230524111540695

  • not运算是非运算,它是一个单目运算符,把True变成FalseFalse变成True

    image-20230524111608215

自定义类型

Python 使用关键字 class 定制自己的类,self 表示类实例对象本身。

一个自定义类内包括属性、方法,其中有些方法是自带的。

类(对象)

1
2
class Dog(object):
pass

以上定义一个 Dog 对象,它继承于根类 object,pass 表示没有自定义任何属性和方法。

下面创建一个 Dog 类型的实例:

1
wangwang = Dog()

Dog 类现在没有定义任何方法,但是刚才说了,它会有自带的方法,使用__dir__() 查看这些自带方法:

1
2
3
4
5
6
class Dog(object):
pass


wangwang = Dog()
print(wangwang.__dir__())

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
['__module__', 
'__dict__',
'__weakref__',
'__doc__',
'__repr__',
'__hash__',
'__str__',
'__getattribute__',
'__setattr__',
'__delattr__',
'__lt__',
'__le__',
'__eq__',
'__ne__',
'__gt__',
'__ge__',
'__init__',
'__new__',
'__reduce_ex__',
'__reduce__',
'__subclasshook__',
'__init_subclass__',
'__format__',
'__sizeof__',
'__dir__',
'__class__']

有些地方称以上方法为魔法方法,它们与创建类时自定义个性化行为有关。比如:

  • __init__方法能定义一个带参数的类;
  • __new__方法自定义实例化类的行为;
  • __getattribute__方法自定义读取属性的行为;
  • __setattr__ 自定义赋值与修改属性时的行为。

类的属性

1
2
3
def __init__(self, name, dtype):
self.name = name
self.dtype = dtype

通过 __init__,定义 Dog 对象的两个属性:name、dtype。

类的实例

1
wangwang = Dog('wangwang','cute_type')

wangwangDog 类的实例。

类的方法

1
2
def shout(self):
print('I\'m %s, type: %s' % (self.name, self.dtype))

注意:

  • 自定义方法的第一个参数必须是 self,它指向实例本身,如 Dog 类型的实例 dog;
  • 引用属性时,必须前面添加 self,比如 self.name 等。

自定义类型代码总结

总结以上代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog(object):
def __init__(self, name, dtype):
self.name = name
self.dtype = dtype

def shout(self):
print('I\'m %s, type: %s' % (self.name, self.dtype))


# 创建类的实例
wangwang = Dog('wangwang', 'cute_tpye')
# 调用实例的方法
wangwang.shout()

# 获取类实例的属性
print(wangwang.name)
print(wangwang.dtype)

执行结果

image-20230524111829302

看到创建的两个属性和一个方法都被暴露在外面,可被 wangwang 调用。这样的话,这些属性就会被任意修改:

1
2
3
# 修改实例中的属性
wangwang.name = 'mimi'
print(wangwang.name)

执行结果

image-20230524111850283

说到这里,要是有其他语言的代码基础,这就是破坏了面向对象中的封装性,是不符合开发思想的,那么我们如何在python里将属性变为私有呢。改动方法:属性前加 2 个 _ 后,变为私有属性。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Dog(object):
def __init__(self, name, dtype):
# 私有属性
self.__name = name
self.__dtype = dtype

def shout(self):
# name和dtype已经变为私有,在该方法中则不能获取
print('I\'m %s, type: %s' % (self.__name, self.__dtype))


# 创建类的实例
wangwang = Dog('wangwang', 'cute_tpye')
# 调用实例的方法
wangwang.shout()

方法前加 2 个 _ 后,方法变为“私有方法”,只能在 Dog 类内被共享使用,执行结果

image-20230524111912453

这时,我在想获取实例的name属性

1
print(wangwang.name)

执行结果

image-20230524111936049

这时我们在访问Dog中的name属性时,就告诉我们Dog类中没有name这个属性,属性name不能被访问了,但是我们又想访问呢?可以使用一个简单的方式,定义一个get_name()的方法:

1
2
def get_name(self):
return self.__name

综合代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Dog(object):
def __init__(self, name, dtype):
# 私有属性
self.__name = name
self.__dtype = dtype

def shout(self):
# name和dtype已经变为私有,在该方法中则不能获取
print('I\'m %s, type: %s' % (self.__name, self.__dtype))

def get_name(self):
return self.__name


# 创建类的实例
wangwang = Dog('wangwang', 'cute_tpye')

print(wangwang.get_name())

执行结果

image-20230524111952785

这时,就可以看到正常获取到name属性的值了。这种方式就类似于Java语言中对象类中的setter/getter方法,属性私有,通过set和get方法进行赋值和取值。在Python语言中,有更好的方式进行属性为只读或只写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 定义一个Book类,继承根类object
class Book(object):
def __init__(self, name, sale):
self.__name = name
self.__sale = sale

# 使用Python自带的property类,将name变为只读的
@property
def name(self):
return self.__name


a_book = Book('Python入门学习', 102.68)
print(a_book.name)

执行结果

image-20230524112012125

使用 @property 装饰后 name 变为属性,意味着 .name 就会返回这本书的名字,而不是通过 .name() 这种函数调用的方法。这样变为真正的属性后,可读性更好。

如果使 name 既可读又可写,就再增加一个装饰器 @name.setter。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 定义一个Book类,继承根类object
class Book(object):
def __init__(self, name, sale):
self.__name = name
self.__sale = sale

# 使用Python自带的property类,将name变为只读的
@property
def name(self):
return self.__name

@name.setter
def name(self, new_name):
self.__name = new_name


a_book = Book('Python入门学习', 102.68)
print(a_book.name)
print('-----------------------------')
a_book.name = 'Python进阶学习'
print(a_book.name)

执行结果

image-20230524112033445

注意这种装饰器写法:name.setter,name 已经被包装为 property 实例,调用实例上的 setter 函数再包装 name 后就会可写。