Python 字典

过程

在字典中,先根据需求来获得字典,然后就是先使用它增删查改,然后就是一些主意的事项了。
创建字典
查询字典内容
更改字典的值
删除字典的值
字典内置的函数&方法

简单介绍字典的用途

在数据中,具有键-值(key-value)存储,具有极快的查找速度。使用字典,我们就可以通过字符串来获取到我们想要的信息。


创建字典

字典是有键值对组成的一种容器。那如何创建它呢?

1
2
>>> dict = {'d1':'dict1', 'd2':'dict2', 'd3':'dict3', 'd4':'dict4'}
>>> print dict

结果如下

1
{'d4': 'dict4', 'd2': 'dict2', 'd3': 'dict3', 'd1': 'dict1'}

这样,我们的字典创建就可以了,以key-value 的形式作为元素哦。

关于字典的键(key)

value 可以没有限制地取任何python对象,但是 key 就需要记住两个:

  1. 不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     >>> dict = {'name':'hello', 'name':'oh'}
    >>> print dict
    {'name': 'oh'}
    # 只有一个值,那就是最后同名的那个值
    ```

    2. `键`必须不可变,所以可以用`数`,`字符串`或`元组`充当。
    ``` python
    >>> dict = {8:'bye', 'you':'coder'} # 包括了 数 '8', 字符串 'you'
    >>> print dict
    {8: 'bye', 'you': 'coder'}
    >>> print 'dict[8]' + dict[8] + ', dict[\'you\']' + dict['you']
    dict[8]bye, dict['you']coder

查询字典的值

字典的查询就不难了,依照上面的字典。试一试

1
2
3
4
5
>>> dict = {8:'bye', 'you':'coder'} # 包括了 数 '8', 字符串 'you'
>>> dict[8]
'bye'
>>> dict['you']
'coder'

通过键我们就可以访问到字典对应的值了,不会像数组那样从 index 0 开始了。

但是如果我们查询的键没有呢?就会出错。

1
2
3
4
>>> dict[9]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 9

那么怎么样才知道它有没有这个键(key)呢? 使用方法 has_key([key])

1
2
3
4
5
>>> dict.has_key(9)
False
>>> dict.has_key(8)
True
# 这样我们就可以在脚本中去判断键的存在咯。

那如果出现Python Error:TypeError: string indices must be integers, not str呢
请参照Python Error:TypeError: string indices must be integers, not str


更改字典的值

修改字典的值,就很容易了。获取到对应键的值,再赋值就好了。

1
2
3
4
5
>>> print dict[8]
bye
>>> dict[8]=80
>>> print dict[8]
80

结果就是这样简单啦。


删除字典的值

删除字典有两种

  1. 删除单一元素 del

    1
    2
    3
    4
    5
    6
    >>> dict = {8:'bye', 'you':'coder'}
    >>> print dict
    {8: 'bye', 'you': 'coder'}
    >>> del dict[8] # 删除元素
    >>> print dict
    {'you': 'coder'}
  2. 清空字典 dict-instance.clear()

    1
    2
    3
    4
    >>> dict = {8:'bye', 'you':'coder'}
    >>> dict.clear() # 清空字典元素啦。。。。
    >>> print dict
    {}

字典内置的函数&方法

内置函数

1
2
3
4
5
6
7
cmp(dict1, dict2):  比较两个字典元素。

len(dict): 计算字典元素个数,即键的总数。

str(dict): 输出字典可打印的字符串表示。

type(variable): 返回输入的变量类型,如果变量是字典就返回字典类型。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
radiansdict.clear():                      删除字典内所有元素

radiansdict.copy(): 返回一个字典的浅复制

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

radiansdict.get(key, default=None): 返回指定键的值,如果值不在字典中返回default值

radiansdict.has_key(key): 如果键在字典dict里返回true,否则返回false

radiansdict.items(): 以列表返回可遍历的(键, 值) 元组数组

radiansdict.keys(): 以列表返回一个字典所有的键

radiansdict.setdefault(key, default=None):和get()类似, 但如果键不已经存在于字典中,将会添加键并将值设为default

radiansdict.update(dict2): 把字典dict2的键/值对更新到dict里

radiansdict.values(): 以列表返回字典中的所有值

参考链接

Python setattr 使用和分析

setattr 讲解

1
2
3
4
5
6
setattr(	object, name, value)

# 参数就是一个对象,name是可能是现有的属性或者是一个可以新建的属性,value为该属性的值。
#
# 这样,我们可以动态的生成属性
# 记住,name 和 value 都是字符串值哦。

setattr 实践

代码来源
首先,去掉 第15行的注释运行,结果显示如下

1
2
3
4
5
6
$ python py_setattr.py
attr4 exists?
Traceback (most recent call last):
File "py_setattr.py", line 15, in <module>
print T.attr4
AttributeError: 'test' object has no attribute 'attr4'

再加上注释,运行

1
2
3
4
5
$ python py_setattr.py                        
attr4 exists?
create new attribute <attr4> test4
attribute <attr3>:test3
changed attribute <attr3> :test3_changed

参考链接

Mysql 表内容的插入

INSERT

表插入的语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
VALUES ({expr | DEFAULT},...),(...),...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
或:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name
SET col_name={expr | DEFAULT}, ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]
或:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

实验证明

  • 如果列清单和VALUES清单均为空清单,则INSERT会创建一个行,每个列都被设置为默认值:

    1
    INSERT INTO tbl_name () VALUES();
  • 假设worker表只有name和email,插入一条数据

    1
    INSERT INTO worker VALUES(“tom”,”tom@yahoo.com”);
  • 批量插入多条数据

    1
    INSERT INTO worker VALUES(‘tom','tom@yahoo.com'),(‘paul','paul@yahoo.com');
  • 给出要赋值的那个列,然后再列出值的插入数据

    1
    insert into worker (name) values ('tom');

参考链接

Mysql 视图创建

关于视图 - 简单看看(如果不想知道视图用来干嘛的,那就跳过咯)

SQL 中,视图时基于SQL语句的结果集的可视化的表

视图包含行和列,就像一个真实的表一样。

视图中的字段来自于一个或者多个数据库中的表的字段。

结果就是感觉就是单一的一张表,也可以说是间接的表啦。

使用视图,主要是为在操作数据库的时候,不在需要频繁多次去读取和处理不同字段,再进行第二次的处理形成我们所需要的数据。在这一步上面,我们可以提高效率,得到我们所需要的内容哦。

这样,我们可以把多张表合并成一张表,经过过滤之后的一张表哦。

视图是一种虚拟的表。视图从数据库中的一个或多个表导出来的表。视图还可以从已经存在的视图的基础上定义。数据库中只存放了视图的定义,而并没有存放视图中的数据。这些数据存放在原来的表中。使用视图查询数据时,数据库系统会从原来的表中取出对应的数据。因此,视图中的数据是依赖于原来的表中的数据的。一旦表中的数据发生改变,显示在视图中的数据也会发生改变。

视图是在原有的表或者视图的基础上重新定义的虚拟表,这可以从原有的表上选取对用户有用的信息。那些对用户没有用,或者用户没有权限了解的信息,都可以直接屏蔽掉。这样做既使应用简单化,也保证了系统的安全。视图起着类似于筛选的作用。视图的作用归纳为如下几点:
1.使操作简单化
2.增加数据的安全性
3.提高表的逻辑独立性

[注释:数据库的设计和结构不会受到视图中的函数、where 或 join 语句的影响。]

OK,实际上。意思就是把多张表经过处理后的到一张整理过的,有需要的一张表,但是这个表的操作不会影响到原表的完整性,读它就可以啦。

创建视图

语法:

1
2
3
4
CREATE VIEW viewName AS
SELECT column_name(s)
FROM table_name
WHERE condition

[注释:视图总是显示最近的数据。每当用户查询视图时,数据库引擎通过使用 SQL 语句来重建数据。]

实践检验问题

可以从某个查询内部、某个存储过程内部,或者从另一个视图内部来使用视图。通过向视图添加函数、join 等等,我们可以向用户精确地提交我们希望提交的数据。

需要准备数据文件来做好操作的准备,里面是关于教师和学生的一个数据库表。

走起

创建视图

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
27
mysql> CREATE VIEW student_teacher AS
-> SELECT sname, tname
-> FROM student, teacher
-> WHERE student.tno=teacher.tno;

Query OK, 0 rows affected (0.13 sec)

mysql> select * from student_teacher;
+-------+-------+
| sname | tname |
+-------+-------+
| sa | wa |
| sb | wa |
| sc | wa |
| sd | wa |
| se | wa |
| sf | wa |
| sg | wa |
| sh | wa |
| si | wa |
| sj | wa |
| sk | wa |
| sl | wa |
| sm | wa |
| sn | wa |
+-------+-------+
14 rows in set (0.06 sec)

这样,我们就可以得到了关于教师和学生的一个列表,但是我们并不知道这个是来自于两个表哦。

更新视图

1
2
3
4
5
6
7
8
SQL CREATE OR REPLACE VIEW Syntax

CREATE OR REPLACE VIEW view_name AS
SELECT column_name(s)
FROM table_name
WHERE condition

------------------------

这个是一个简单的例子。

撤销视图

1
2
3
4
5
6
SQL DROP VIEW Syntax
DROP VIEW view_name

------------------------
mysql> DROP VIEW student_teacher;
Query OK, 0 rows affected (0.30 sec)

参考链接

Mysql 建立表和删除表

创建表

  • CREATE TABLE tableName

    1
    2
    3
    4
    5
    mysql> CREATE TABLE person (
    number INT(11),
    name VARCHAR(255),
    birthday DATE
    );
  • CREATE TABLE IF NOT EXISTS tableName

    1
    2
    3
    4
    5
    mysql> CREATE TABLE IF NOT EXISTS person (
    number INT(11),
    name VARCHAR(255),
    birthday DATE
    );

删除表

  • DROP TABLE tableName

    1
    mysql> DROP TABLE  tbl_name;
  • DROP TABLE IF EXISTS tableName

    1
    mysql> DROP TABLE IF EXISTS tbl_name;

参考链接

Mysql 建立数据库和删除数据库

创建数据库

  • CREATE DATABASE databaseName

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     mysql> CREATE DATABASE test;
    Query OK, 1 row affected (0.05 sec)
    mysql> SHOW DATABASES;
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | demo |
    | mysql |
    | performance_schema |
    | studentSystem |
    | sys |
    | test |
    | zh |
    +--------------------+
    8 rows in set (0.03 sec)
  • CREATE DATABASE IF NOT EXISTS databaseName

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    mysql> CREATE DATABASE IF NOT EXISTS test1;
    Query OK, 1 row affected (0.00 sec)

    mysql> SHOW DATABASES;
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | demo |
    | mysql |
    | performance_schema |
    | studentSystem |
    | sys |
    | test |
    | test1 |
    | zh |
    +--------------------+
    9 rows in set (0.00 sec)

删除数据库

  • DROP DATABASE databaseName

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    mysql> DROP DATABASE test;
    Query OK, 0 rows affected (0.05 sec)

    mysql> SHOW DATABASES;
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | demo |
    | mysql |
    | performance_schema |
    | studentSystem |
    | sys |
    | test1 |
    | zh |
    +--------------------+
    8 rows in set (0.03 sec)
  • DROP DATABASE IF EXISTS databaseName

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    mysql> DROP DATABASE IF EXISTS test1;
    Query OK, 0 rows affected (0.00 sec)

    mysql> SHOW DATABASES;
    +--------------------+
    | Database |
    +--------------------+
    | information_schema |
    | demo |
    | mysql |
    | performance_schema |
    | studentSystem |
    | sys |
    | zh |
    +--------------------+
    7 rows in set (0.00 sec)

参考链接

Python 连接 Mysql 数据库

连接 mysql 数据库

使用 MySQLdb 来做为连接 mysql 数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 import MySQLdb
 
try:
# host 表示主机类型
# user 登录的用户
# passwd 登录密码
# db 登录的数据库
# port 端口号,在本地情况下可以不用写
    conn=MySQLdb.connect(host='localhost',user='root',passwd='root',db='test',port=3306) # 连接数据库
    cur=conn.cursor() # 获取数据库的指针
    cur.execute('select * from user') # 数据库操作
    cur.close() # 关闭数据库的指针
    conn.close() # 关闭数据库
except MySQLdb.Error,e: # 数据库连接失败。
      print "Mysql Error %d: %s" % (e.args[0], e.args[1])

问题

如果出现了这种情况

1
2
3
4
 Traceback (most recent call last):
File "db_test.py", line 1, in <module>
import MySQLdb
ImportError: No module named MySQLdb

说明没有安装相应的库

安装 MySQLdb

Python下的Mysql模块MySQLdb安装详解
下载Mysql模块MySQLdb

参考链接

Python 函数返回多值的分析

函数返回多值的原理

实际上,函数返回多值的内容就是一个 tuple

我们来看看表面

1
2
3
4
5
6
import math

def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny

这样我们就可以同时获得返回值:

1
2
3
>>> x, y = move(100, 100, 60, math.pi / 6)
>>> print x, y
151.961524227 70.0

哟呵,真的可以返回多值耶。

实际的原理

Python函数返回的仍然是单一值:

1
2
3
>>> r = move(100, 100, 60, math.pi / 6)
>>> print r
(151.96152422706632, 70.0)

其实就是一个 tuple,实际就是这样,并没有那么神秘嘛。

参考链接

KVO

KVO 基础

解释: Key-Value observing 就是某个对象的属性改变时通知其他对象的机制。对于被观察对象来说,键值观察(KVO)就是注册想要监视的属性的键路径和观察者

目的: 为了在GUI组件和程序之间调整值

过程: 当属性改变的时候,观察者就会接收到消息,虽然和 NSNotification 通知相似,但是 KVO 不存在通知中心的对象,所以不可以指定消息的选择器。

KVO 可以实现监视属性, 一对一的关系, 一对多关系等各种形式的属性,可以使用 NSObject 来实现的。

KVO 准则

使用 键值编码的准则 来访问 访问器 或者 实例变量 的情况下,才可以监视属性的变化。

在方法内直接改变实例变量的变量值是不能被监视的 > 实例验证代码

结果显示:

1
2
3
$ clang kvcsample.m -fobjc-arc -framework Foundation
$ ./a.out
$

并没有结果

准则具体如下

  1. 访问器方法而改变 - 这个时候访问器就是 @proeprty 所产生的 get 和 set 的方法名字。
  2. 使用 setValue:forKey: 和键进行改变。此时可能不经过访问器
  3. 使用 setValue:forKeyPath: 和键路径进行变化,也可能不经过访问器。不仅仅是最终的监视对象的属性,当路径中的属性发生变化时也会被通知。

KVO 的方法

  • 注册监视
    1
    2
    3
    4
    - (void) addObserver:(NSObject \*) anObserver
    forKeyPath:(NSString \*) keyPath
    options:(NSKeyValueObservingOptions) options
    context:(void *)context**

监视键路径 keyPath 中的某个属性,观察者anObserver,消息的发送者为被观察者

属性发生变化的时候,就会发送通知消息。

消息包含变化内容的字典数据,context 中指定的任意指针。

options 指定字典数据包含什么样的值。
NSKeyValueObservingOptionNew … 提供改变后的属性值
NSKeyValueObservingOptionOld … 提供改变前的属性值。

当属性改变的时候,下面的消息将会发送给观察者。

  • 获取监视通知
    1
    2
    3
    4
    - (void)observeValueForKeyPath:(NSString *) keyPath
    ofObject:(id)object
    change:(NSDictionary *)change
    context:(void *)context

change 保存着改变的相关信息,context 返回注册观察者时指定的值。

如果要停止监视,实现一下方法

  • 停止监视

    1
    2
    - (void)removeObserver: (NSObject *) anObserver
    forKeyPath: (NSString *) keyPath
  • change 字典中保存的入口
    NSKeyValueChangeKindKey

    属性改变的种类
    

    NSKeyValueChangeNewKey

    属性的新对象的值
    

    NSKeyValueChangeOldKey

    属性旧对象的值
    

    NSKeyValueChangeIndexesKey

    动态数组中进行了插入,删除,置换。表示执行了这些操作的索引集合 --- NSIndexSet 类
    的实例为入口值
    

验证

用于验证的代码

结果显示:

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
27
28
29
30
31
32
33
34
35
--- Received by <<Person, Jiro, HP=140>> ---
Object=<<Person, Taro, HP=800>>, Path=hitPoint
Change={
kind = 1;
new = 800;
old = 500;
}
--- Received by <<Dragon, Choco, HP=400>> ---
Object=<<Dragon, Choco, HP=400>>, Path=master.hitPoint
Change={
kind = 1;
new = 800;
old = 500;
}
--- Received by <<Dragon, Choco, HP=400>> ---
Object=<<Dragon, Choco, HP=400>>, Path=master.hitPoint
Change={
kind = 1;
new = 140;
old = 600;
}
--- Received by <<Person, Jiro, HP=140>> ---
Object=<<Person, Taro, HP=500>>, Path=hitPoint
Change={
kind = 1;
new = 500;
old = 600;
}
--- Received by <<Dragon, Choco, HP=400>> ---
Object=<<Dragon, Choco, HP=400>>, Path=master.hitPoint
Change={
kind = 1;
new = 340;
old = 140;
}

代码的结果分析
(1) 改变 p1 的 hitPoint,并确实向 p2 和 dra 发送了消息
(2) 虽然调用了更改 hitPoint 的消息,但是没有收到相应的消息
(3) 改变了 master ,收到了 master.hitPoint 的消息。即使不是指定的键路径的属性,在产生改变时也会被通知
(4),(5) 使用声明属性改变了 p2, p1 的 hitPoint 也可以被监视。
(6) 删除了通知后就收不到了。

名词解释

被观察者

1
属性值发生改变的时候,会被观察者了解到它的发生情况

观察者

1
设置观察对象的主动者

KVC 键路径的访问

路径访问简介

路径访问就是在类中还有类的实例,那么如何深层次的去访问呢?
通过路径访问的方式去实现

方法调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
以点切分键路径,并使用第一个键接收器发送 valueForKey: 方法,然后再使用键路径的下一个键,向
得到的对象发送 valueForKey: 的方法,反复直到返回最后获得的对象。

*/

- (id) valueForKeyPath: (NSString *)keyPath

/**
与 valueForKeyPath: 方法同样取出对象,这里只对路径中的最后一个键调用 setValue:forKey:
方法,并设定其属性 value.

*/

- (void) setValue: (id)value
forKeyPath: (NSString *) keyPath

实验证明

两个类

  • Person

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @interface Person: NSObject
    {
    NSString *name;
    NSString *email;
    int age;
    }

    @end
    @implementation Person
    @end
  • WorkingGroup

    1
    2
    3
    4
    5
    6
    7
    8
    @interface WorkingGroup: NSObject
    {
    Person *leader; // the leader
    }
    @end

    @implementation WorkingGroup
    @end

main.m

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
27
28
int main(void)
{


@autoreleasepool{
NSLog(@"start");

Person *p = [[Person alloc] init];
[p setValue:@"hehe" forKey:@"name"];

WorkingGroup *aGroup = [[WorkingGroup alloc] init];
[aGroup setValue:p forKey:@"leader"];

NSLog(@"start to move");

id aPerson = [aGroup valueForKey:@"leader"];
id name = [aPerson valueForKey:@"name"];

NSLog(@"without path => name: %@", name);

// 这里实现 键路径的查询
id p_name = [aGroup valueForKeyPath:@"leader.name"];

NSLog(@"with path => name: %@", p_name);

}

return 0;
}

结果

1
2
3
4
5
6
$ clang keyPathOperation.m -framework Foundation
$ ./a.out
2016-03-14 00:30:52.111 a.out[3880:429793] start
2016-03-14 00:30:52.112 a.out[3880:429793] start to move
2016-03-14 00:30:52.113 a.out[3880:429793] without path => name: hehe
2016-03-14 00:30:52.113 a.out[3880:429793] with path => name: hehe