重点汇总-python-gitbook-重要点学习-1
Python中关键字yield有什么作用?
为了理解yield
有什么用,首先得理解generators
,而理解generators
前还要理解iterables
Iterables
当你创建了一个列表,你可以一个一个的读取它的每一项,这叫做iteration:
>>> mylist = [1, 2, 3]
>>> for i in mylist:
... print(i)
1
2
3
Mylist是可迭代的.当你用列表推导式的时候,你就创建了一个列表,而这个列表也是可迭代的:
>>> mylist = [x*x for x in range(3)]
>>> for i in mylist:
... print(i)
0
1
4
所有你可以用在for...in...
语句中的都是可迭代的:比如lists
,strings
,files
...因为这些可迭代的对象你可以随意的读取所以非常方便易用,但是你必须把它们的值放到内存里,当它们有很多值时就会消耗太多的内存.
Generators
生成器也是迭代器的一种,但是你只能迭代它们一次.原因很简单,因为它们不是全部存在内存里,它们只在要调用的时候在内存里生成:
>>> mygenerator = (x*x for x in range(3))
>>> for i in mygenerator:
... print(i)
0
1
4
生成器和迭代器的区别就是用()
代替[]
,还有你不能用for i in mygenerator
第二次调用生成器:首先计算0,然后会在内存里丢掉0去计算1,直到计算完4.
-----注:若二次调用即出现闭包现象,很容易出错,廖在闭包处多次强调
Python中的元类(metaclass)是什么?
metaclass,直译为元类,简单的解释就是:
当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。
元类负责创建类, 类负责创建实例,主要应用在ORM上
用Python如何一个文件是否存在?
不用try:语句可以一个文件存在
如果不确定文件存不存在,可以这样做:
import os.path
os.path.isfile(fname) # ⚠️举例 os.path.isfile(' /Users/jkx/Desktop/hello.txt ') ' ' 号不可少,否则报错。结果会提示 True or False
在Python中有三元运算符吗?
语法如下:
a if test else b # 牢记!
来个大栗子:
>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'
在Python中调用外部命令? (不太懂)
-
os.system
("命令加参数")
把命令和参数传递给你系统的shell中.用这个命令的好处在于你可以一次运行好多命令还可以设置管道来进行重定向.来个栗子:os.system
("命令 < 出入文件 | 另一个命令 > 输出文件")尽管它非常方便,但是你还是不得不手动输入像空格这样的shell字符.从另一方面讲,对于运行简单的shell命令而不去调用外部程序来说的话还是非常好用的.
-
- stream = os.popen("命令和参数")
这个命令和os.system
差不多,但是它提供了一个连接标准输入/输出的管道.还有其他3个popen
可以调用.如果你传递一个字符串,你的命令会把它传递给shell
,如果你传递的是一个列表,那么就不用担心溢出字符了(escaping characters).
- stream = os.popen("命令和参数")
- subprocess模块的管道Popen.
这个Popen是打算用来替代os.popen的方法,它有点复杂:
- subprocess模块的管道Popen.
print subprocess.Popen("echo Hello World", shell=True,stdout=PIPE).stdout.read()
而用os.popen
:
print os.popen("echo Hello World").read()
它最大的优点就是一个类里代替了原来的4个不同的popen
-
subprocess
的call
方法.
它的基本用法和上面的Popen类参数一致,但是它会等待命令结束后才会返回程序.来个大狸子:
-
return_code = subprocess.call("echo Hello World", shell=True)
在Python里如何用枚举类型?
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
这样我们就获得了Month类型的枚举类,可以直接使用Month.Jan
来引用一个常量,或者枚举它的所有成员:
for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
value
属性则是自动赋给成员的int
常量,默认从1开始计数。
如果需要更精确地控制枚举类型,可以从Enum派生出自定义类:
from enum import Enum, unique
@unique
class Weekday(Enum):
Sun = 0 # Sun的value被设定为0
Mon = 1
Tue = 2
Wed = 3
... ...
如何在一个表达式里合并两个字典?
我有两个Python字典,我想写一个表达式来返回两个字典的合并.update()
方法返回的是空值而不是返回合并后的对象.
>>> x = {'a':1, 'b': 2}
>>> y = {'b':10, 'c': 11}
>>> z = x.update(y)
>>> print z
None
>>> x
{'a': 1, 'b': 10, 'c': 11}
怎么样才能最终让值保存在z而不是x?
>>> z = dict(list(x.items()) + list(y.items()))
>>> z
{'a': 1, 'c': 11, 'b': 10} # 字典中key必须唯一的,这里 'b' 用的是y的值
或者:
z = x.copy() # 涉及 copy() update() 用法
z.update(y)
装饰器@staticmethod和@classmethod有什么区别?
class A(object):
# 实例方法
def foo(self,x):
print "executing foo(%s,%s)"%(self,x)
# 类方法
@classmethod
def class_foo(cls,x):
print "executing class_foo(%s,%s)"%(cls,x)
# 静态方法
@staticmethod
def static_foo(x):
print "executing static_foo(%s)"%x
a = A() # 结果下图

可以看到,实例是三种方法都可以调用的,而类只可以调用两种。所以这些方法的使用就是看你是否要让类不需要通过实例来调用方法,而类方法和静态方法的区别就是你是否要在该方法引导类的属性或者其他类的类方法。
知乎的解释:
一个基本的实例方法就向下面这个:
class Kls(object):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
ik1 = Kls('arun')
ik2 = Kls('seema')
ik1.printd() # arun
ik2.printd() # seema

然后看一下代码和示例图片:
- 1,2参数传递给方法.
- 3 self参数指向当前实例自身.
- 4 我们不需要传递实例自身给方法,Python解释器自己会做这些操作的.
如果现在我们想写一些仅仅与类交互而不是和实例交互的方法会怎么样呢? 我们可以在类外面写一个简单的方法来做这些,但是这样做就扩散了类代码的关系到类定义的外面. 如果像下面这样写就会导致以后代码维护的困难:
def get_no_of_instances(cls_obj):
return cls_obj.no_inst
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
ik1 = Kls()
ik2 = Kls()
print(get_no_of_instances(Kls)) # 输出 2
@classmethod
我们要写一个只在类中运行而不在实例中运行的方法. 如果我们想让方法不在实例中运行,可以这么做:
def iget_no_of_instance(ins_obj):
return ins_obj.__class__.no_inst
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
ik1 = Kls()
ik2 = Kls()
print iget_no_of_instance(ik1) # 输出 2
在Python2.2以后可以使用@classmethod装饰器来创建类方法:
class Kls(object):
no_inst = 0
def __init__(self):
Kls.no_inst = Kls.no_inst + 1
@classmethod
def get_no_of_instance(cls_obj):
return cls_obj.no_inst
ik1 = Kls()
ik2 = Kls()
print ik1.get_no_of_instance() # 2
print Kls.get_no_of_instance() # 2
这样的好处是: 不管这个方式是从实例调用还是从类调用,它都用第一个参数把类传递过来.
@staticmethod
经常有一些跟类有关系的功能但在运行时又不需要实例和类参与的情况下需要用到静态方法. 比如更改环境变量或者修改其他类的属性等能用到静态方法. 这种情况可以直接用函数解决, 但这样同样会扩散类内部的代码,造成维护困难.
比如这样:
IND = 'ON'
def checkind():
return (IND == 'ON')
class Kls(object):
def __init__(self,data):
self.data = data
def do_reset(self):
if checkind():
print('Reset done for:', self.data)
def set_db(self):
if checkind():
self.db = 'new db connection'
print('DB connection made for:',self.data)
ik1 = Kls(12)
ik1.do_reset() # Reset done for: 12
ik1.set_db() # DB connection made for: 12
如果使用@staticmethod就能把相关的代码放到对应的位置了.
IND = 'ON'
class Kls(object):
def __init__(self, data):
self.data = data
@staticmethod
def checkind():
return (IND == 'ON')
def do_reset(self):
if self.checkind():
print('Reset done for:', self.data)
def set_db(self):
if self.checkind():
self.db = 'New db connection'
print('DB connection made for: ', self.data)
ik1 = Kls(12)
ik1.do_reset() # Reset done for: 12
ik1.set_db() # DB connection made for: 12
下面这个更全面的代码和图示来展示这两种方法的不同
@staticmethod
和 @classmethod
的不同
class Kls(object):
def __init__(self, data):
self.data = data
def printd(self):
print(self.data)
@staticmethod
def smethod(*arg):
print('Static:', arg)
@classmethod
def cmethod(*arg):
print('Class:', arg)
>>> ik = Kls(23)
>>> ik.printd()
23
>>> ik.smethod()
Static: ()
>>> ik.cmethod()
Class: (<class '__main__.Kls'>,)
>>> Kls.printd()
TypeError: unbound method printd() must be called with Kls instance as first argument (got nothing instead)
>>> Kls.smethod()
Static: ()
>>> Kls.cmethod()
Class: (<class '__main__.Kls'>,)
下面这个图解释了以上代码是怎么运行的:
