从 JavaScript 角度学 Python(10) - 容器型别(下)

前言

前一篇我们聊了一些字典有趣的取值方式,所以接下来我想接着继续聊关於字典的部分。

字典取值

在 JavaScript 中我们时常会使用到两个很好用的 ES6 语法取出物件属性名称与物件属性值,没有错,就是 Object.keys()Object.values(),而这两个语法都有异曲同工之处,底层实作会将物件中的属性名称与值使用 for...in 全部跑过一次并回传其结果,而回传的结果会是一个阵列。

Object.keys() 来讲就是回传物件的属性:

var obj = {
  myName: 'Ray',
  a: '1',
  b: '2',
  fn() {
    console.log('123')
  }
};

console.log(Object.keys(obj)); //  [ "myName", "a", "b", "fn" ]

Object.values() 则是回传属性的值:

var obj = {
  myName: 'Ray',
  a: '1',
  b: '2',
  fn() {
    console.log('123')
  }
};

console.log(Object.values(obj)); //  [ "Ray", "1", "2", fn() ]

可以看到如果是函式的话,就会直接回传你一个函式。

那麽 Python 也有相同的功能吗?有的,一样也是叫做 keysvalues

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

print(dis.keys()) # dict_keys(['myName', 'a', 'b'])
print(dis.values()) # dict_values(['Ray', '1', '2'])

看到 dict_keysdict_values,不用太害怕,它只是告诉你这是字典的 keysvalues 而已。

但是这边要注意,如果你直接使用 dis.keys()[0] 取值是会出现错误的:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

print(dis.keys()[0]) # TypeError: 'dict_keys' object is not subscriptable

有没有觉得自己好像被阴了一下?

https://ithelp.ithome.com.tw/upload/images/20210910/20119486BXK0qV21aG.png

毕竟我们在 JavaScript 中使用 Object.keys()Object.values() 之後就可以直接执行一些阵列操作方法,但是在 Python 是必须额外处理的,因此你必须使用 list() 将它转换成串列,这样子才能够正确的取值:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

print(list(dis.keys())[0]) # myName
print(list(dis.values())[0]) # Ray

最後一个则是 Python 的 items 方法,而 items 与 JavaScript 的 Object.entries 非常雷同,会将属性与值一起都回传出来:

var obj = {
  myName: 'Ray',
  a: '1',
  b: '2',
};

console.log(Object.entries(obj)); // [ [ "myName", "Ray" ], [ "a", "1" ], [ "b", "2" ] ]

但是在讲 items 方法之前,先让我跳来讲另一个前面没有讲到的东西东西也就是 元组(Tuple)

元组(Tuple)

元组很特别,它是一个类似串列的容器,看到这边可能有些写过 TypeScript 的人会很兴奋,毕竟 TypeScript 中也有一个叫做元组的型别:

const a: [string, number];
a = ['Ray', 1];
console.log(a[0]); // Ray

https://ithelp.ithome.com.tw/upload/images/20210910/20119486ryluI6cphm.png

但是在 Python 的元组宣告方式是使用括号 () 来宣告,除此之外它还有一个特性,元组是 read only (唯读) 的,当你宣告了这个元组之後你就无法再更改它,但取值的方式与串列没有差异:

tpe = (1, 2, 3)
print(tpe[0]) # 1

只要你做出了修改值的行为就会出现错误:

tpe = (1, 2, 3)
tpe[0] = 10 # TypeError: 'tuple' object does not support item assignment
print(tpe[0])

所以如果你有需要修改的需求,那麽还是会建议你使用串列就好:

tpe = [1, 2, 3]
tpe[0] = 10
print(tpe) # [10, 2, 3]

回到 items 的部分,为什麽要先讲元组呢?因为使用 items 取出来的字典会是一个元组:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

print(list(dis.items())) # [('myName', 'Ray'), ('a', '1'), ('b', '2')]

这就是为什麽要先拉过来介绍元组了,因为使用 items 取出来的串列都会是唯读不可修改:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}
print(list(dis.items())) # [('myName', 'Ray'), ('a', '1'), ('b', '2')]
print(list(dis.items())[0]) # ('myName', 'Ray')
print(list(dis.items())[0][1]) # 'Ray'

list(dis.items())[0][1] = 'Ray2' # TypeError: 'tuple' object does not support item assignment

元组中的字典

虽然我们前面有说明到元祖本身是 read only (唯读):

tup = (1, 2, 3)
tup[0] = 1 # TypeError: 'tuple' object does not support item assignment

可是如果今天修改的是元组内的字典属性可以不可以呢?答案基本上是可以的:

tup = ({
  'myName1': 'Ray1'
},{
  'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'

那麽这是为什麽?主要原因是我们是修改的字典中的属性,并不是修改本身元组所指向的字典记忆点位置,因此就可以修改字典的值,甚至是新增另一个属性也可以:

tup = ({
  'myName1': 'Ray1'
},{
  'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
tup[0]['blog'] = 'Welcome.Web.World - Ray Blog'

除非你今天是重新指向给它新的字典位置才会出现错误:

tup = ({
  'myName1': 'Ray1'
},{
  'myName2': 'Ray2'
})
tup[0]['myName1'] = 'QQ'
tup[0]['blog'] = 'Welcome.Web.World - Ray Blog'
tup[0] = {} # TypeError: 'tuple' object does not support item assignment

而这边的概念就 JavaScript 中的 const obj = {}; 的概念是非常雷同的唷。

in 运算子

最後额外补充聊一下 in 运算子,基本上这个运算子的概念就如同 JavaScript 的 Object.hasOwnProperty 方法,hasOwnProperty 可以用於寻找该属性是否存在於这个物件中:

var obj = {
  myName: 'Ray',
}
obj.hasOwnProperty('myName'); // true

而 Python 中的 in 运算子也是一样的存在,如果存在就会回传 True,如果不存在就是 False,但是这个运算子的写法是属性在前,字典在後:

dis = {
  'myName': 'Ray',
  'a': '1',
  'b': '2',
}

print('myName' in dis) # True

透过阅读程序码就可以很明确的知道这一段正在表达「字串 myName 在不在 dis 字典中。」这一段话。

题外话,其实 JavaScript 也有 in 运算子,只是我自己很少使用:

var obj = {
  myName: 'Ray',
}

console.log('myName' in obj); // true

作者的话

这几天算是把花雕酒给消耗完毕了,但是跑去逛全联时却一个脑弱不小心又败了一瓶绍兴酒回来...看来又要开始制作醉鸡之路了...

关於兔兔们

兔法无边


<<:  Day 9 - Event

>>:  每个人都该学的30个Python技巧|技巧 11:回圈二部曲—while回圈(字幕、衬乐、练习)

5. Html&Css&Javascript(上)

介绍 html(Hypertext Markup Language)是一种标记语言,就是里面的标记有...

Day 8 - [Zenbo开发系列] 05-DDE回覆规则设计

这篇会写如何设计 DDE 语料库,还有 DDE 设计的逻辑。 终於来到第五篇,这次截图比较多,主要是...

#24 数据中中的特徵相关性(3)

基於上篇,有了数据特徵,再来就可以把欧氏距离发展为马氏距离公式 马氏距离公式(Mahalanobis...

Day18:[排序演算法]Selection Sort - 选择排序法

其实插入排序法就很像平时我们在玩扑克牌时整理牌组的行为,将扑克牌依照大小插入对应的位置,插入排序法...

Day21 - Spinner(一)

Spinner下拉式选单 这也很常用在表单中 如:选择地区、居住地、选择语言、学校 那今天就来学习点...