一些python基础问题

By | 2019年1月13日

以下是《python进阶中文版》的一些总结和个人记录内容

http://docs.pythontab.com/interpy/


1、set()  build an ordered  collections of unique elements

用set()强制转换时,会排序??,去重。。排序的结果存在不正确。

set.intersection 交集

set.difference  差集

1/1 zip()产生的生成器只能使用一次。

如:

prices_and_names = zip(prices.values(), prices.keys())
print(min(prices_and_names)) # OK
print(max(prices_and_names)) # ValueError: max() arg is an empty sequence

正确使用:

min_price = min(zip(prices.values(), prices.keys()))
# min_price is (10.75, 'FB')
max_price = max(zip(prices.values(), prices.keys()))
# max_price is (612.78, 'AAPL')

2、random.choice 

从给定的序列中随机选择一个元素返回。

源码:

def choice(self,seq):
    return seq[int(self.random() * len(seq))]

所以,如果给定的输入序列为空,会报错。list index out of range.

3、默认参数问题

g = lambda x, y=2, z : x + y**z
g(1, z=10) = 

报错。SyntaxError: non-default argument follows default argument

默认参数后必须都是默认参数。

4、map,filter,reduce

print map(lambda x,y:x+y,[1,2,3,4],[1,6,8,9])
print filter(lambda x:x>3,[2,4,6,8])
print reduce(lambda x,y:x+y,[1,2,3,4])

res:[2, 8, 11, 13]    [4, 6, 8]    10

5、装饰器  函数和类

装饰器函数

from functools import wraps

def logit(logfile='out.log'):
    def logging_decorator(func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile,并写入内容
            with open(logfile, 'a') as opened_file:
                # 现在将日志打到指定的logfile
                opened_file.write(log_string + '\n')
            return func(*args, **kwargs)
        return wrapped_function
    return logging_decorator

装饰器类,支持继承

from functools import wraps

class logit(object):
    def __init__(self, logfile='out.log'):
        self.logfile = logfile

    def __call__(self, func):
        @wraps(func)
        def wrapped_function(*args, **kwargs):
            log_string = func.__name__ + " was called"
            print(log_string)
            # 打开logfile并写入
            with open(self.logfile, 'a') as opened_file:
                # 现在将日志打到指定的文件
                opened_file.write(log_string + '\n')
            # 现在,发送一个通知
            self.notify()
            return func(*args, **kwargs)
        return wrapped_function

    def notify(self):
        # logit只打日志,不做别的
        pass
class email_logit(logit):
    '''
    一个logit的实现版本,可以在函数调用时发送email给管理员
    '''
    def __init__(self, email='admin@myproject.com', *args, **kwargs):
        self.email = email
        super(logit, self).__init__(*args, **kwargs)

    def notify(self):
        # 发送一封email到self.email
        # 这里就不做实现了
        pass


6、可变类型

def add_to(num, target=[]):
    target.append(num)
    return target

结果错误,target会成为类似全局变量的东西。

在Python中当函数被定义时,默认参数只会运算一次,而不是每次被调用时都会重新运算。你应该永远不要定义可变类型的默认参数,除非你知道你正在做什么。

正确:

def add_to(element, target=None):
    if target is None:
        target = []
    target.append(element)
    return target

7、__slots__

对类使用__slots__可以减少内存。

在Python中,每个类都有实例属性。默认情况下Python用一个字典来保存一个对象的实例属性。这非常有用,因为它允许我们在运行时去设置任意的新属性。
然而,对于有着已知属性的小类来说,它可能是个瓶颈。这个字典浪费了很多内存。Python不能在对象创建时直接分配一个固定量的内存来保存所有的属性。因此如果你创建许多对象(我指的是成千上万个),它会消耗掉很多内存。

class MyClass(object):
    def __init__(self, name, identifier):
        self.name = name
        self.identifier = identifier
        self.set_up()
    # ...
#使用 __slots__:
class MyClass(object):
    __slots__ = ['name', 'identifier']
    def __init__(self, name, identifier):
        self.name = name
        self.identifier = identifier
        self.set_up()
以下通过ipython根据来查看内存使用情况,可以看到使用slots后的好处。
Python 3.4.3 (default, Jun  6 2015, 13:32:34)
Type "copyright", "credits" or "license" for more information.

IPython 4.0.0 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: import ipython_memory_usage.ipython_memory_usage as imu

In [2]: imu.start_watching_memory()
In [2] used 0.0000 MiB RAM in 5.31s, peaked 0.00 MiB above current, total RAM usage 15.57 MiB

In [3]: %cat slots.py
class MyClass(object):
        __slots__ = ['name', 'identifier']
        def __init__(self, name, identifier):
                self.name = name
                self.identifier = identifier

num = 1024*256
x = [MyClass(1,1) for i in range(num)]
In [3] used 0.2305 MiB RAM in 0.12s, peaked 0.00 MiB above current, total RAM usage 15.80 MiB

In [4]: from slots import *
In [4] used 9.3008 MiB RAM in 0.72s, peaked 0.00 MiB above current, total RAM usage 25.10 MiB

In [5]: %cat noslots.py
class MyClass(object):
        def __init__(self, name, identifier):
                self.name = name
                self.identifier = identifier

num = 1024*256
x = [MyClass(1,1) for i in range(num)]
In [5] used 0.1758 MiB RAM in 0.12s, peaked 0.00 MiB above current, total RAM usage 25.28 MiB

In [6]: from noslots import *
In [6] used 22.6680 MiB RAM in 0.80s, peaked 0.00 MiB above current, total RAM usage 47.95 MiB

8、collections

defaultdict无key不报错的dict:

import collections
tree = lambda: collections.defaultdict(tree)
some_dict = tree()
some_dict['colours']['favourite'] = "yellow"

## 运行正常
#你可以用json.dumps打印出some_dict,例如:

import json
print(json.dumps(some_dict))
## 输出: {"colours": {"favourite": "yellow"}}

counter计数器:

from collections import Counter

colours = (
    ('Yasoob', 'Yellow'),
    ('Ali', 'Blue'),
    ('Arham', 'Green'),
    ('Ali', 'Black'),
    ('Yasoob', 'Red'),
    ('Ahmed', 'Silver'),
)

favs = Counter(name for name, colour in colours)
print(favs)

## 输出:
## Counter({
##     'Yasoob': 2,
##     'Ali': 2,
##     'Arham': 1,
##     'Ahmed': 1
##  })

deque双端队列:

popleft,pop,extendleft,extend

注意:extendleft([1,2,3])实际上会先在左边插入1,然后2,然后3。最后结果如:3,2,1。。。

namedtuple命名元组:

from collections import namedtuple

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="perry", age=31, type="cat")
print(perry[0])

## 输出: perry

使用方式:命名元组需要两个初始化参数,元组名称和字段名称。命名元组能够像字典一样访问,如perry.name。且比字典快,和普通元组性能差不多。

同样,命名元组不能进行赋值。

命名元组可以使代码自文档,且向下兼容。可以像普通元组一样通过下标访问。

Enum枚举类型:

from collections import namedtuple
from enum import Enum

class Species(Enum):
    cat = 1
    dog = 2
    horse = 3
    aardvark = 4

    # 但我们并不想关心同一物种的年龄,所以我们可以使用一个别名
    kitten = 1  # (译者注:幼小的猫咪)
    puppy = 2   # (译者注:幼小的狗狗)

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="Perry", age=31, type=Species.cat)

enumerate:

可以用在对list的for循环中,获取索引和元素,并且,可以传入参数,说明索引从几开始。

my_list = ['apple', 'banana']
for c, value in enumerate(my_list, 1):
    print(c, value)

# 输出:
(1, 'apple')  #无参数1时:(0,'apple')
(2, 'banana') #无参数1时:(1,'banana')

9、一行式

locals和globals函数:

locals展示当前作用区域的局部变量。用法如下:

class A(object):
        def __init__(self, a, b, c, d, e, f):
            self.__dict__.update({k: v for k, v in locals().items() if k != 'self'})

上述代码省去了一行行赋值。locals展示的是变量键值对。

globals展示程序所有变量。较少会用到。

csv转为json:

python -c "import csv,json;print json.dumps(list(csv.reader(open('csv_file.csv'))))"

构建共享文件夹:

    # Python 2
    python -m SimpleHTTPServer

    # Python 3
    python -m http.server

脚本性能分析:

python -m cProfile my_script.py

列表碾平(不定层数列表):

flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x]

10、for-else
for有一个特殊用途,可携带else字句,else的代码在for循环正常结束才会执行。该功能在for循环中存在break,且我们希望知道for循环是否break结束还是正常结束时用处很大。

for item in container:
    if search_something(item):
        # Found it!
        process(item)
        break
else:
    # Didn't find anything..
    not_found_in_container()

发表评论