python的基本对象类型

在python中,万物皆对象,或许你现在还不理解这句话的含义,但是从现在开始,我们即将接触的就是python的对象,对象有类型,python默认了一些对象类型

  • int整数
  • 浮点数(不用深究的情况下,把他直接理解为小数即可)
  • bool值
  • 内置数据结构
  • 列表
  • 元祖
  • 字符串
  • 字典
  • 集合


整数

a = input("please insert a num:")
print(a,type(a))

运行结果:
please insert a num:23
23 <class 'str'>

str 是string(字符串)的简写,怎么把a 转换成数字类型a呢?

a = int(input("please insert a num"))
print(a,type(a))

运行结果:
please insert a num23
23 <class 'int'>

在python2里分为整型和长整型(long),但在python3里就是int

[root@hadoop-namenode002 /]# python
Python 2.7.5 (default, Nov  6 2016, 00:28:07) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> a = 999999999999999999999999999999999999999
>>> print(type(a))
<type 'long'>
>>> b = 333
>>> print(type(b))
<type 'int'>
[root@hadoop-namenode002 opt]# python
Python 3.5.3 (default, Jul 27 2017, 22:41:34) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> 
>>> 
>>> a = 99999999999999999999999999999999999999999999999999999
>>> print(type(a))
<class 'int'>
>>> b = 333
>>> print(type(b))
<class 'int'>


浮点数

a = 23.0
print(a,type(a))

运行结果:
23.0 <class 'float'>


python 内置数据结构

五种内置数据结构:

  • list 列表
  • tuple 元组
  • str 字符串
  • set 集合
  • dic 字典

其中 列表、元组、字符串是线性结构(线性结构是一个有序数据元素的集合),线性结构可以做切片操作解包和封包 ,而成员运算符,遍历操作
只要是可迭代对象都可以,比如集合虽不是线性结构,但也是可迭代对象,也可以用 for 循环遍历

解析式:

  • 列表解析式
  • 生成器解析式 (py3 特有)
  • 集合解析式 (py3 特有)
  • 字典解析式 (py3 特有)


列表


创建列表

初始化一个空列表,列表用list表示,创建空列表有两种方式:


创建空列表
方式一:

a = []
print(a,type(a))
运行结果:
[] <class 'list'>

方式二:

a = list()
print(a,type(a))
运行结果:
[] <class 'list'>

创建一个非空列表

b = [1,2,3,4,5]
print(b,type(b))
运行结果:
[1, 2, 3, 4, 5] <class 'list'>


列表的索引和下标操作

python中 列表的索引是从0开始的,索引0代表第一个元素,索引1代表第二个元素,索引-1代表最后一个元素
也有人把索引叫做下标,都是一样的

x = ["a","b","c","d","e","f","g"]
x[0]
运行结果:
'a'

x[1]
运行结果:
'b'

x[-1]
运行结果:
'g'

x[-2]
运行结果:
'f'

如果索引超出范围,将会引发我们的index_error

x[7]
运行结果:
IndexError: list index out of range

x[-9]
运行结果:
IndexError: list index out of range

上面我们通过索引取出了列表中元素的值,现在我们希望通过值找到他的下标

x = ["a","b","c","d","e","f","g"]
x.index("d")  #index 可以通过type补齐,因为.index 是列表的内置方法 
运行结果:
3

help(list) 可以看到list有很多内置方法,但是终究还是增删改查,带下划线的方法可以忽略


列表的增删改查


增方法之append
yunwei = ["dailiang","network","hardware","software","DBA"]
yunwei.append("security")
print(yunwei)
运行结果:
['dailiang', 'network', 'hardware', 'software', 'DBA', 'security']

你发现新的元素追加到最后了

help(list.append)
运行结果:
    Help on method_descriptor:

    append(...)
        L.append(object) -> None -- append object to end


增方法之insert
help(list.insert)
运行结果:

    Help on method_descriptor:

    insert(...)
        L.insert(index, object) -- insert object before index
yunwei = ["dailiang","network","hardware","software","DBA"]
yunwei.insert(2,"python")
print(yunwei)
运行结果:
['dailiang', 'network', 'python', 'hardware', 'software', 'DBA']
yunwei = ["dailiang","network","hardware","software","DBA"]
yunwei.insert(3,"python")
print(yunwei)
运行结果:
['dailiang', 'network', 'hardware', 'python', 'software', 'DBA']
yunwei = ["dailiang","network","hardware","software","DBA"]
yunwei.insert(100,"python")
yunwei.insert(-100,"linux")
print(yunwei)
运行结果:
['linux', 'dailiang', 'network', 'hardware', 'software', 'DBA', 'python']

总结:insert方式操作的索引超出范围的化,如果为正索引,那么效果为append,如果是负索引,等同于insert(0,”元素”)

增方法之extend
help(list.extend)
运行结果:

    Help on method_descriptor:

    extend(...)
        L.extend(iterable) -> None -- extend list by appending elements from the iterable

iterable 可迭代的

a = [1,2,3]
b = [4 ,5,6]
a.extend(b)
print(a)
运行结果:
[1, 2, 3, 4, 5, 6]
a = [1,2,3]
b = range(10)
a.extend(b)
print(a)
运行结果:
[1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

我们发现列表里面可以有重复元素的


删方法之pop
help(list.pop)
运行结果:

    Help on method_descriptor:

    pop(...)
        L.pop([index]) -> item -- remove and return item at index (default last).
        Raises IndexError if list is empty or index is out of range.

pop 根据下标删除元素,默认为 -1 ,如果index超出索引或者列表为空,会抛出IndexError 异常

a = [1,2,3,4,5]
a.pop()
print(a)
运行结果:
[1, 2, 3, 4]
a = [1,2,3,4,5]
a.pop(0)
print(a)
运行结果:
[2, 3, 4, 5]
a = [1,2,3,4,5]    #索引超出限制
a.pop(100) # pop index out of range
运行结果:
a.pop(100) # pop index out of range
IndexError: pop index out of range
a = [1,2,3] #列表为空的情况
a.pop()
a.pop()
a.pop()
print(a)
a.pop()
运行结果:
[]
IndexError: pop from empty list


删方法之remove
help(list.remove)
运行结果:

    Help on method_descriptor:

    remove(...)
        L.remove(value) -> None -- remove first occurrence of value.
        Raises ValueError if the value is not present.
x = ["a","b","c","d","b"]
x.remove("a")
print(x)
运行结果:
['b', 'c', 'd', 'b']
x = ["a","b","c","d","b"]
x.remove("b")
print(x)
运行结果:
["a","c","d","b"]

可以看出是按照顺序删除的,remove删除第一个对应该value的元素

pop是根据索引删除元素,而remove方法是直接删除元素


删方法之clear
help(list.clear)
运行结果:

    Help on method_descriptor:

    clear(...)
        L.clear() -> None -- remove all items from L
x = ["a","b","c","d","b"]
x.clear()
print(x)
运行结果:
[]


删方法之del

前面的删除方式: pop、remove、clear都是列表的内置方法。而del并非列表的内置方法,可以用在元组、字典等多种数据结构

x = ["a","b","c","d","b"]
del x[0]
print(x)
运行结果:
['b', 'c', 'd', 'b']


改方法之reverse
help(list.reverse)
运行结果:
    Help on method_descriptor:

    reverse(...)
        L.reverse() -- reverse *IN PLACE*
x = ["a","b","c","d"]
x.reverse()
print(x)
运行结果:
['d', 'c', 'b', 'a']


改方法之sort
help(list.sort) #排序
运行结果:
    Help on method_descriptor:
    sort(...)
        L.sort(key=None, reverse=False) -> None -- stable sort *IN PLACE*
x = ["a","c","b","d","b"]
x.sort()
print(x)
运行结果:
['a', 'b', 'b', 'c', 'd']
x = [3,5,4,2,1]
x.sort()
print(x)
运行结果:
[1, 2, 3, 4, 5]
x = [3,5,4,2,1]
x.sort(reverse=False)
print(x)
x.sort(reverse=True)
print(x)
运行结果:
[1, 2, 3, 4, 5]
[5, 4, 3, 2, 1]


查找统计方式之index
x = ["a","b","c","d","e"]
x.index("b")
运行结果:
1

x[0]
运行结果:
'a'


查找统计方式之count
help(list.count)
运行结果:

    Help on method_descriptor:

    count(...)
        L.count(value) -> integer -- return number of occurrences of value
x = ["a","b","b","c","d","e"]
x.count("b")
运行结果:
2


查找统计方式之len

len 不是list的内置方法,而是一个函数

a = [1,2,3,4,5,6]
len(a)
运行结果:
6


列表的深浅copy

赋值
x = ["a","b","c","d","e"]
y = x   
print("--1--",y)
y.remove("a")
print("--2--",y)
print("--3--",x)
运行结果:
    --1-- ['a', 'b', 'c', 'd', 'e']
    --2-- ['b', 'c', 'd', 'e']
    --3-- ['b', 'c', 'd', 'e']

你发现你删除了y 里面的值,x的值也顺便删除了,这种是不能接受的 原理是这样的,y = x 只是把x对应的内存指针给指过来了

print(id(x))
print(id(y))
运行结果:
139674624008840
139674624008840

发现都是指向同一块内存地址,举例:一间房子两个门牌号而已,这种情况我们是不能接受的,所以我们又有了copy函数

浅copy (shallow copy)
help(list.copy)  #shallow copy 也叫做浅copy
运行结果:

    Help on method_descriptor:

    copy(...)
        L.copy() -> list -- a shallow copy of L
x = ["a","b","c","d","e"]
y = x.copy()
print("--1--",y)
y.remove("a")
print("--2--",y)
print("--3--",x)
print(id(x),id(y))
运行结果:
    --1-- ['a', 'b', 'c', 'd', 'e']
    --2-- ['b', 'c', 'd', 'e']
    --3-- ['a', 'b', 'c', 'd', 'e']
    139674623262472 139674623032584

现在你可能发现一切都完美了,但是看下面一个例子

x = ["a","b",["c","d","e"] ]
print(x,type(x))
运行结果:
['a', 'b', ['c', 'd', 'e']] <class 'list'>

x = ["a","b",["c","d","e"] ]
y = x.copy()
y[2][1] = "k"
print("---",x)
print("---",y)
运行结果:
    --- ['a', 'b', ['c', 'k', 'e']]
    --- ['a', 'b', ['c', 'k', 'e']]

浅copy只能改变一层内存地址,如果列表嵌套列表,那么是不行的,于是我们有了深copy的方法

deepcopy
import  copy
s = [[1,2],3,4]
s2 = copy.deepcopy(s) 
s2[0][1] = 'abc'
print('列表s:',s)
print('列表s2:',s2)
运行结果:
    列表s: [[1, 2], 3, 4]
    列表s2: [[1, 'abc'], 3, 4]

导入模块的例子:

>>> a = [1,2,3]
>>> b = copy.deepcopy(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'copy' is not defined
>>> import copy 
>>> b = copy.deepcopy(a)
>>> print(b)
[1, 2, 3]


元组

元组(tuple)其实跟列表差不多,也是存一组数,只不是它一旦创建,便不能再修改,所以又叫只读列表

创建空元组

a = ()
print(a,type(a))
b = tuple() 
print(b,type(b))
运行结果:
    () <class 'tuple'>
    () <class 'tuple'>

因为元组一旦被创建,就不能够被修改,所以创建空元组基本没有意义的

元组的方法

x = (1,2,3)
print(x,type(x))
运行结果:
(1, 2, 3) <class 'tuple'>
输入tuple. tab补全,发现tuple只有 count 和index
x = ("a","b","b","c","d")
print(x.count("b"))
print(x.index("b"))  #找到第一个就不往下查找了
len(x)
运行结果:
2
1
5


x[1]
运行结果:
'b'

x[1] = "z"
运行结果:
TypeError: 'tuple' object does not support item assignment


列表与元组的区别

  • 列表与元组最大的区别,就是元组不可变
  • 元组是可hash的
a = [1,2,3,4]
b = (1,2,3,4)
hash(a)
运行结果:
TypeError: unhashable type: 'list'

hash(b)
运行结果:
485696759010151909

这个功能我们在讲字典的时候会讲,就先记住这个知识点即可

在讲字典时我们会讲到,字典的key要求是必须可hash的,所以元组可以作为字典的key,而list不行


线性结构

列表、元组、字符串是线性结构(线性结构是一个有序数据元素的集合),线性结构可以做切片操作
之所以说它有序,因为它可以使用下标的方式把元素取出来

线性结构可以做切片操作,解包和封包 ,而成员运算符,遍历操作 只要是可迭代对象都可以,比如集合虽不是线性结构,但也是可迭代对象,也可以用 for 循环遍历,我们先来说一下什么叫做切片操作

线性结构的切片操作


列表的切片
a = ["a","b","c","d","e","f","g","h","i","j"]
b = a[0:2]
print(b)
运行结果:
 ['a', 'b']

你会发现上面的是半开区间的,这就叫做切片的“顾头不顾尾”原则

a = ["a","b","c","d","e","f","g","h","i","j"]
b = a[0:10000]
print(b)
运行结果:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']


a = ["a","b","c","d","e","f","g","h","i","j"]
b = a[0:-1]
print(b)
运行结果:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

切片操作最后一个值不写,那么代表取全部的值

a = ["a","b","c","d","e","f","g","h","i","j"]
b = a[0:]
print(b)
运行结果:
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']

切片操作也可以前面的值不写,那么这个值默认为0,不常用

a = ["a","b","c","d","e","f","g","h","i","j"]
b = a[:-1]
print(b)
运行结果:
    ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']


元组的切片操作
x = ("a","b","c","d","e","f","g","h","i","j")
x[0:4]
运行结果:
('a', 'b', 'c', 'd')


切片的步长
x = ("a","b","c","d","e","f","g","h","i","j")
x[0:4:2]
运行结果:
('a', 'c')

切片步长默认是1,那么步长为负数呢??

x = list(range(10)) #如果用list() 方式来创建列表,list() 内的值必须为一个可迭代对象
print(x)
运行结果:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
x = list(range(10))
y = x[0:8:-1]
print(y)
运行结果:
[]

步长为负,为何是空列表呢? 步长为负时,要求切片的起始值大于结束值

x = list(range(10))
y = x[8:0:-1]
print(y)
运行结果:
[8, 7, 6, 5, 4, 3, 2, 1]
x = list(range(10))
y = x[8:0:-2]
print(y)
运行结果:
[8, 6, 4, 2]


x = list(range(10))
y = x[:0:-1]
print(y)
运行结果:
[9, 8, 7, 6, 5, 4, 3, 2, 1]


x = list(range(10))
y = x[9::-1]
print(y)
运行结果:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

我们之前说过反转列表使用reverse

x = list(range(10))
x.reverse()
print(x)
运行结果:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

我们现在有了第二个方式来反转列表

x = list(range(10))
y = x[::-1]
print(y)
运行结果:
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]


线性结构的解包和封包

线性结构之pack & unpack(封包,解包)

封包

什么叫做封包?把一组变量打包为一个元组叫做pack,也叫封包
* 封包出来的一定是元组 *

x = 1,3
print(x,type(x))
运行结果:
(1, 3) <class 'tuple'>
x = 1,[1,2,3],(4,5,6)
print(x,type(x))
运行结果:
(1, [1, 2, 3], (4, 5, 6)) <class 'tuple'>


解包
x,y = (1,3)
print(x)
print(y)
运行结果:
1
3
x,y = [1,3]
print(x)
print(y)
运行结果:
1
3
x,y = (1,2,3) #数量必须一致
运行结果:
ValueError: too many values to unpack (expected 2)

我们来举一个封包、解包的例子:

z = (1,3) #封包为元组
a,b = z 
print(a,b)
运行结果:
1 3

我们可以把封包的过程省略:

a,b = 1,3
print(a,b)
运行结果:
 1 3


解包与封包的初级作用

我们通过一个例子来了解:解包与封包的实际作用
比如 a = 1 , b =2 ,我们定义了两个变量,现在我想把他们两个的值调换以下,应该怎么办?

def change(a,b):
    i = b 
    b = a 
    a = i 
    return (a,b)

change(1,3)
运行结果:
(3, 1)

但是我们可以通过解包封包的思想来看以下这个问题:
先把 a,b 封包成一个元组c

a = 1
b = 3
#封包
c = a,b 
#print(c)
#解包
b,a =c 
print(a)
print(b)
运行结果:
3
1

再把封包过程省略

a = 1 
b = 3 
b,a = a,b 
print(a,b)
运行结果:
3 1


解包的高级应用:
head,*tail = list(range(10))
print(head)
print(tail)
运行结果:
0
[1, 2, 3, 4, 5, 6, 7, 8, 9]
head , *mid ,tail = list(range(0,10))
print(head)
print(mid)
print(tail) 
运行结果:
0
[1, 2, 3, 4, 5, 6, 7, 8]
9

ok,前面我们一直在对列表 做解包操作,现在我们对元组做一下解包操作

head , *mid ,tail = tuple(range(0,10))
print(head)
print(mid)
print(tail)
运行结果:
0
[1, 2, 3, 4, 5, 6, 7, 8]
9

你会发现mid也是返回列表的形式,所以结论是:无论是unpack任意值,*asg 永远返回的是列表

封包永远是封成元组,解包如果有*asg,那么*asg永远是列表

* 不能单独存在

*tail = tuple(range(0,10))
运行结果:
      File "<ipython-input-278-0a880552cf3e>", line 1
        *tail = tuple(range(0,10))
                                  ^
    SyntaxError: starred assignment target must be in a list or tuple

不能同时存在多个*

head , *mid ,*tail = tuple(range(0,10))
运行结果:
      File "<ipython-input-279-feac08157463>", line 1
        head , *mid ,*tail = tuple(range(0,10))
                                               ^
    SyntaxError: two starred expressions in assignment

强调:head ,tail ,mid 只是为了方便大家理解,而定义的变量,换成a b c 等任意字符均可

x , *y ,z = tuple(range(0,10))
print(y)
运行结果:
[1, 2, 3, 4, 5, 6, 7, 8]

python的一个惯例,使用单个下划线表示需要丢弃的变量,只是约定俗称,当然你可以不遵守,后果就是降低代码可读性

head ,*_,tail = list(range(10))
print(_)
运行结果:
[1, 2, 3, 4, 5, 6, 7, 8]


多层解构

题目:Q = [“a”,”b”,”c”,”d”] ,使用解构方式取出正数第二个和倒数第二个值

Q = ["a","b","c","d"]
head,*mid,tail = Q
print(mid)
运行结果:
['b', 'c']
head,tail = mid
print(head,tail)
运行结果:
b c

更好的方式

Q = ["a","b","c","d","e","f"]
_,x,*_,y,_ = Q
print(x,y)
运行结果:
b e

实际工作中,我们一般这样用:
比如我们会经常遇到key,value类型的配置文件,例如ip=127.0.0.1 之类的,我们可以通过解构的方式,轻松的把key和value取出来

s = "ip=127.0.0.1"
print(s,type(s))
运行结果:
ip=127.0.0.1 <class 'str'>


s.partition("=")
运行结果:
('ip', '=', '127.0.0.1')


ip,*_,value = s.partition("=")
print(ip)
print(value)
运行结果:
ip
127.0.0.1

迭代

迭代:在python中表现就是用for循环,从对象中获得一定数量的元素
将for循环用于列表、字符串、字典的键值对,这就是迭代
迭代并不只是线性结构特性,比如集合set ,也可以使用for循环进行迭代
可以迭代的都叫做可迭代对象(iterable)

name = "dai"
for i in name :
    print(i)
运行结果:
d
a
i
name = ["a","b","c"]
for i in name :
    print(i)
运行结果:
a
b
c
name = {"a","b","c"}  #集合内的元素没有顺序,不是线性结构,不能取索引和下标
print(name ,type(name))
for i in name:
    print(i)
运行结果:
{'a', 'c', 'b'} <class 'set'>
a
c
b

成员运算符in 与 not in

成员运算符可以不用遍历对象语句类似于for i in ,直接in 或者 not in 即可

c = ["a","b","c","d","e"]

if "c" in c :
    print("ok")
else:
    print("not")
运行结果:
ok
name = {"a","b"}
if "a" not in name :
    print("yes")
else:
    print("no")
运行结果:
no