python基础学习

 

目录

 

1.zip, map, lambda

2.copy, deepcopy, =复制

3.set 集合

4. map, filter, reduce

5. sort, sorted, reverse, reversed

6.callable() 函数

5.round(number [,ndigits ] )

6.装饰器

7.生成器(Generators)

8._ _slots_ _

9.容器 Collections

10.对象自省

11.异常

12.一行式命令

13.使用c扩展

14.python 省内存

15. python多继承


1.zip, map, lambda

zip:纵向连接list

lambda匿名函数,定义简单函数

map:连接函数和参数

>>> a=[1,2,3]
>>> b=[4,5,6]
>>> zip(a,b)
[(1, 4), (2, 5), (3, 6)]
>>> def fun1(x,y):
... return x+y
...
>>> fun1(4,5)
9
>>> fun2=lambda x,y:x+y
>>> fun2(4,5)
9
>>> map(fun2,[3,4],[5,7])
[8, 11]

2.copy, deepcopy, =复制

=赋值,完全copy,用同一份内存

copy,浅拷贝,浅层(第一层)用的不同内存,深层(二维及以上)用的是同一份内存

deepcopy,深拷贝,完全用的不同内存

可认为:copy只拷贝父对象,不会拷贝对象的内部的子对象; copy.deepcopy()深拷贝,拷贝对象及其子对象。

>>> import copy
>>> a=[1,2,3]
>>> b=a
>>> c=copy.copy(a)
>>> id(a)==id(b)
True
>>> a[2]=[33,44]
>>> a
[1, 2, [33, 44]]
>>> b
[1, 2, [33, 44]]
>>> c
[1, 2, 3]
>>> c=copy.copy(a)
>>> c
[1, 2, [33, 44]]
>>> id(a)==id(c)
False
>>> id(a[2])==id(c[2])
True
>>> d=copy.deepcopy(c)
>>> id(d)==id(c)
False
>>> id(d[2])==id(c[2])
False
>>> d[2][1]=55
>>> d
[1, 2, [33, 55]]
>>> c
[1, 2, [33, 44]]
>>> c[2][1]=66
>>> c
[1, 2, [33, 66]]
>>> a
[1, 2, [33, 66]]
>>> c[0]=5
>>> c
[5, 2, [33, 66]]
>>> a
[1, 2, [33, 66]]

3.set 集合

add()

clear()

remove(y):无y元素报错

discard(y) :无y元素不报错

intersection():交集

difference():差集

>>>a=['a','b','c','d','d']
>>>set2=set(['a','f','g'])
>>> set1.difference(set2)
set(['c', 'b', 'd'])
>>> set1.intersection(set2)
set(['a'])

例1:set 对list去重后,顺序也会改变

>>> a = [5, 2, 5, 1, 4, 3, 4,1,0,2,3,8,9,9,9]
>>> print list(set(a))
[0, 1, 2, 3, 4, 5, 8, 9]

若要保持set后顺序也不改变,可执行:

>>> m = [1,3,6,2,2,8,7,5,3]
>>> a = sorted(set(m), key=m.index)
>>> print a
[1, 3, 6, 2, 8, 7, 5]

例2:set只对可hash的类型转化

如直接转化list中的元素也是list,就会报错:

>>> a=[[2,3],[2,3],[5,6]]
>>> set(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

可转换为tuple后set

>>> a=[[2,3],[2,3],[5,6]]
>>> list(set(tuple(t) for t in a))
[(5, 6), (2, 3)]

例3: set中的对象如何去重

先了解set去重原理:https://www.cnblogs.com/linshuhui/p/9580620.html

set 方法先去调用hash方法,hash值相同,再调用eq方法判断。

class Foo:
    def __init__(self,name,count):
        self.name = name
        self.count = count
    def __hash__(self):
        print("%s调用了哈希方法"%self.name)
        return hash(self.count)
    def __eq__(self, other):
        print("%s调用了eq方法"%self.name)
        return self.__dict__ == other.__dict__

f1 = Foo('f1',1)
f2 = Foo('f2',1)
f3 = Foo('f3',3)
ls = [f1,f2,f3]
print(set(ls))


结果:
f1调用了哈希方法
f2调用了哈希方法
f1调用了eq方法
f3调用了哈希方法
set([<__main__.Foo instance at 0x104f9b878>, <__main__.Foo instance at 0x1058098c0>, <__main__.Foo instance at 0x104f9b8c0>])
#定义Person对象
classPerson():
    def__init__(self,name,number):
        self.name=name
        self.number=number


person1=Person('yms',('123456','123'))
person2=Person('yms',('123456','123'))
#将两个对象都放到set里面set([person1,person2])请问怎么去重呢?注意一下('123456','123')是个元组不是普通字符串

针对上例,你需要为这个类定义__eq__、__ne__、__hash__这三个函数,缺一不可:

#/usr/bin/python
#coding=utf-8
import sys
import dict
import math

class Person:
    def __init__(self,name,number):
        self.name=name
        self.number=number

    def __eq__(self,other):
        if isinstance(other,Person):
            return((self.name==other.name)and(self.number==other.number))
        else:
            return False
    def __ne__(self,other):
        return(notself.__eq__(other))
    def __hash__(self):
        return hash(self.name)+hash(self.number)

def main():
    person1=Person('yms',('123456','123'))
    person2=Person('yms',('123456','123'))
    b=[person1,person2]
    c=set([person1,person2])
    #print c
    for i in c:
        print i.name
        print i.number

if __name__ == '__main__':
    res=main()
题目中number是元组,就直接对其使用hash函数了。这个hash函数是随便写的,可自定义调整

4.dict 字典

update() :更新字典中的键/值对,可以修改存在的键对应的值,也可以添加新的键/值对到字典中。

# !/usr/bin/python3
 
D = {'one': 1, 'two': 2}
 
D.update({'three': 3, 'four': 4})  # 传一个字典
print(D)
 
D.update(five=5, six=6)  # 传关键字
print(D)
 
D.update([('seven', 7), ('eight', 8)])  # 传一个包含一个或多个元祖的列表
print(D)
 
D.update(zip(['eleven', 'twelve'], [11, 12]))  # 传一个zip()函数
print(D)
 
D.update(one=111, two=222)  # 使用以上任意方法修改存在的键对应的值
print(D)

#输出结果
{'one': 1, 'three': 3, 'two': 2, 'four': 4}
{'one': 1, 'four': 4, 'six': 6, 'two': 2, 'five': 5, 'three': 3}
{'one': 1, 'eight': 8, 'seven': 7, 'four': 4, 'six': 6, 'two': 2, 'five': 5, 'three': 3}
{'one': 1, 'eight': 8, 'seven': 7, 'four': 4, 'eleven': 11, 'six': 6, 'twelve': 12, 'two': 2, 'five': 5, 'three': 3}
{'four': 4, 'seven': 7, 'twelve': 12, 'six': 6, 'eleven': 11, 'three': 3, 'one': 111, 'eight': 8, 'two': 222, 'five': 5}

4. map, filter, reduce

map()

将序列中的元素通过处理函数处理后返回一个新的列表
filter()

将序列中的元素通过函数过滤后返回一个新的列表
reduce()

将序列中的元素通过一个二元函数处理返回一个结果
将上面三个函数和lambda结合使用

li = [1, 2, 3, 4, 5]
# 序列中的每个元素加1
map(lambda x: x+1, li) # [2,3,4,5,6]
>>> map(lambda x:x%2==0,li)
[False, True, False, True, False]

# 返回序列中的偶数
filter(lambda x: x % 2 == 0, li) # [2, 4]
# 返回所有元素相乘的结果
reduce(lambda x, y: x * y, li) # 1*2*3*4*5 = 120

5. sort, sorted, reverse, reversed

sort 是应用在list上的方法(对象的属性),在原对象直接操作,无返回值 

sorted 是一个函数,可以对所有可迭代的对象进行排序操作,返回的是一个新的 list,如果是字典将返回键的列表

sort 语法

list.sort(cmp=None, key=None, reverse=False)
  • cmp -- 可选参数, 如果指定了该参数会使用该参数的方法进行排序。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)。

sorted语法

sorted(iterable, cmp=None, key=None, reverse=False)
  • iterable -- 可迭代对象。
  • cmp -- 比较的函数,这个具有两个参数,参数的值都是从可迭代对象中取出,此函数必须遵守的规则为,大于则返回1,小于则返回-1,等于则返回0。
  • key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
  • reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。

例1:返回sorted后的dict(不只是key)

#以key排序返回dict
table_data = sorted(table_data.items(), key=lambda d:d[0]) 

reverse()与sort的使用方式一样,而reversed()与sorted()的使用方式相同

PS:通过序列的切片也可以达到“逆转”的效果

>>> mystring="54321"
>>> mytuple=(5,4,3,2,1) 
>>> mylist=[5,4,3,2,1] 
>>> mystring[::-1] 
'12345'
>>> mytuple[::-1] 
(1, 2, 3, 4, 5) 
>>> mylist[::-1] 
[1, 2, 3, 4, 5]

6.callable() 函数

callable() 函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败;但如果返回False,调用对象ojbect绝对不会成功。

对于函数, 方法, lambda 函式, 类, 以及实现了 __call__ 方法的类实例, 它都返回 True。

注:类对象都是可被调用对象,类的实例对象是否可调用对象,取决于类是否定义了__call__方法。

>>>callable(0)
False
>>> callable("runoob")
False
 
>>> def add(a, b):
...     return a + b
... 
>>> callable(add)             # 函数返回 True
True
>>> class A:                  # 类
...     def method(self):
...             return 0
... 
>>> callable(A)               # 类返回 True
True
>>> a = A()
>>> callable(a)               # 没有实现 __call__, 返回 False
False
>>> class B:
...     def __call__(self):
...             return 0
... 
>>> callable(B)
True
>>> b = B()
>>> callable(b)               # 实现 __call__, 返回 True
True

5.roundnumber [ndigits 

返回浮点值四舍五入到ndigits小数点后的数字。如果省略ndigits,则默认为零。结果是一个浮点数。将值四舍五入为最接近的10 乘以n的整数如果两个倍数相等地接近,则四舍五入要远离0(例如,round(0.5)is 1.0和 round(-0.5)is -1.0)。

python 内置函数参考:https://docs.python.org/2/library/functions.html#reduce

6.装饰器

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短。

理解Python中的装饰器,不得不先理解闭包(closure)这一概念

维基百科:

在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。

# print_msg是外围函数
def print_msg():
    msg = "I'm closure"

    # printer是嵌套函数
    def printer():
        print(msg)

    return printer


# 这里获得的就是一个闭包
closure = print_msg()
# 输出 I'm closure
closure()

msg是一个局部变量,在print_msg函数执行之后应该就不会存在了。但是嵌套函数引用了这个变量,将这个局部变量封闭在了嵌套函数中,这样就形成了一个闭包。

(1)蓝本规范:

from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not can_run:
            return "Function will not run"
        return f(*args, **kwargs)
    return decorated
 
@decorator_name
def func():
    return("Function is running")
 
can_run = True
print(func())
# Output: Function is running
 
can_run = False
print(func())
# Output: Function will not run

@wraps接受一个函数来进行装饰,能把原函数的元信息拷贝到装饰器里面的函数中。函数的元信息包括docstring、name、参数列表等等。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

(2)带参数的装饰器

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
 
@logit()
def myfunc1():
    pass
 
myfunc1()
# Output: myfunc1 was called
# 现在一个叫做 out.log 的文件出现了,里面的内容就是上面的字符串
 
@logit(logfile='func2.log')
def myfunc2():
    pass
 
myfunc2()
# Output: myfunc2 was called
# 现在一个叫做 func2.log 的文件出现了,里面的内容就是上面的字符串

(3)装饰器类

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

@logit()
def myfunc1():
    pass

(4)基础解释

1.*args**kwargs 主要用于函数定义。 你可以将不定数量的参数传递给一个函数。不定的意思是:预先并不知道, 函数使用者会传递多少个参数给你, 所以在这个场景下使用这两个关键字。

*args 是用来发送一个非键值对的可变数量的参数列表给一个函数.

def test_var_args(f_arg, *argv):
    print("first normal arg:", f_arg)
    for arg in argv:
        print("another arg through *argv:", arg)

test_var_args('yasoob', 'python', 'eggs', 'test')

输出:
first normal arg: yasoob
another arg through *argv: python
another arg through *argv: eggs
another arg through *argv: test

**kwargs 允许你将不定长度的键值对, 作为参数传递给一个函数。 如果你想要在一个函数里处理带名字的参数, 你应该使用**kwargs

def greet_me(**kwargs):
    for key, value in kwargs.items():
        print("{0} == {1}".format(key, value))


>>> greet_me(name="yasoob")
name == yasoob

使用*args**kwargs来给这个小函数传递参数

def test_args_kwargs(arg1, arg2, arg3):
    print("arg1:", arg1)
    print("arg2:", arg2)
    print("arg3:", arg3)

# 首先使用 *args
>>> args = ("two", 3, 5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# 现在使用 **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two", "arg1": 5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3

FYI:标准参数与*args、**kwargs在使用时的顺序:

some_func(fargs, *args, **kwargs)

7.生成器(Generators)

生成器也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,而是在运行时生成值。作用:节省资源。

大多数时候生成器是以函数来实现的。它们并不返回一个值,而是yield(暂且译作“生出”)一个值,用Python内置函数:next()来获取一个序列的下一个元素

def generator_function():
    for i in range(3):
        yield i

gen = generator_function()
print(next(gen))
# Output: 0
print(next(gen))
# Output: 1
print(next(gen))
# Output: 2
print(next(gen))
# Output: Traceback (most recent call last):
#            File "<stdin>", line 1, in <module>
#         StopIteration

对于一个非迭代器,用内置函数iter()将一个可迭代对象返回一个迭代器对象。

my_string = "Yasoob"
my_iter = iter(my_string)
next(my_iter)
# Output: 'Y'

8._ _slots_ _

在Python中,每个类都有实例属性。默认情况下Python用一个字典来保存一个对象的实例属性。这非常有用,因为它允许我们在运行时去设置任意的新属性。

然而,对于有着已知属性的小类来说,它可能是个瓶颈。这个字典浪费了很多内存

不使用__slots__:

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()
  # ...

第二段代码会为你的内存减轻负担。通过这个技巧,有些人已经看到内存占用率几乎40%~50%的减少。

9.容器 Collections

Python附带一个模块,它包含许多容器数据类型,名字叫作collections。我们将讨论的是:

  • defaultdict

  • counter

  • deque

  • namedtuple

  • enum.Enum (包含在Python 3.4以上)

(1)defaultdict

defaultdict dict类型不同,你不需要检查key是否存在,使用dict会触发KeyError

from collections import defaultdict

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

favourite_colours = defaultdict(list)

for name, colour in colours:
    favourite_colours[name].append(colour)

print(favourite_colours)

(2)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
##  })

(3)dequeue,双端队列,你可以从头/尾两端添加或删除元素

d = deque(range(5))
print(len(d))
## 输出: 5
d.popleft()
## 输出: 0
d.pop()
## 输出: 4
print(d)
## 输出: deque([1, 2, 3])

可以限定dequeue的大小,当超出你设定的限制时,数据会从对队列另一端被挤出去(pop)。

d = deque(maxlen=30)
d = deque([1,2,3,4,5])
d.extendleft([0])
d.extend([6,7,8])
print(d)

## 输出: deque([0, 1, 2, 3, 4, 5, 6, 7, 8])

(4)namedtuple 命名元组

它把元组变成一个针对简单任务的容器。你不必使用整数索引来访问一个namedtuples的数据。你可以像字典(dict)一样访问namedtuples,但namedtuples是不可变的。

一个命名元组(namedtuple)有两个必需的参数。它们是元组名称和字段名称。

在下面的例子中,我们的元组名称是Animal,字段名称是'name','age'和'type'。

from collections import namedtuple

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

print(perry)

## 输出: Animal(name='perry', age=31, type='cat')

print(perry.name)

## 输出: 'perry'
print(perry[0])

## 输出: perry

namedtuple让你的元组变得自文档了,也向后兼容普通元组,这让你的代码更易于维护。 而且,namedtuple的每个实例没有对象字典,所以它们很轻量,与普通的元组比,并不需要更多的内存。这使得它们比字典更快。

可将命名元组转化为字典dict:

from collections import namedtuple

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

## 输出: OrderedDict([('name', 'Perry'), ('age', 31), ...

(4)enum.Enum (Python 3.4+)枚举对象

from collections import namedtuple
from enum import Enum

class Species(Enum):
    cat = 1
    dog = 2
    horse = 3
    aardvark = 4
    butterfly = 5
    owl = 6
    platypus = 7
    dragon = 8
    unicorn = 9
    # 依次类推

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

Animal = namedtuple('Animal', 'name age type')
perry = Animal(name="Perry", age=31, type=Species.cat)
drogon = Animal(name="Drogon", age=4, type=Species.dragon)
tom = Animal(name="Tom", age=75, type=Species.cat)
charlie = Animal(name="Charlie", age=2, type=Species.kitten)

>>> charlie.type == tom.type
True
>>> charlie.type
<Species.cat: 1>

#有三种方法访问枚举数据,例如以下方法都可以获取到'cat'的值
Species(1)
Species['cat']
Species.cat

10.对象自省

(1)dir 它返回一个列表,列出了一个对象所拥有的属性和方法

my_list = [1, 2, 3]
dir(my_list)
# Output: ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
# '__delslice__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__',
# '__getitem__', '__getslice__', '__gt__', '__hash__', '__iadd__', '__imul__',
# '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
# '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__',
# '__setattr__', '__setitem__', '__setslice__', '__sizeof__', '__str__',
# '__subclasshook__', 'append', 'count', 'extend', 'index', 'insert', 'pop',
# 'remove', 'reverse', 'sort']

(2)type返回对象的数据类型,id()返回对象的唯一id

11.异常

包裹到finally从句中的代码不管异常是否触发都将会被执行

包裹到else从句中的代码是在没有触发异常的时候执行

try:
    file = open('test.txt', 'rb')
except IOError as e:
    print('An IOError occurred. {}'.format(e.args[-1]))
else:
    # 这里的代码只会在try语句里没有触发异常时运行,
    # 但是这里的异常将 *不会* 被捕获
    print('This would only run if no exception occurs. And an error here '
          'would NOT be caught.')
finally:
    print("This would be printed whether or not an exception occurred!")

# Output: An IOError occurred. No such file or directory
# This would be printed whether or not an exception occurred!

12.一行式命令

(1)简易Web Server

默认8000接口,可浏览器中输入:127.0.0.1:8000查看本地其服务路径下文件

    # Python 2
    python -m SimpleHTTPServer

    # Python 3
    python -m http.server

(2)打印json数据

    cat file.json | python -m json.tool

(3)脚本性能分析

    python -m cProfile my_script.py

13.使用c扩展

通常我们说的python是cpython,就是底层是c语言实现的python。

开发者有三种方法可以在自己的Python代码中来调用C编写的函数-ctypesSWIGPython/C API,毕竟c比python快50+倍

ctypes是将c程序编程成 .so文件,然后在python程序中调用这个 .so文件

SWIG是Simplified Wrapper and Interface Generator的缩写,开发人员必须编写一个额外的接口文件来作为SWIG(终端工具)的入口,然后在python中import这个模块

Python/C API需要以特定的方式来编写C代码以供Python去调用它。所有的Python对象都被表示为一种叫做PyObject的结构体,并且Python.h头文件中提供了各种操作它的函数。

具体参考:https://eastlakeside.gitbook.io/interpy-zh/c_extensions (6-13 均参考此链接)

14.__future__模块

(1)它可以帮你在Python2中导入Python3的功能。

eg:python3中print是一个函数

print
# Output:

from __future__ import print_function
print(print)
# Output: <built-in function print>

(2)Python2中有12个内置功能在Python3中已经被移除了,强制python2中不出现这些内置功能

from future.builtins.disabled import *

from future.builtins.disabled import *

apply()
# Output: NameError: obsolete Python 2 builtin apply is disabled

(3)其他

from __future__ import print_function
from __future__ import unicode_literals #对字符串使用unicode字符
from __future__ import division         # /除有小数,//为整除
from __future__ import absolute_import  #绝对导入,用环境变量的绝对路径

14.python 省内存

(1)__slot__属性

问题:你的程序要创建大量(可能上百万) 的对象,导致占用很大的内存。

解决方案:对于主要是用来当成简单的数据结构的类而言,你可以通过给类添加__slots__属性来极大的减少实例所占的内存。比如:

class Date:
    __slots__ = ['year', 'month', 'day']
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day

 当你定义__slots__ 后,Python 就会为实例使用一种更加紧凑的内部表示。实例通过一个很小的固定大小的数组来构建,而不是为每个实例定义一个字典,这跟元组或列表很类似。在__slots__ 中列出的属性名在内部被映射到这个数组的指定小标上。使用slots 一个不好的地方就是我们不能再给实例添加新的属性了,只能使用在__slots__ 中定义的那些属性名。

FYI:但不要随意使用__slot__特性:

a.会导致不可使用多继承;

b.Python 的很多特性都依赖于普通的基于字典的实现

(2)生成字符串时使用Format来代替“+”

st = "{0}_{1}_{2}_{3}".format(a,b,c,d) # 对内存更好,不创建临时变量
st2 = a + '_' + b + '_' + c + '_' + d # 在每个"+"时创建一个临时str,这些都是驻留在内存中的。

(3)读文件

read方法:会读取直到EOF,默认参数size=-1时,当文件大小大于可用内存时,自然会发生内存溢出的错误

如果是二进制文件推荐用如下这种写法,可以自己指定缓冲区有多少byte。显然缓冲区越大,读取速度越快。

with open(file_path, 'rb') as f:
    while True:
        buf = f.read(1024)
        if buf:    
            sha1Obj.update(buf)
        else:
            break

readlines方法:会构造一个list。list而不是iter,所以所有的内容都会保存在内存之上,同样也会发生内存溢出的错误

readline方法或直接迭代文件:每次读取一行,速度慢,效率低,但省内存

with open(file_path, 'rb') as f:
    while True:
        line = f.readline()
        if buf:    
            print(line)
        else:
            break

with open(file_path, 'rb') as f:
    for line in f:
        print(line)

 

FYI:检验内存

两种工具guppy与memory_profiler可以很好地来监控python代码运行时的内存占用问题。

15. python多继承

(1)python中使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承,也叫菱形继承问题)

eg:

class X(object):
    def f(self):
        print 'x'
class A(X):
    def f(self):
        print 'a'

    def extral(self):
        print 'extral a'

class B(X):
    def f(self):
        print 'b'

    def extral(self):
        print 'extral b'

class C(A, B, X):
    def f(self):
        super(C, self).f()
        print 'c'

print C.mro()
c = C()
c.f()
c.extral()

#结果:
[<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.X'>, <type 'object'>]
a
c
extral a

(2)super() 函数

用于调用父类(超类)的一个方法。

super(type[, object-or-type]) 
type -- 类。
object-or-type -- 类,一般是 self

super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。(MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表)

在Python2.3之前,MRO是基于深度优先算法的,自2.3开始使用C3算法,定义类时需要继承object,这样的类称为新式类,否则为旧式类,旧式类查找属性时是深度优先搜索,新式类则是广度优先搜索

广度优先的提出解决了旧式类的本定优先级和单调性问题

  • 本地优先级:指声明时父类的顺序,比如C(A,B),如果访问C类对象属性时,应该根据声明顺序,优先查找A类,然后再查找B类。
  • 单调性:如果在C的解析顺序中,A排在B的前面,那么在C的所有子类里,也必须满足这个顺序

Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx 

如上面多继承的super为2.x的,在3.x中可以写成super.f()

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值