python call函数_Python中的__call__()函数

__call__()函数

python中类的实例(对象)可以被当做函数对待.也就是说,我们可以将它们作为输入传递到其他的函数/方法中并调用它们,正如我们调用一个正常的函数那样。而类中的call()函数的意义正在于此.为了将一个类实例当作函数调用,我们需要再类中事先call()方法.假设x是X类的一个实例.调用x.__call__(1,2)等同于调用x(1,2).这个实例本身在这里相当于一个函数.

Python pickle模块学习

Python提供了一个简单的持久化功能.可以将对象以文件的形式存放在磁盘上.

Pickle模块只能在Python中使用,python中几乎所有的数据类型(列表,字典,集合,类等),都可以用pickle来序列化.

pickle序列化以后的数据,可读性差,人一般无法识别

pickle.dump(obj,file[,protocol])

序列化对象,并将结果数据流写入到文件对象中.参数protocol是序列化模式,默认值为0,表示文本的形式的序列化。protocol也可以是1或2,表示二进制的形式序列化

pickle.load(file)

反序列化对象.将文件中的数据解析为一个Python对象.其中要注意的是,在load(file)的时候,要从python中能够找到类的定义,否则会报错.

pickle.clear_memo()

清空pickler的“备忘”,使用pickler实例在序列化对象的时候,它会记住已经被序列化的对象引用,所以对同一对象多次调用dump(obj),pickler不会”傻傻”的去多次序列化

Python collections

collections是Python内建的一个集合模块,提供了许多有用的集合类.

namedtuple

我们知道tuple可以表示一个元组,是不可变的集合,例如一个点的二维坐标就可以这样表示成

1p=(1,2)

但是,看到(1,2),很难看出这个tuple是用来表示一个坐标的

定义一个class又小题大做了,这时,namedtuple就派上了用场:

1

2

3

4

5

6

7>>>from collections import namedtuple

>>>Point=namedtuple('Point',['x','y'])

>>>p=Point(1,2)

>>>p.x

1

>>>p.y

2

namedtuple是一个函数,它用来创建一个自定义的tuple对象,并且规定了tuple元素的个数,并可以用属性而不是索引来引用tuple的某个元素.

这样一来,我们的namedtuple可以很方便地定义一种数据类型,它具备tuple的不变性,又可以根据属性来引用,十分方便.

deque

使用list存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为list是线性存储,数据量大的时候,插入和删除效率很低.

deque是为了高效地实现插入和删除操作的上香列表,适合用于队列和栈

1

2

3

4

5

6>>>from collections import deque

>>>q=deque(['a','b','c'])

>>>q.append('x')

>>>q.appendleft('y')

>>>q

deque(['y','a','b','c','x'])

deque除了实现list的append和pop外,还支持appendleft()和popleft()

Counter

Counter是一个简单的计数器,例如,统计字符出现的个数

1

2

3

4

5

6

7>>>from collections import Counter

>>>c=Counter()

>>>for ch in 'programming':

c[ch]=c[ch]+1

...

>>>c

Counter({'g':2,'m'2,'r':2,'a':1,'i':1,'o':1,'n':1,'p':1})

Counter实际上也是dict的一个子类,上面的结果可以看出,字符’g’,’m’,’r’各出现2次,其他字符出现1次

zip

感觉本文成了python专项贴.

zip的用法

解压

传入的data为batch个元组,即batch个(iamges,captions) 对儿

images,captions=zip(data)

表示zip( data)=(batch 个image,batch 个 caption)

data=zip(images,captions)

例子1

2

3

4

5

6

7

8

9>>>a=[1,2,3]

>>>b=[4,5,6]

>>>c=[4,5,6,7,8]

>>>zipped=zip(a,b)

[(1,4),(2,5),(3,6)]

>>>zip(a,c)

[(1,4),(2,5),(3,6)]

>>>zip(*zipped)

[(1,2,3),(4,5,6)]

老生常谈的深拷贝和浅拷贝

https://blog.csdn.net/edogawachia/article/details/79762310

平时写Python用惯了numpy的矩阵类型,只用python自带的list做有关矩阵的(二维数组的)处理的时候碰到各种bug。这里是今日份的bug和解决方案。

问题缘起

在一个程序中,我们希望用list实现一个二维数组,然后对其中的元素挨个根据下标的指引来进行赋值。我们对这个二维数组也就是矩阵的初始化是这样的:

1

2m, n = 5, 3

matrix = [[1] * n] * m

其中m,n分别是行数和列数。乍一看没有什么问题,但是在赋值的时候出现了这样的一幕:

1

2

3

4

5

6

7matrix

Out[199]: [[1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1]]

matrix[1][0] = 233

matrix

Out[201]: [[233, 1, 1], [233, 1, 1], [233, 1, 1], [233, 1, 1], [233, 1, 1]]

深拷贝与浅拷贝

首先要知道拷贝与引用的区别,拷贝只是单单对值得复制,引用是像指针一样的存在

在python 中,对一个list后面用 乘号 再加上 数字 的方法来初始化一个list,实际上是对这个list进行了浅拷贝(shallow copy),在python中,有深拷贝(deep copy) 和 浅拷贝 的区别。简单来讲就是:深拷贝就是把要拷贝的对象整体复制一份,存在新开辟的空间里;而浅拷贝指的是,对于要拷贝的对象要复制一份,但是对于其内部的子对象就不复制了,而是直接引用,也就是类似于添加了一个链接而已,如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16import copy

a

Out[210]: [888, 2, 3, [4, 5]]

b = copy.copy(a)

b

Out[212]: [888, 2, 3, [4, 5]]

b[0] = 233

b

Out[214]: [233, 2, 3, [4, 5]]

a

Out[215]: [888, 2, 3, [4, 5]]

b[3][1] = 666

b

Out[217]: [233, 2, 3, [4, 666]]

a

Out[218]: [888, 2, 3, [4, 666]]

这里就很明显了,我们对a做一个浅拷贝,目的是b,然后我们对b进行操作,如果对list中的整数赋值,也就是对象中的元素赋值,那么就只改变b中的这个位置的元素值,而a的不变;但是如果我们对list中的list,也就是子对象进行赋值,那么我们法线,这个操作同样也影响了a中的结果。

(很明显浅拷贝就是只是对浅层元素进行拷贝,深层元素采用引用)

copy 这个模块里的copy()是浅拷贝的函数,我们在试一下深拷贝deepcopy()函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15a

Out[219]: [888, 2, 3, [4, 666]]

b = copy.deepcopy(a)

b

Out[221]: [888, 2, 3, [4, 666]]

b[0] = 1

b

Out[223]: [1, 2, 3, [4, 666]]

a

Out[224]: [888, 2, 3, [4, 666]]

b[3][0] = 233

b

Out[226]: [1, 2, 3, [233, 666]]

a

Out[227]: [888, 2, 3, [4, 666]]

这就很科学了!两个对象 a 和 b 互不打扰,很和谐。

另外,我们通常的赋值操作(list的直接赋值)又是怎样的结果呢?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15a

Out[229]: [888, 2, 3, [4, 666]]

b = a

b

Out[231]: [888, 2, 3, [4, 666]]

b[0] = 1

b

Out[233]: [1, 2, 3, [4, 666]]

a

Out[234]: [1, 2, 3, [4, 666]]

b[3][0] = 1

b

Out[236]: [1, 2, 3, [1, 666]]

a

Out[237]: [1, 2, 3, [1, 666]]

可以看出来,直接赋值的结果是比浅拷贝还浅拷贝的。。。因为a和b根本上就是指向的同一个对象!也就是说,a和b是这个对象的两个引用(reference),修改一个就会改变另一个。

对上文中问题的解释

了解了这两个概念的区别,就可以解释上述的问题。首先,我们对

1

2

3[1] * 3 # 创建了 1 的三个浅拷贝,得到了[1,1,1],此时我们修改某个1,不会影响其他的,因为这是int的元素,不是子对象

[[1] * 3] * 4 创建了list列表[1,1,1]的四个浅拷贝,这里得到的list是以list为元素类型的,因此改变一个就会影响其他

# 这就是我们开始会得到所有行都改变的原因,因为他们实际上指向的是同一个东西!

改用如下方式初始化数组,就可以得到一个可以通过二维下标访问的矩阵了。

1matrix = [[ 1 for i in range(n)] for i in range(m)]

这就是之前整理过的list comprehension的方法生成list。

Python函数的的传值和传引用

https://www.jianshu.com/p/2c83db2f5ef3

Python函数有一个很变态的地方,就是他调用函数时,将传递参数的方式是传引用.这种传参对于int,double,str,tuple型没有什么问题,但对于list,dict,set 就会出现传引用的问题.

在网上大部分博客的结论是:

不可变对象作为函数参数,python通过值传递

可变对象作为函数参数,python通过引用传递

注:Python中,数值类型(int和float)、字符串str、元组tuple都是不可变类型。而列表list、字典dict、集合set是可变类型。

这种时候我就会比较想念C++的形参。

那么怎么样处理才能使得我们的可变对象在经过函数后不改变呢

网上看到的一个方法是在函数中新建对象,然后将传递的参数赋给他。

对比:

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# 处理多个银行账户的余额信息

def addInterest(balances, rates):

print()

print("第二处", id(balances))

for i in range(len(balances)):

balances[i]= balances[i]*(1+rates)

print()

print("第三处",id(balances))

def test():

amounts = [1000,105,3500,739]

print()

print("第一处",id(amounts))

rate = 0.05

addInterest(amounts, rate)

print()

print(amounts)

print()

print("第四处",id(amounts))

test()

#结果

第一处 41203656

第二处 41203656

第三处 41203656

第三处 41203656

第三处 41203656

第三处 41203656

[1050.0, 110.25, 3675.0, 775.95]

第四处 41203656

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# 计算单个银行账户余额

def addinterest(balance, rate):

print("第二处", id(balance))

newBalance = balance * (1 + rate)

print()

print("第三处", id(balance))

print()

print("第四处", id(newBalance))

return newBalance

def main():

amount = 1000

print("第一处", id(amount))

print()

rate = 0.05

amount = addinterest(amount, rate)

print()

print("第五处", id(amount))

print()

print(amount)

print("第六处", id(amount))

main()

#结果

第一处 33533648

第二处 33533648

第三处 33533648

第四处 33563344

第五处 33563344

1050.0

第六处 33563344

可以看到第一种情况,id都是一样的,而第二种情况新建了对象,id是变化的了

得出结论:对于可变对象作为函数参数,且参数不指向其他对象时,相当于引用传递;否则,若参数指向其他对象,则对参数变量的操作并不影响原变量的对象值

大大的总结

对于不可变对象作为函数参数,相当于C系语言的值传递;

对于可变对象作为函数参数,且参数不指向其他对象时,相当于C系语言的引用传递。

对于可变对象作为函数参数,参数指向其他对象,对参数变量的操作不影响原变量的值。

python牛客网做题总结

现在许多公司都是在牛客网上进行笔试的,因此有必要了解一下牛客网上的编程方式

坑很多:

一、题目提示有多个case 或者 输出‘空,检查是否输入多个case’

1

2

3

4

5

6

7

8while True:

try:

# your code

except:

break

二、题目提示多组同时输入或加入while循环超时

1

2

3import sys

for line in sys.stdin:

N = line.strip()

Python牛客注意事项

提高通过率技巧时间复杂度问题:增加条件break或continue出循环,能break尽量break;减少不必要的判断条件(比如在不在字典中);做一些排序来减少后期的工作量

空间复杂度问题:

边界条件:某些数据是不是始终存在

测试用例通过但0%的原因:1.没有理解题意

输入

而可以考虑用input

1

2

3Input=input().split(' ')

a=int(Input[0])

b=int(Input[1])

注意输入进去的都是string类型

输出

一般逐行打印

1

2

3for i in result:

print(i)

常用数据结构

list和dict比较好用,不能导入numpy库

list:做整体的排序

dict:做局部的排序,要在单个条件下xxx

常用函数

list

min() max() sum() .index()

.remove(具体内容) .pop(索引号) del a[索引号]

.sort(key=lambda x: x[0])

.sort(key=lambda x:(-x[1],x[0],x[2]))#默认是升序,加个符号变降序,可做多级排序。

sorted()#不在本地做排序

元素 in list名称

变量

float(‘inf’)

字典

keys()

.values()

.items()#返回的是元组

字符串

.strip() 去除首位空格

.strip().strip(‘-a’)去除首位空格和字符

S[:3]+S[5:] 拼接字符串,去除某个字符

.replace(‘a’,’b’) 替换字符

re.sub(‘a’,’b’,s) 替换字符

ord(a)是用来将单个字符转化成它的ASCII值,因为python里不像C++那样两个字符相减可以求出ASCII数值差

chr(100)是ord的逆过程,将ASCII值转化成字符

Python sorted

一般的sorted

1

2sorted([5, 2, 3, 1, 4])

#[1, 2, 3, 4, 5]

其实list也自带sort()方法

1

2

3

4a = [5, 2, 3, 1, 4]

a.sort()

a

#[1, 2, 3, 4, 5]

Key参数/函数

从python2.4开始,list.sort()和sorted()函数增加了key参数来指定一个函数,此函数将在每个元素比较前被调用。 例如通过key指定的函数来忽略字符串的大小写:

1

2sorted("This is a test string from Andrew".split(), key=str.lower)

['a', 'Andrew', 'from', 'is', 'string', 'test', 'This']

key参数的值为一个函数,此函数只有一个参数且返回一个值用来进行比较。这个技术是快速的因为key指定的函数将准确地对每个元素调用。

更广泛的使用情况是用复杂对象的某些值来对复杂对象的序列排序,例如:

1

2

3

4

5

6

7>>>student_tuples = [

('john', 'A', 15),

('jane', 'B', 12),

('dave', 'B', 10),

]

>>>sorted(student_tuples, key=lambda student: student[2]) # sort by age

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

同样的技术对拥有命名属性的复杂对象也适用,例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14>>>class Student:

def __init__(self, name, grade, age):

self.name = name

self.grade = grade

self.age = age

def __repr__(self):

return repr((self.name, self.grade, self.age))

>>>student_objects = [

Student('john', 'A', 15),

Student('jane', 'B', 12),

Student('dave', 'B', 10),

]

>>>sorted(student_objects, key=lambda student: student.age) # sort by age

[('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)]

升序和降序

list.sort()和sorted()都接受一个参数reverse(True or False)来表示升序或降序排序。例如对上面的student降序排序如下:

1

2

3

4>>>sorted(student_tuples, key=itemgetter(2), reverse=True)

[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

>>>sorted(student_objects, key=attrgetter('age'), reverse=True)

[('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)]

其他语言普遍使用的排序方法-cmp函数

1

2

3

4>>>def numeric_compare(x, y):

return x - y

>>>sorted([5, 2, 4, 1, 3], cmp=numeric_compare)

[1, 2, 3, 4, 5]

或者你可以反序排序:

1

2

3

4>>>def reverse_numeric(x, y):

return y - x

>>>sorted([5, 2, 4, 1, 3], cmp=reverse_numeric)

[5, 4, 3, 2, 1]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值