python 学习笔记,之前有两篇笔记,因为太多了,所以新开一篇。
python 中常见的判别函数
isinstance()
判断一个item 是否是list or tuple
1
2
3
4
5
6
7
8
|
def myextend(alist):
blist = []
for item in alist:
if isinstance(item, (list, tuple)):
blist.extend(myextend(item))
else:
blist.append(item)
return blist
|
基本类型对于 classinfo
可以是
1
|
int,float,bool,complex,str(字符串),list,dict(字典),set,tuple
|
isinstance() 与 type() 区别:
- type() 不会认为子类是一种父类类型,不考虑继承关系。
- isinstance() 会认为子类是一种父类类型,考虑继承关系。
如果要判断两个类型是否相同推荐使用 isinstance()。
1
2
3
4
5
6
7
8
9
10
|
class A:
pass
class B(A):
pass
isinstance(A(), A) # returns True
type(A()) == A # returns True
isinstance(B(), A) # returns True
type(B()) == A # returns False
|
- 针对字符串的判别函数
1
2
3
4
5
6
7
|
s.isalnum() 所有字符都是数字或者字母
s.isalpha() 所有字符都是字母
s.isdigit() 所有字符都是数字
s.islower() 所有字符都是小写
s.isupper() 所有字符都是大写
s.istitle() 所有单词都是首字母大写,像标题
s.isspace() 所有字符都是空白字符、\t、\n、\r
|
- 对于数字的判别
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
isdigit()
True: Unicode数字,byte数字(单字节),全角数字(双字节),罗马数字
False: 汉字数字
Error: 无
isdecimal()
True: Unicode数字,,全角数字(双字节)
False: 罗马数字,汉字数字
Error: byte数字(单字节)
isnumeric()
True: Unicode数字,全角数字(双字节),罗马数字,汉字数字
False: 无
Error: byte数字(单字节)
|
具体实例可以看这里
- 字符串的拼接
在python 开发中,很多时候需要使用到字符串拼接,python 字符串拼接有很多,这里就总结一下:
1
2
3
|
格式化类:%、format()、template
拼接类:+、()、join()
插值类:f-string
|
- 使用
+
拼接
- 使用
%
拼接
- 使用
join()
方法拼接
- 使用
format()
方法拼接
- 使用
f-string
拼接
** 使用+
拼接**
这个适合数据量比价小的时候,当总长度小于 20 的时候,可以使用
使用 %
拼接
借鉴了C语言中 printf 函数的功能,如果你有C语言基础,看下文档就知道了。这种方式用符号“%”连接一个字符串和一组变量,字符串中的特殊标记会被自动用右边变量组中的变量替换:
1
|
print '%s %s'%('Python', 'Tab')
|
使用 join()
方法拼接
如果你想要合并的字符串是在一个序列或者 iterable 中,那么最快的方式就是使用 join() 方法。比如:
1
2
3
4
5
6
7
|
>>> parts = ['Is', 'Chicago', 'Not', 'Chicago?']
>>> ' '.join(parts)
'Is Chicago Not Chicago?'
>>> ','.join(parts)
'Is,Chicago,Not,Chicago?'
>>> ''.join(parts)
'IsChicagoNotChicago?'
|
使用 format()
方法拼接
1
2
|
str = 'There are {}, {}, {} on the table'
str.format(fruit1,fruit2,fruit3)
|
还可以指定参数对应位置:
1
2
|
str = 'There are {2}, {1}, {0} on the table'
str.format(fruit1,fruit2,fruit3) #fruit1出现在0的位置
|
最重要的需要引起注意的是,当我们使用加号(+)操作符去连接大量的字符串的时候是非常低效率的, 因为加号连接会引起内存复制以及垃圾回收操作。 特别的,你永远都不应像下面这样写字符串连接代码:
1
2
3
|
s = ''
for p in parts:
s += p
|
同样还得注意不必要的字符串连接操作。有时候程序员在没有必要做连接操作的时候仍然多此一举。比如在打印的时候:
1
2
3
|
print(a + ':' + b + ':' + c) # Ugly
print(':'.join([a, b, c])) # Still ugly
print(a, b, c, sep=':') # Better
|
当混合使用I/O操作和字符串连接操作的时候,有时候需要仔细研究你的程序。 比如,考虑下面的两端代码片段:
1
2
3
4
5
6
|
# Version 1 (string concatenation)
f.write(chunk1 + chunk2)
# Version 2 (separate I/O operations)
f.write(chunk1)
f.write(chunk2)
|
如果两个字符串很小,那么第一个版本性能会更好些,因为I/O系统调用天生就慢。 另外一方面,如果两个字符串很大,那么第二个版本可能会更加高效, 因为它避免了创建一个很大的临时结果并且要复制大量的内存块数据。 还是那句话,有时候是需要根据你的应用程序特点来决定应该使用哪种方案。
这种方式也
1
|
print('python', 'tab' ,'i', sep =',')
|
使用 f-string
拼接
从Python3.6版本引入。这种方式在可读性上秒杀format()方式,处理长字符串的拼接时,速度与join()方法相当。
1
2
3
4
5
|
name = 'world'
myname = 'python_cat'
words = f'Hello {name}. My name is {myname}.'
print(words)
>>> Hello world. My name is python_cat.
|
总结:
当要处理字符串列表等序列结构时,采用join()方式;拼接长度不超过20时,选用+号操作符方式;长度超过20的情况,高版本选用f-string,低版本时看情况使用format()或join()方式。
python中strip(),lstrip(),rstrip()函数
想要去掉什么字符,那么就传入什么字符,默认是空格。如果没有输入,那么就是删除首尾空格的意思: strip() 删除前导和后缀字符
但是当有了参数(传入的是一个字符数组)那么就会删除所有字符数组中的所有数组。比如说:
1
2
3
4
5
6
7
8
9
10
|
theString = 'saaaay yes no yaaaass'
print theString.strip('say')
print theString.strip('say ') #say后面有空格
print theString.lstrip('say')
print theString.rstrip('say')
# 输出结果是
yes no
es no
yes no yaaaass
saaaay yes no
|
Python 中的 is
和 ==
is
is the identity comparison. #比较引用是否相同
==
is the equality comparison. #比较内容是否相同
1
|
The operator a is b returns True if a and b are bound to the same object, otherwise False. When you create two empty lists you get two different objects, so is returns False (and therefore is notreturns True)
|
- magic method
定义:函数声明时候的函数名是以双下划线开始和结尾的,比如说__init__
这样的函数声明,被认为是 magic函数。常见的魔法函数有以下几种:
(1)创建 __new__
函数
创建类并且返回类的实例。
(2)初始化__init__
函数
初始化该实例
(3)__str__
函数
(4)__len__
函数
运算符相关的魔法方法很多,比如说
(5)__cmp__()
函数
(6)__eq__()
函数
(7)__add__(self, other)
函数
python中魔术方法(magic method)是一种重载(overloading)函数。
(6)python交换值为何不使用中间变量
在C++和C 中交换两个变量需要使用到临时变量tmp
,但是在python 中是不必的。交换两个变量一般使用如下的语句:
一般来说python语句是从左到右解析的,但是在赋值操作的时候,因为右值具有更高的计算优先级,所以是从右到左解析的。执行顺序如下:
- 计算等号右边
y, x
(可能是比较复杂的表达式),然后创建元组,分别存储 y, x
的值
- 计算左边的标识符,元组中的element 分别赋值(如果等号左右两边标识符数量不等的时候会出现
ValueError
, 当左边只有一个变量时候,右边计算值就pack成一个元组传递给了左边的变量)
python2 和python3 的差异
使用了from __future__ import xxx
可以在python2,python3环境下运行同一份代码而不出错
1
2
3
4
|
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
|
以 为例子
1
2
3
4
5
6
|
#coding:utf-8
from datetime import datetime
now = datetime.now()
print now.strftime('%m月%d日 %H:%M')
# 03月12日 21:53
|
1
2
3
4
5
6
|
from __future__ import unicode_literals
from datetime import datetime
now = datetime.now()
print now.strftime('%m月%d日 %H:%M')
# 报错 UnicodeEncodeError: 'ascii' codec can't encode character u'\u6708' in position 2: ordinal not in range(128)
|
原因: 因为datetime.strftime()只接受str类型的字符串,不接受unicode类型的字符串。
解决方案:
推荐做法: 传入 str类型的参数
1
2
3
4
5
6
|
#coding:utf-8
from __future__ import unicode_literals
from datetime import datetime
now = datetime.now()
print now.strftime('%m月%d日 %H:%M'.encode('utf-8')) # 指明str类型字符串
|
不推荐做法: 设置运行的时候的编码为 utf-8
1
2
3
4
5
6
7
8
9
10
|
#coding:utf-8
from __future__ import unicode_literals
import sys
from datetime import datetime
reload(sys)
sys.setdefaultencoding('utf-8')
now = datetime.now()
print now.strftime('%m月%d日 %H:%M')
|
python中*
的使用
python 中 *
有乘法和赋值 ([1] *5
) 的用法,除此之外还有解压(unpack)的功能。而zip() 是压缩的功能,如下代码所示:
1
2
3
4
5
|
stuff = ['apple','banana','peach']
money = [10, 5, 7]
pair = list(zip(stuff,money))
# pair = [('apple',10),('banana',5),('peach',7)]
|
同样的,当我们想要还原成原来的两个list, stuff 和money 时候,我们需要用到 *
符号。
1
|
stuff, money =zip(*pair)
|
当然,并不是说 *
只能使用在 list 中,凡是可迭代对象都是可以使用 *
符号。
1
2
3
4
5
6
7
|
def do_something(x,y,z):
print('x is ', x)
print('y is ', y)
print('z is ', z)
list1 = ['a','b','c']
do_something(*list1)
|
可见, *
操作符自动将list1 中的三个元素赋给了三个形参,所以是一种非常方便的用法。
**
的用法
对于字典(dict) 来说,也是可以使用*
运算符,但是一个 *
得到的是key 值,如果想要得到 value 值,那么是需要使用 **
运算符。
1
2
|
dict2 = {'z':1, 'x':2, 'y':3}
do_something(**dict2)
|
所以上面那种传参的方式就是在程序中经常见到的。
*args
和 **kwargs
是我们经常见到的两个参数。用法很简单,当不确定有什么待传入的参数时候,就使用*args
将形参传入到 args
元组里面。同理 **kwargs
效果则是将输入的未定义的形参及其对应的值存在kwargs字典。
1
2
3
4
5
6
|
def intro(**data):
print("\nData type of argument:",type(data))
for key, value in data.items():
print("{} is {}".format(key,value))
intro(Firstname="Sita", Lastname="Sharma", Age=22, Phone=1234567890)
|
也可以进行字典的合并 **
。
1
2
3
|
date_info = {'year': "2020", 'month': "01", 'day': "01"}
track_info = {'artist': "Beethoven", 'title': 'Symphony No 5'}
all_info = {**date_info, **track_info}
|
随机数
We do not need true randomness in machine learning. Instead we can use pseudorandomness. Pseudorandomness is a sample of numbers that look close to random, but were generated using a deterministic process.
很难得到到真实的随机数,然而是可以生成伪随机数。
python 中的random() 库函数是基于马特赛特旋转演算法 (Mersenne Twister)算法生成的。
The pseudorandom number generator is a mathematical function that generates a sequence of nearly random numbers. It takes a parameter to start off the sequence, called the seed. The function is deterministic, meaning given the same seed, it will produce the same sequence of numbers every time. The choice of seed does not matter.
给定特定的种子(seed),可以产生 deterministic 的结果,所以可以重复多次,所以可以复现相同的实验结果。
Random with Python
(1) Random Floating Point Values
1
2
3
4
5
6
7
|
from random import seed
from random import random
seed(1)
for _ in range(10): # generate random numbers between 0-1
val =random()
print(val)
|
产生的是[0, 1]区间的浮点数,可以 rescale to 任意的范围。
1
|
scaled_value =min +(val *(max -min))
|
(2) Random Integer Values
使用 randint()
得到整数
1
2
3
4
5
6
7
|
frmo random import seed
from random import randint
seed(1)
for _ in range(10):
val =randint(0, 10)
print(val)
|
(3)Random Gaussian Values
使用的是 gauss
分布。
1
2
3
4
5
6
7
8
|
from random import seed
from random import gauss
seed(1)
for _ in range(10):
val =gauss(0, 1)
print(val)
|
(4) Random Choosing From a List
使用到了 choice()
函数,choice 每次只是选择了其中的一个。
1
2
3
4
5
6
7
8
9
10
11
|
from random import seed
from random import choice
seed(1)
sequence =[i for i in range(20)]
print(sequence)
for _ in range(5):
selection =choice(sequence)
print(selection)
|
(5)Random Subsample From a List
1
2
3
4
5
6
7
8
9
|
from random import seed
from random import sample
seed(1)
sequence =[i for i in range(20)]
print(sequence)
# default without replacement,不放回抽样
subset =sample(sequence, 5)
|
1
2
3
4
|
sample with replacement vs sample without replacement
两者的区别: 前者是有放回的,所以两次sample 是独立的;后者是没有放回的,两次sample是不独立的。
|
python 中的 random.sample()
默认是没有放回抽样的。如果想要实现,一种方式是基于 randint()
改造,一种是使用numpy 中的函数:numpy.random.choice(replace =True)
。但是python自带的包中可以设置 weight
权重,也就是有权重的sample。
(5) Randomly Shuffle a List
shuffle 操作在python 中是 in-place()
的
1
2
3
4
5
6
7
8
|
from random import seed
from random import shuffle
seed(1)
sequence =[i for i in range(10)]
print(sequence)
shuffle(sequence)
print(sequence)
|
(6) random sampling with replacemnet: random.choices()
random.choices()
returns multiple random elements from the list with replacemnt.
choices 默认是有放回的; sample默认是无放回的。
1
2
3
|
import random
ll =[0, 1, 2, 4]
print(random.choices(ll, k =3))
|
Random Numbers with Numpy
The NumPy pseudorandom number generator is different from the Python standard library pseudorandom number generator. Importantly, seeding the Python pseudorandom number generator does not impact the NumPy pseudorandom number generator. It must be seeded and used separately.
Numpy 中有自己实现的Random 机制,该机制和Numpy 中的机制不一样,当然Numpy 中也有马特赛特旋转演算法 (Mersenne Twister)算法。重要的是,两者是需要单独设置的。
(1) Seed The Random Number Generator
1
2
3
4
5
6
7
|
# seed the pseudorandom number generator
from numpy.random import seed
from numpy.random import rand
# seed random number generator
seed(1)
# generate some random numbers
print(rand(3))
|
(2)Array of Random Floating Point Values
1
2
3
4
5
|
from numpy.random import seed
from numpy.random import rand
seed(1)
vals =rand(10)
print(vals)
|
(3)Array of Random Integer Values
1
2
3
4
5
6
7
|
from numpy.random import seed
from numpy.random import randint
seed(1)
# start, end, numbers
values =randint(0, 10, 20)
print(values)
|
(4)Array of Random Gaussian Values
1
2
3
4
5
|
from numpy.randon import seed
from numpy.random import randn
seed(1)
values =randn(10)
print(values)
|
(5)Shuffle Numpy Array
这个也是 in-place 的操作
1
2
3
4
5
6
7
8
|
from numpy.random import seed
from numpy.random import shuffle
seed(1)
sequence =[i for i in range(20)]
print(sequence)
shuffle(sequence)
print(sequence)
|
总结:
随机数的生成需要设置 seed
,如果生成number,那么使用 python standard library
; 如果是生成array, 那么使用 NumPy library
。
参考文献
How to Generate Random Numbers in Python
python 中的import 函数
(1)搜索路径
首先是当前的路径,然后是一些内置函数的路径,重要的是如果加上 sys.path.append(path)
,可以添加自定义的路径, path可以是相对路径或者是绝对路径。其中 .
表示当前目录(同一级别的)。
1
2
3
4
|
import sys
print(sys.path)
sys.path.append("..")
print(sys.path)
|
输出结果:
1
2
|
['/home/jeng/projects/named_entity_recognition', '/home/jeng/anaconda3/lib/python37.zip', '/home/jeng/anaconda3/lib/python3.7', '/home/jeng/anaconda3/lib/python3.7/lib-dynload', '/home/jeng/anaconda3/lib/python3.7/site-packages']
['/home/jeng/projects/named_entity_recognition', '/home/jeng/anaconda3/lib/python37.zip', '/home/jeng/anaconda3/lib/python3.7', '/home/jeng/anaconda3/lib/python3.7/lib-dynload', '/home/jeng/anaconda3/lib/python3.7/site-packages', '..']
|
(2)import语句
1
2
3
|
import os, sys, time # 虽然可以一次导入多个,但是不建议这样做,不是python 风格
import sys as system # 建议一条语句导入一个
import solongname as shortname # 这个也是可以的
|
(2)from ... import *
from-import 是导入指定模块中指定方法的方式。将一个模块中所有内容全部导入到当前的命名空间,只需要使用如下的声明:
一般不建议这样写,太消耗内存,不要过多这样使用。唯一推荐全部导入的只有 Tkinter
(是python 中的一个gui 框架)。可以选择一个折中的方案, 从 os
中导入5 个函数。
1
|
from os import path, walk, unlink, uname, remove, rename
|
(3)reload() 函数
当一个模块被导入到一个脚本,模块顶层部分的代码只会被执行一次。因此,如果你想重新执行模块里顶层部分的代码,可以用 reload() 函数。该函数会重新导入之前导入过的模块。语法如下:
(4)导入顺序
1). python 标准库模块
2). python 第三方模块
3). 自定义模块
(5)可选导入
可以使用该方式去处理版本问题
1
2
3
4
5
6
7
8
9
|
try:
# For Python 3
from http.client import responses
except ImportError: # For Python 2.5-2.7
try:
from httplib import responses # NOQA
except ImportError: # For Python 2.4
from BaseHTTPServer import BaseHTTPRequestHandler as _BHRH
responses = dict([(k, v[0]) for k, v in _BHRH.responses.items()])
|
(6)局部导入
当再次需要使用 math
模块的时候,还是需要再次导入,所以平衡好是全局导入还是局部导入
1
2
3
4
5
|
import sys # 全局导入
def square_root(a):
import math # 局部
return math.sqrt(a)
|
(7)python 中的 -m
参数
如果在运行的时候,加上了 -m
参数,那么将导入的包先运行,然后再运行本脚本
__main__.py
文件与python -m
Python的-m参数用于将一个模块或者包作为一个脚本运行,而__main__.py文件相当于是一个包的“入口程序“。
1
|
-m module-name:Searches sys.path for the named module and runs the corresponding .py file as a script.
|
比如下面的例子
1
2
3
|
package
├── __init__.py
└── __main__.py
|
其中 __init__.py
文件内容:
其中 __main__.py
文件内容:
当使用 python -m
执行,先是执行了init 函数,然后是main 函数。输出是
当使用 python
执行的时候,直接执行 main, 输出是
所以不管加不加 -m
,最后的 main函数都是会被执行。加上 -m
会将模块或者包导入之后才执行
(8)__name__ =="__main__"
的作用
很多编程语言都有一个入口,比如C++、C 和Java中都需要一个 main
函数作为程序的入口。但是和上述的编译语言不同,Python属于脚本语言,不需要编译成二进制执行,而是动态逐行解释运行,可以没有统一的入口。所以可以没有 main
函数入口。
但是除了作为脚本语言直接被运行外,还是可以作为模块(库)被其他 .py
文件导入。所有的模块中都有一个内置的属性 __name__
,表示当前模块的名字。如果被当做脚本运行,__name__
值为__main__
。而被别的模块引用的时候, __name__
值为模块的名字。
(9) python 中的 module 模块
Python 中引入 module 的写法
python 中建立一个 folder,那么就加上一个 __init__.py
文件,即使文件内是没有内容的,也需要保持格式上的一致。
If you want to import anything from top level directory. Then,
1
|
from ...module_name import *
|
Also, if you want to import any module from the parent directory. Then,
1
|
from ..module_name import *
|
Also, if you want to import any module from the parent directory. Then,
1
|
from ...module_name.another_module import *
|
This way you can import any particular method if you want to.
我的理解,如果是 2 个 dots,那么就父节点,3 个dots,那么就是父节点的父节点
总结:
__name__
可以用于调试代码:当脚本执行,在 if __name__ == '__main__
中的代码会被执行;而被别的模块所引用的时候,因为这个时候的 __name__
不是 main ,所以该函数不会被执行。
在Python中,使用单引号(')和双引号(")定义的字符串没有区别。
__call__
函数讲解
__init__
的作用是初始化某个类的一个实例
__call__
的作用是使实例能够像函数一样被调用,可以用来改变实例的内部成员的值。
1
2
3
4
5
6
7
8
|
class Person(object):
def __init__(self, name, gender):
self.name = name
self.gender = gender
def __call__(self, friend):
print 'My name is %s...' % self.name
print 'My friend is %s...' % friend
|
比如以下的例子:
1
2
|
p = Person('Bob', 'male')
p('Tim')
|
python中 pickle 模块
pickle模块是python中用来持久化对象的一个模块。所谓对对象进行持久化,即将对象的数据类型、存储结构、存储内容等所有信息作为文件保存下来以便下次使用。在神经网络中训练的模型也是可以经过序列化处理的,需要注意的是以二进制保存和读取的内容,所以在读写的时候需要加上 b
超参数。
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
|
# 向文件中写入 pickle 对象
#导入pickle模块
import pickle
#创建一个名为data1的对象
data1 = {'a': '123', 'b': [1, 2, 3, 4]}
#打开(或创建)一个名为data1.pkl的文件,打开方式为二进制写入(参数‘wb’)
file_to_save = open("data1.pkl", "wb")
#通过pickle模块中的dump函数将data1保存到data1.pkl文件中。
#第一个参数是要保存的对象名
#第二个参数是写入到的类文件对象file。file必须有write()接口, file可以是一个以'w'方式打开的文件或者一个StringIO对象或者其他任何实现write()接口的对象。如果protocol>=1,文件对象需要是二进制模式打开的。
#第三个参数为序列化使用的协议版本,0:ASCII协议,所序列化的对象使用可打印的ASCII码表示;1:老式的二进制协议;2:2.3版本引入的新二进制协议,较以前的更高效;-1:使用当前版本支持的最高协议。其中协议0和1兼容老版本的python。protocol默认值为0。
pickle.dump(data1, file_to_save, -1)
#关闭文件对象
file_to_save.close()
# 从文件中读取 pickle 对象
#导入pickle模块
import pickle
#打开一个名为data1.pkl的文件,打开方式为二进制读取(参数‘rb’)
file_to_read = open('data1.pkl', 'rb')
#通过pickle的load函数读取data1.pkl中的对象,并赋值给data2
data2 = pickle.load(file_to_read)
#打印data2
print data2
#关闭文件对象
file_to_read.close()
|
easydict
python 中的easydict 的使用,比系统自带dict 更加方便的字典 EasyDict。
easydict的作用:可以使得以属性的方式去访问字典的值!所以主要是写得方便。
···
pip install easyinstall
····
使用代码:
···python
from easydict import EasyDict as edict
easy = edict(d = {‘foo’:3, ‘bar’:{‘x’:1, ‘y’:2}}) # 将普通的字典传入到edict()
print(easy[‘foo’]) # 这是传统的方法
print(easy.foo) # 这是我们使用easydict输出二者结果是一样的,但是可以更为方便的使用字典了
print(easy.bar.x) # 我们也是可以很方便的使用字典中字典的元素了
····
解析json目录时很有用
python中的文件遍历
(1)os.listdir
适用情况:在一个目录下面只有文件,没有文件夹(有文件夹的时候会遍历到文件夹,但是不会继续递归往下遍历)
1
2
3
4
5
6
7
|
def file_name(file_dir):
for files in os.listdir(file_dir): # 不仅仅是文件,当前目录下的文件夹也会被认为遍历到
print("files:", files)
#files: A # 指定路径文件夹的子文件
#files: B # 指定路径文件夹的子文件
#files: text.txt # 指定路径文件夹的非文件夹内容
|
(2)os.walk
适用情况:递归的情况,一个目录下面既有目录(目录下面还可能有目录和文件)也有文件,如何读取里面所有文件,使用os.walk;
1
2
3
4
5
6
|
import os
def file_name(file_site):
for root, dirs, files in os.walk(file_dir):
print("root", root) # 当前目录路径
print("dirs", dirs) # 当前路径下所有子文件夹
print("files", files) # 当前路径下所有非子文件夹的文件
|
这个是递归查找文件很好的函数。
glob 是python 中支持正则查询的方式,需要提取一定的规则之后使用才比较方便,比如说目录只有两层。
switch 在python 中的实现
c、c++ 中都有 switch (case )语句的实现,但是python 中就没有相关的实现,只能通过其他的方式去完成该功能。基本的思路是通过 dictionary
实现方式一
1
2
3
4
5
|
def f(x):
return {
'a': 1,
'b': 2,
}[x]
|
实现方式二
1
2
3
4
5
6
7
8
9
10
|
if x == 'a':
# Do the thing
elif x == 'b':
# Do the other thing
if x in 'bc':
# Fall-through by not using elif, but now the default case includes case 'a'!
elif x in 'xyz':
# Do yet another thing
else:
# Do the default
|
Why Doesn’t Python Have Switch/Case? 比较详细介绍了在python 中为什么没有 switch -case 语句。
使用的是一种 dictionary 去实现了 switch 的功能
1
2
3
4
5
6
7
|
def numbers_to_strings(argument):
switcher = {
0: "zero",
1: "one",
2: "two",
}
return switcher.get(argument, "nothing")
|
比较复杂的版本(借助了 function), function 中可以实现更加复杂的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def zero():
return "zero"
def one():
return "one"
def numbers_to_functions_to_strings(argument):
switcher = {
0: zero,
1: one,
2: lambda: "two",
}
# Get the function from switcher dictionary
func = switcher.get(argument, lambda: "nothing")
# Execute the function
return func()
|
使用类的形式 (更好的封装性能)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Switcher(object):
def numbers_to_methods_to_strings(self, argument):
"""Dispatch method"""
# prefix the method_name with 'number_' because method names
# cannot begin with an integer.
method_name = 'number_' + str(argument)
# Get the method from 'self'. Default to a lambda.
method = getattr(self, method_name, lambda: "nothing")
# Call the method as we return it
return method()
def number_0(self):
return "zero"
def number_1(self):
return "one"
def number_2(self):
return "two"
|
python 中的with statement
遇到with是在文件那一章,with的作用是就是会自动关掉文件管道。
1
2
|
with open('path','读写模式‘) as f:
do something
|
上面的功能等价于
1
2
3
|
f = open('path','读写模式')
do something
f.close()
|
with statement 适合在消耗比较多的资源的情况下使用,是一种更好的管理资源的方式。
下面这种方式,需要手写 open 和close 语句。
Perhaps the most common (and important) use of context managers is to properly manage resources. In fact, that’s the reason we use a context manager when reading from a file. The act of opening a file consumes a resource (called a file descriptor), and this resource is limited by your OS. That is to say, there are a maximum number of files a process can have open at one time. To prove it, try running this code:
1
2
3
4
5
|
files = []
for x in range(10000):
f = open('foo.txt', 'w')
f.close()
files.append(f)
|
In other languages, developers are forced to use try…except…finally every time they work with a file (or any other type of resource that needs to be closed, like sockets or database connections). Luckily, Python loves us and gives us a simple way to make sure all resources we use are properly cleaned up, regardless of if the code returns or an exception is thrown: context managers.
是可以使用 try except 和finally 进行处理的,但是 python 中有更好的方式实现
1
2
3
4
|
with something_that_returns_a_context_manager() as my_resource:
do_something(my_resource)
...
print('done using my_resource')
|
That’s it! Using with, we can call anything that returns a context manager (like the built-in open() function). We assign it to a variable using … as <variable_name>. Crucially, the variable only exists within the indented block below the with statement. Think of with as creating a mini-function: we can use the variable freely in the indented portion, but once that block ends, the variable goes out of scope. When the variable goes out of scope, it automatically calls a special method that contains the code to clean up the resource.
这上面说 在with 之外的变量是无法访问的,但实际上就我的经验而言,貌似也是能够访问的。
这里说的with 之外的变量是无法访问,是指的文件 as 之后的变量,但是对于 with
缩进之内的变量是可以访问的。
with 是如何工作的?
- 紧跟with后面的语句被求值后,返回对象的’enter()’方法被调用,这个方法的返回值将被赋值给as后面的变量.
- 当with后面的代码块全部执行完之后,将被调用前面返回对象的__exit__()方法.
总之,with-as表达式极大的简化了每次写finally的工作,这对保持代码的优雅性是有极大帮助的。如果有多个项,那么可以这样写
1
2
|
with open("x.txt") as f1, open('xxx.txt') as f2:
do something with f1,f2
|
python 和numpy 中关于类型函数
1
2
3
|
type() 返回参数的数据类型
dtype 返回数组中元素的数据类型
astype() 对数据类型进行转换
|
ndim返回的是数组的维度,返回的只有一个数,该数即表示数组的维度。
1
2
|
print(arr1.ndim, arr2.ndim, arr3.ndim)
# 返回的是一个数字,表示数组的维度
|
shape:表示各位维度大小的元组。返回的是一个元组。
1
2
3
|
print(arr1.shape, arr2.shape, arr3.shape)
# 返回的是一个元祖
# (5,) (2, 3) (2, 2, 3)
|
1
2
3
|
print(arr1.dtype, arr2.dtype, arr3.dtype)
# 返回的是数组的数据类型
# int64 int64 int64
|
- astype
1
2
3
4
5
6
|
arr1.astype('int32')
# 转换数组的数据类型
# array([1, 2, 3, 4, 5], dtype=int32)
# int32 --> float64 完全ojbk
# float64 --> int32 会将小数部分截断
# string_ --> float64 如果字符串数组表示的全是数字,也可以用astype转化为数值类型
|
关于取整数 取小数的知识
1
2
3
4
5
6
7
8
9
10
11
12
|
# 数据转换 astype() 的知识
a =3.75
int(a) # 向下取整
round(a) # 四舍五入
import math
math.ceil(a) # 向上取整
# 取整数和小数部分
import math
math.modf(3.25)
#(0.25, 3.0)
|
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
|
2 **3 # 8乘方
# 计算的先后顺序(和数学中定义的方法是一样的)
()
**
*/
+-
round() # 四舍五入,将浮点数转换成 int 类型
min(), max()
abs()
#e 相当于计算 10 的多少次幂,科学计数法
1.3e5 # 130000
tang =2
1 < tang <3 # 在python中,可以连续判断
tang ="hello"
tang *3 # 可以相乘操作
# 能切能合
tang ="1 2 3"
tang =tang.split()
tang_str =""
tang_str.join(tang) # 将分散的合到一起了
tang_str.upper() # 全部大写
tang_str.lower() # 全部小写
tang =" hello python "
tang.strip() # 将前后的空格去掉
tang.lstrip() #去掉左边的空格去掉
tang.rstrip() # 去掉右边的空格
'{} {} {}'.format('tang', 'yu', 'di')
# 索引: 前面从0 开始,可以从
tang[::2] # 每间隔2个取值
lst =[123, 456]
lst[:] =['tang', 'yudi'] # 是全部重新赋值
del lst[0] # 这个是inplace 操作,直接删除了
del lst[0:]
tang =['apple', 'apple', 'banana']
tang.count('apple') # 计数功能
tang.index('apple') # 找到词的index 操作
tang.index(2, 'python') # 在index =2 插入位置
tang.remove('python') # 默认去掉匹配的第一个元素
tang.pop(1) # 弹出index =1 元素
tang.reverse() # 翻转
# 字典结构
# 字典中没有顺序,是依靠 key 找结果;不是顺序
tang ={} # key-value 结构, key 值是字符串,value值可以是任意的结构
tang['first'] =123
tang['python'] =456
tang['python'] =444 # dict 和list 都是可以嵌套
tang.pop('tang')
# dict 的更新是比较常见的
tang ={'tang' : 123, 'yudi' :456}
tang2 ={'tang' : 789, 'python': 888}
tang.update(tang2) # 用新的数据tang2 去更新旧的数据 tang
tang.keys() # 打印所有的键值
tang.values() #
tang.items()
# 集合 set
tang =set([123, 123, 456, 789])
tang =set()
tang ={} # 这个和dictionary 是一样的初始化
a ={1, 2, 3,4}
b ={5, 6}
a.union(b) # a|b 符号操作, 并集
a.intersection(b) # a & b, 交集
a.difference(b) # a-b,减法
b.issubset(a) # b <=a 符号操作, 判断是否是子集
# 基本操作
a ={1, 2, 3}
a.add(4)
a.update([4,5])
a.remove(1)
a.pop() # 只能是弹出最后一个元素
# 赋值机制
tang =123
yudi =tang
id(yudi)
id(tang) # id 是用来查看变量内存的位置
tang is yudi # 判断两个变量是否是同一个东西
tang =1
yudi =1
id(tang)
id(yudi) # 两个是指向同一个内存,python 中对于比较简单的内容,直接采用的是复用
tang =1000
yudi =1000
id(tang)
id(yudi)
# 对于比较大的数字,python 中是分别进行赋值,所以两个id 是不一样的
# 循环:for, while , break, continue
# 函数的定义 args 表示没有限制参数的个数
def add_number(a, *args):
for i in args:
a += i
return a
add_number(1, 2, 3, 4)
# 参数是设置成键值对的格式 (很有用的参数类型)
def add_number(a, **kargs):
for arg, val in kargs.items():
print(arg, val)
add_number(a, x =1, y=2)
# python 是一个脚本语言,包的本质是脚本文件
# python包
# 复用,这个功能还是很强大的
import tang as tg
from tang import tang_v, tang_add
from tang import * # 所有的东西都进行了导入
# 如果想要在 os 中删除一个文件(内存中的)
import os
os.remove("tang.py")
# 异常处理
# 这种写法需要清楚知道每一个异常
for i in range(10):
try:
input_number =input("write a number")
if input_number =='q':
break
result =math.log(float(input_number))
except ValueError:
print("Value Error")
break
# 或者直接将异常写成一个类
for i in range(10):
try:
input_number =input("write a number")
if input_number =='q':
break
result =1.0/ math.log(float(input_number))
except Exception: # 只要出现一种异常,那么都可以捕捉到,而不是某一种具体的 error。
print("Value Error")
break
for i in range(10):
try:
input_number =input("write a number")
if input_number =='q':
break
result =1.0/ math.log(float(input_number))
except ValueError: # 写成具体的error 类型
print("Value Error")
except ZeroDivisionError:
print("log value must != 0")
break
for i in range(10):
try:
input_number =input("write a number")
if input_number =='q':
break
result =1.0/ math.log(float(input_number))
except ValueError: # 写成具体的error 类型
print("Value Error")
except ZeroDivisionError:
print("log value must != 0")
except Exception:
print("other error")
break
# raise 抛出异常; try catch 是捕捉
try:
print(1/0)
except Exception:
print("Exception")
finally:
print("finally") # 有没有异常都会执行该语句
# 这个语句实现的是在jupyter 中创建文件并且写入文件内容
%%writefile tang.txt
hello python
tang yu di
ji tain tian
# 类的学习
class people:
'帮助信息: xxx'
number =100 # 类变量,该类或者对象都可以直接访问
def __init__(self,name, age):
self.name =name # 将name 初始为传入的参数
self.age =age
def display(self):
print("number = :", people.number)
def display_name(self):
print(self.name)
# 使用
# people.__doc__ 可以查看帮助信息
p1 =people("tang", 40)
p2 =people("pytho", '50')
p1.name # 调用一个属性
del p1.name # 在内存中删掉
hasattr(p1, 'name') # 判断类中是否有相应的属性
getattr(p1, 'name') # get
setattr(p1, 'name') # set
delattr(p1, 'name') # 删除属性
# 时间操作
import time
print(time.time()) # 时间戳,1970年1月1日 经过了多少时间
# 一般有用的是格式化的时间:年月日,时分秒
print(time.strftime('%Y-%m-%d %H:%M:%S', time.localtime()))
import calendar
print(calendar.month(2017,11))
help(calendar.month) # 在python 或者 jupyter 中使用 help 帮助文档
|
python操作数据库
python 操作mongbdb数据库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import pymongo
import csv
client = pymongo.MongoClient(host='db.collov.com', port=9788)
db = client.Inventory
db.authenticate('inventory','e135abfa17dee86ef5472d5ad53f1b97e1b470d8c06a92cd8aefc73258440400')
collection = db.object_detection_collov
number = 1
x = collection.find({},{'objects': False, 'labels.embedding': False})
for item in x:
with open('aaaaa.csv', 'a', encoding='utf-8', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',')
writer.writerow([item['img_id'], item.get('s3_path'), item.get('labels')])
print(number)
number += 1
|
python 操作mysql 数据库
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
|
import pymysql
import pandas as pd
conn =pymysql.connect(host='172.31.31.76', user="admin", password="pass", port =3303, db="db")
cursor =conn.cursor()
cursor.execute("select id, name, description, category, link, visual_type_one, visual_type_two, materials,saved_pics,bg_removed_pics from t_flair_goods")
all_rows =cursor.fetchall()
conn.close()
columns =[
'id',
'name',
'description',
'category',
'link',
'visual_type_one',
'visual_type_two',
'materials',
'saved_pics',
'bg_removed_pics'
]
df =pd.DataFrame(list(all_rows), columns =columns)
df.to_csv("test.csv")
print('end')
|
其他
print()
和 sys.stdout.write()
的区别
sys.stdout.write() 只能输出一个字符串str,而 print() 可以输出多个值,数据类型多样。 print(obj) 实际上是调用 sys.stdout.write(obj+'\n') ,因此print在打印时会自动加个换行符。
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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
# 变量的多重赋值
a, b = 50, 60
# 一个值分配给多个变量
a =b =c =50
# 字符串反转
my_string = "MY STRING"
rev_string = my_string[::-1]
my_string = "This is a string in Python"
my_list = my_string.split()
my_string = " ".join(my_list)
# 多次打印字符串
n = int(input("How many times you need to repeat:"))
my_string ="Python\n"
print(my_string *n)
# 多个条件运算符(如果能写到一起,那么尽量写到一起,增加可读性)
a = 15
if (a >10 and a <10):
print("Hi")
# 取而代之,可以将条件运算符组合成单个表达式
a =15
if (10 <a < 20):
print("Hi")
# 在列表中查找最频繁的元素
# list.count() 是 python 内置的函数
my_list = [1,2,3,1,1,4,2,1]
# 下面这两种写法都可以得到结果的
most_frequent =max(set(my_list), key = my_list.count)
most_frequent =max(my_list, key= my_list.count)
# 查找列表中所有元素出现的次数
from collections import Counter
my_list = [1,2,3,1,1,4,2,1]
print(Counter(my_list))
# 检查两个字符串的易位构词
# 如果一个字符串由另一个字符串中的字符组成,那么这两个字符串就是易位构词(Anagram)。
from collections import Counter
my_string_1 = "RACECAR"
my_string_2 = "CARRACE"
if(Counter(my_string_1) == Counter(my_string_2)):
print("Anagram")
else:
print("Not Anagram")
import math
my_number = 18.7
print(math.floor(my_number))
print(math.ceil(my_number))
# 返回布尔值
# 下面这种写法很笨
def function(n):
if n >10:
return True
else:
return False
n =int(input())
if (function(n)):
print("Eligible")
else:
print("Not Eligible")
# 不使用 if else, 这样是比较简洁的
def function(n):
return n >10
n =int(input())
print("Eligible ") if function(n) else print("Not Eligible")
# lambda 匿名函数, 可以实现在一行中创建函数
# 对于小函数,可以使用这种方式
x = lambda a, b, c: a +b +c
print(x(10, 20, 30))
# map 是一个高阶函数,为列表中所有元素应用特定的函数
my_list = ["felix", "antony"]
new_list = map(str.capitalize, my_list)
print(list(new_list))
# map 和 lambda 一块使用
my_list =[1, 2, 3, 4]
new_list = map(lambda x: x *x, my_list)
print(list(new_list))
# 使用 filter 函数过滤值, filter(function, iterable)
def eligibility(age):
return age >= 24
list_of_age =[10, 24, 27,33, 30, 18, 17]
age =filter(eligibility, list_of_age)
print(list(age))
# 合并两个字典, 这个很常用哈
# 下面这种方法并不会进行 对应值相加
dict_1 = {'One':1, 'Two':2}
dict_2 = {'Two':2, 'Three':3}
dictionary = {**dict_1, **dict_2}
print(dictionary)
# 将两个列表合并成一个词典
list_1 = ["One","Two","Three"]
list_2 = [1,2,3]
dictionary = dict(zip(list_1, list_2))
|
python 中的注册器(register)
在 python 项目中,常常有 register 的出现,这个并不是注册账号的模块,而是项目中注册模块的模块。比如,一个深度学习项目中可能支持多种模型,具体使用哪种模型需要根据用户在配置文件中指定。最简单的方法是维护一个模型名称 -> 模型类
的字典,缺点是每次增加一个模型,都需要手动维护这个字典,比较繁琐。
这里介绍的注册器,你仅仅需要注册的模块的代码路径(相对简单些)。
所以注册器完全可以理解为一个字典,里面存储同系列的类。
注册器在使用的时候,可以参考装饰器。注册器类似一个 dict
(实际上有一个 _dict
属性),可以set_item
和get_item
。关键是 register
函数,可以作为装饰器,注册一个函数或者一个类。
1
2
|
@register_obj.register
class Modle1:
|
等效于
1
|
register_obj.register(Model1)
|