python入门

这篇文章算是入门的索引。其实,这里可能会放所有的比较杂的知识点。

一些比较优质的资源。

资源

零散知识点

乱码问题

python2.7乱码问题。下面的代码是写在greenplum中的测试脚本。最终如下:

CREATE OR REPLACE FUNCTION scc_hello(addr text) RETURNS text AS $$
#coding=utf-8
return '#'.join([x.encode('utf-8') for x in addr.decode('utf-8')])
$$LANGUAGE plpythonu;

在遍历中文字符的时候,如果不先进行decode,再decode,则会各种乱码。(具体参见 乱码.txt)

>>> addr='您好世界' 
>>> print(addr)
您好世界
>>> '#'.join([x.encode('utf-8') for x in addr.decode('utf-8')]
KeyboardInterrupt
>>> '#'.join([x.encode('utf-8') for x in addr.decode('utf-8')])
'\xe6\x82\xa8#\xe5\xa5\xbd#\xe4\xb8\x96#\xe7\x95\x8c'
>>> print('#'.join([x.encode('utf-8') for x in addr.decode('utf-8')]))#好#世#界

为什么要先decode,再encode呢?

先记住这样,u.encode,str.decode,而str函数,。。。

对中文的遍历,在python2.7的时候,默认按ascii码来取,所以呢,中文的字,会变成两2,无法正常的遍里,故,先转换为unicode编码(unicode中的一个就代表完整的一个字),然后运算完,再转换为string。即可。同理,[:]切片应该也遵循相同的道理。

上面仅仅是针对2.7的,而且也废弃了。

对于3.6及以上的版本。见到过b'somechar'的,只接使用str()函数来处理。

查看python模块的位置

-- 方式1
pydoc modules

-- 方式2,先进入交互模式,然后再输入命令
pydoc   
help("modules")

assert

有的时候,我们希望出错了,不太想做具体的判断,直接exit,则可以用assert关键字。

def save_csv(filename,obj_list):
    assert obj_list is not None and len(obj_list) > 0

raise

手动抛出异常,如果上层调用处,没有做错误捕捉,则可能导致程序退出。

raise error('save_csv : 数据有误')

pprint

第一次知道,还有这样的函数。2021-10-29 16:57

from pprint import pprint,pformat

# 格式化输出的内容
pprint(dic)
# 输出的内容,形似json,正好也是,python中定义,定义字段的代码。
print(eval(pformat(res.data.rows[0])))

全局变量

如下代码,必须要申明cookies 为全局的cookies,python判断一个变量是否是新的变量,貌似的机制是:

如果一个变量,上来就用,没有定义过,那么认为,这个变量是全局的。

而相反,如果发现上来就对一个变量赋值,则认为,这是在申明一个新的变量,导致,函数作用域的这个新变量覆盖全局的同名变量。

这有点神奇,js呢,少var则认为是全局。python呢,看你变量是不是上来就用,还是上来就赋值来区分。php呢,则全认为是局部变量。好吧,原来如此。

def get_cached_cookie():
    global cookies
    if os.path.isfile(COOKIES_FILE):
        with open(COOKIES_FILE,'r') as fi:
            cookies = json.load(fi)

输入处理

python2的时候,使用raw_input,以下为python3代码:

num = input("输入你的工号:")
passwd = input("输入你的密码:")

字符串作为函数来调用

在php中,可以直接使用字符串来调用函数,但是python中如何来用呢?参见文章

函数调用

# 1、eavl方式
eavl('func')()

# 2、locals()和globals()  是python的两个内置函数,以字典类型返回当前位置的全部局部和全部全局变量.
locals()['func']()

对象方法调用

# 1、getattr()
# getattr() 是 python 的内建函数,getattr(object,name) 就相当于 object.name,但是这里 name 可以为变量。返回 foo 模块的 bar 方法

f = getattr(foo_instance, 'do_' + opname)
f()

# 2、methodcaller
f = Foo()
from operator import methodcaller
methodcaller('do_foo')(f)
# 标准库operator下的methodcaller函数

生成器,省略括号

发现,貌似有括号的地方,写生成器,可以直接省略。如下。

from random import choice
data = ''.join(choice('ABCD') for i in range(10)) # join 的括号 被当作了生成器的括号
print(data)


def mytest(*text):
    print(text)
mytest(choice('ABCD') for i in range(10))


#print('hello world') for i in range(10)  # 没有括号,就不能省略了
(print('hello world') for i in range(10))

字典生成器

不必说,常用的数组生成器,对象也有生成器。但是,注意一下两种格式的区别。

# 方式1: key value都是从迭代中直接获取
demo = {'age':1,"sex":2}
d2 = {k: v for (k, v) in demo.items()}


rows = [
    {'id':1,'name':"zhangsan1"},
    {'id':2,'name':"zhangsan2"},
    {'id':3,'name':"zhangsan3"},
    {'id':4,'name':"zhangsan4"},
]
# 方式2: 从迭代中,只拿一个变量,其他都是运算所得。
{item['id']:item['name'] for item in rows }
# 甚至,直接遍历一个数组
{"key%d"%i:i  for i in range(10)}

只从迭代中只拿一个变量,这种方式更加常用。推荐。

数组的加乘法运算

tmp = [i for i in range(10)]
tmp += ['']*4     # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, '', '', '', '']
# 但是没有减 除运算


# 以下两种,都是达到相同的目的。
[i for i in range(10)] + [33]
[i for i in range(10)].append(33)  # 但是没有返回值。

如果求list的并集等,如何计算呢?set有此概念,故先转换为set。

对比较运算符号也做了重载。

[10] > [2,1]

集合运算

list的集合运算需要借助于set来完成。示例如下:

a = [2, 3, 4, 5]
b = [2, 5, 8]

# 交集
print([val for val in a if val in b])
print (list(set(a).intersection(set(b))))

# 并集
print(a + [var for var in b if var not in a ])
print (list(set(a).union(set(b))))
# 差集
print([var for var in b if var not in a ])
print (list(set(b).difference(set(a)))) # b中有而a中没有的

序列解包

常用,其他语言,js/php都有对应的概念。

另:参见map/filter本质

# other前面的 *  用来匹配剩余所有的参数,可以有0+个元素,封装为一个数组
first_number,*other = data['job_number'].split(',')


# playload = {}  字典  ,因为format接受的参数是   format(key1=value1,)
'{name}...'.format(**payload)


# 数组也是一样,一个 * 号。
params = [a,b,c]
test(a,b,c)
test(*params)

另一种用法,交换元素的值,或者变量批量初始化。

a = 1 
b = 2 
a,b = b,a
print(a)
print(b)

引入模块

https://zhuanlan.zhihu.com/p/64893308

  • 导入同级目录下的文件。
import demo  # 同级目录的文件,不用加py扩展名,类似于 nodejs
  • 其他位置的Python文件,如果想直接引入,则先执行下面,再引入
sys.path.append("../path/to")  #
  • 引入子目录的文件,先增加空的__init__.py文件,整体作为一个模块,然后再引入。
# 假入 module跟当前Python文件在同一路径,  欲引入  module/demo.py
# 然后增加 __init__.py  把它当作一个模块来处理。

from module import demo
  • 其他,不过是以下的组合拳,先把模块或python文件,加到系统搜索路径内,然后再引入。
sys.path.append("../path/to")  #

import demo 
from module import demo 

数组、元组比较

这个有点神奇,其他语言从来没有这种比较。以下代码摘自requests/__init__.py

# 元组比较
assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0)

# 数组也能比较
cryptography_version = list(map(int, cryptography_version.split('.')))
cryptography_version < [1, 3, 4]:

运算符重载

python是允许对运算符重载。如数组、元组可以使用逻辑比较符号,数组可以加、乘运算等。pandas里面的中括号语法,貌似也是运算符号重载。

运算符号,可以简单的理解是,函数、方法的别名,但看起来更间接、直观,本质上,还是函数、方法的调用。

参考链接:https://zhuanlan.zhihu.com/p/162931696

python运算符号重载

zip

zip生成一个只能迭代一次的迭代器,一旦你迭代了它,它就耗尽了。(py3是,py2好像可以反复使用)

主要作用,相当于将数据库的多列(多个数组),合并成一个表的感觉(一个数组(每个数组有多列))。这样,可以遍历每一行。

另:参见map/filter本质

numbers = [1,2,3]
letters = ['a','b','c']

myzip = zip(numbers,letters)

print(myzip)
print(type(myzip))


# 转换成list 并保存返回值,就能多次循环使用了
# print(list(myzip))

# for i in list(myzip):
#     print(i)

# for k,v in list(myzip):
#     print('%s\t%s'%(k,v))

# for k,v in myzip:
#     print('%s\t%s'%(k,v))

# print(list(zip(*myzip)))
# 兜兜转转,又回到原来的样子
a,b = zip(*myzip)
print(a)
print(b)

print('done')

map/filter本质

def _map(fn, *iterables):
    return [fn(*i) for i in zip(*iterables)]   # 序列解包
def _filter(fn, iterable): 
    return [i for i in iterable if fn(i)]



print(_map(lambda x,y: x +y ,[1,3,5],[2,4,6])) # [3, 7, 11]
print(list(map(lambda x,y: x +y ,[1,3,5],[2,4,6]))) # [3, 7, 11]

print(_filter(lambda x:x%2==0 ,range(10)))   # [0, 2, 4, 6, 8]
print(list(filter(lambda x:x%2==0 ,range(10)))) # [0, 2, 4, 6, 8]

环境

虚拟环境

python3.3以上好像自带venv命令。

docker虚拟环境

docker有很好的隔离特性,也可以作为一种虚拟环境来使用。比如:

FROM 10.131.9.12:5000/python

WORKDIR /opt/py
ADD requirements.txt  .
RUN pip3 install -r requirements.txt
# 增加自己的代码或目录,不增加的话,可以直接使用映射
ADD *.py ./

将python脚本跑在定时任务中

# echo "0 0 * * * $PWD/run.sh >> $PWD/run.log 2>&1"
docker run --rm  -t ldap2mysql:0.1  python3 ldap_save.py
# 注意不要加 -i 选项。

# 直接做脚本运行时,存到 /usr/local/bin/mypython   然后执行mypython来运行
docker run --rm  -it -v $PWD:/opt/py -w /opt/py  ldap2mysql:0.1 python3 $@

定时任务时,不要加 -i选项,因为会输出:

the input device is not a TTY

但是,我看的文章说,去掉-t,即不需要分配伪终端。

ipython

pip3 install ipython


requests.request?  # 查看说明
requests.request??  # 查看源代码 + 说明

%time sleep(1)
%lsmagic  # 列出魔法变量

!pip3 install bs4  # 执行系统命令

jupyter

参考链接 https://zhuanlan.zhihu.com/p/33105153/

底层也依赖了ipython,所以部分操作跟ipython很像。不再详述。

网页版本的。可以使用docker环境来使用。也可以在本地环境安装。本地安装如下:

# 安装 
pip3 install jupyter

# 使用 ,默认目录为当前cmd目录
jupyter notebook   
jupter notebook --port 9999 --no-browser

使用说明

jupyter的用途,其实是在写测试代码,因为,每次只运行一个窗格,而之前的状态,都会保存,比如,一些变量等等。但是,我试过,用jupter来写代码,反而有点鸡肋,为啥呢?因为,我花了1个小时左右,把所有的代码调通,然后,又花了1个小时,将前面的半成品,调整,成为一个程序。整体,非常的浪费时间。

用法:用来测试代码。写的所有的代码,尽量都封装成一个个函数。这样,方便,后期整体封装成一个程序。(或者,同步的,写一个脚本,写一个函数,集成测试一下?)

jupyterlab

高级版的jupyter,功能多一点。

pip install jupyterlab
# 运行
jupyter-lab

更多操作,参见jupyter安装

升级pip

sudo pip3 install fabric

error like this:
Command "python setup.py egg_info"


sudo pip3 install --upgrade setuptools
sudo python3 -m pip install --upgrade pip
sudo pip3 install fabric

python多环境

在windows下安装了anaconda3,故按以下方式安装python多环境。

Linux下的参考文档

# 查看可安装的版本
conda search -f python

# 查询的虚拟环境
conda info --envs 或者conda env list 

# 创建
conda create -n py310 python=3.10.4

# 激活环境
conda activate py310
# 退出环境
conda deactivate

# 移除虚拟环境
conda remove -n yourenvname -all

另一种方式,在Linux可以直接采用Docker的方式,创建python多环境版本。

或者安装两个版本,注意一下命名。可参考本文章

代码片段

字典生成器

亮点:字典生成,外层迭代table,内存迭代s。

def main():
    html = get_page_content()
    soup = BeautifulSoup(html, 'lxml')
    table = soup.find('table', id='proxylisttable')
    rows = table.find_all('tr')[1:-1]  # remove first and last row
    s = ('ip', 'port', 'code', 'contry', 'anonymity', 'google', 'https', 'lastchecked')
    for tr in rows:
        td = tr.find_all('td')
        yield {key: td[i].string for i, key in enumerate(s)}
#print(list(main()))