basic concept
- python 中
一切皆为对象,即使类本身也是一种对象(类对象/Class Objects),所以避免使用其他语言中的instance,而是instance object,class object,method object. - 使用
attribute(属性)来表达成员的含义,有数据属性以及方法属性,一个object=数据属性+方法属性 function与method有区别,前者一般指普通函数,后者一般指的是bounding method(instance object 的方法属性)- 我的形象理解,python的世界中,有三种层级的对象,分别负责创建下一级别的对象,由上到下是type关系,不是继承关系
- 第一阶级:metaclass/type object。
- 第二阶级:class object。
- 第三阶级:instance object.
- 常说的UML图中,描述的是同一阶级内部之间的继承关系(主要第二层),与不同阶级无关。python可以用
issubclass()检查。 type()可以查看其上一层级的object,或者说这个对象是由哪个类对象创造的- metaclass比较神奇,因为其type为自身。其父类也是自身。
- object类对象,跨越一二层,是他们公共的父类。
- 第一阶层,实际编程很少需要考虑。
- python中所有的方法都是虚方法
- 与C不同,在函数内部默认不使用全部变量,除非使用global指定,且if,for,while,try之类的关键字不会产生作用域。
- python3 中的round()函数并不是四舍五入的,应该是
四舍,六入,五选偶,这样做是保证总误差不会被累积。 - lambda函数的写法
lambda x: x+1 map()在python中一个函数,而非Dict(),注意与C++区别,他会给每个元素执行一遍函数,并且返回一个可以迭代的map对象。也可以通过list()等方法,转成list对象。- sort方法会inplace修改对象,sorted不会。
string
a = "123"
b = a
a = "456" # 字符串之间的拷贝都是深拷贝
print (b)
path_t =r"D:\worksapce_python\20160426_cp\training" # 禁止使用转义字符
a = 123
b = 456
c1 = f"a={a}, b={b}" # 两种初始化方法 1
c2 = "a={}, b={}".format(a,b) # 两种初始化方法 2
container
#list, 顺序容器,支持随机访问,类似c++中的std::vector.
data = list()
data = [] #两种初始化方法
#set/dict, 无序哈希表,不是RB tree,但在python3中遍历顺序与插入顺序相同。
data = {} #{}默认带key,即dict
data = dict()
data = set()
#tuple, 不可改变的list
data = ()
data = tuple()
class
class MyBaseClass: # 类命名一般使用驼峰
def __init__(self): # 初始化函数,self是约定俗成的,不是强制的
self.name = "name" # 在这里增加数据属性,也可以在外部添加
self._counter = 0 # 私有变量一般使用_开头,外部也可以强制访问
def print_name(self): # 方法属性命名一般使用下划线开头
print(self.name, "this is the ", self._counter, "time")
self._counter += 1
class MyDerivedClass(MyBaseClass):
pass
if __name__ == "__main__":
base = MyBaseClass()
base2 = base
derived = MyDerivedClass()
print(issubclass(MyDerivedClass,MyBaseClass)) # issubclass 只是用来衡量两个类对象之间的关系。
print(isinstance(base,MyBaseClass)) # isinstance 用来衡量类对象与实例对象之间的关系。
print(type(base))
print(base.__class__) # 显示object的type/类
print(type(type(base))) # type 是元类
base.print_name()
'''
print_name是一个function object,是MyBaseClass的一个属性,base.print_name会调用`_get_`生成一个临时的boudingd method方法。然后再调用
'''
with
with b as a:
code
等价流程
- a = b.enter
- code
- b.exit
as a是一个option,不是必须的
异常处理
- try 模块中通过raise抛出异常
- {except else(可选)}处理异常情况 or 不处理
- finally(可选) 执行相关代码
- 如果异常没有处理,则继续向上传送异常。
读取可变长度参数
def print_two(*args):
arg1, arg2 = args
print(f"arg1: {arg1}, arg2: {arg2}")
numpy
numpy 中matrix是array的一个子类,是严格意义上的二维矩阵,区别是*在matrix是矩阵乘法,而array是代表对应位置的元素相乘。
| 叉乘(标准) | 点乘(逐元素) | |
|---|---|---|
| array | dot @ | multiply * |
| matrix | dot @ * | multiply |
@新版本推荐使用这个符号来表示矩阵的乘法
numpy 会自动把列向量转成行向量, 转置操作对行向量无效,需要reshape。
np.array([1,2,3])//这是一个数组(行向量),shape为(3,),无法执行转置T,可以reshapenp.array([[1,2,3]])//这是一个矩阵,shape为(1*3)
产生随机数 np.random.rand(50)*100
产生顺序值 np.arange(3,7,2)
将二维变成1维 x.flatten()
里面的索引方式都是先行后列的,创建shape的时候也是如此。
dataframe
- dataframe 是一列列series对象(numpy的增强版)的集合.
- 列读取
df['time']//取出其中的一列,取出的是series对象,这里不能用数字/index,需要stringdf[['time']]//取出其中的一列,取出的是一个data frame 对象, 因为['time'],实际上是一个list.
- 行读取
df.iloc[0]/基于row number,输入行号,不是索引值,这里返回同样是一个series对象df.iloc[[0]]//取出的就是一个dataframe对象df.loc["john"]//基于index的具体内容
注意,
[]不一定完全是按照列读取,如果使用df[1:3],是按照行去读取,这里容易出错。
Ref: pandas.pydata.org/pandas-docs…
numpy、series、dataframe的区别
- series是带索引的增强版numpy,其索引可以是任意类型的数据,支持分区提取,例如data['c':'f']
在索引的时候,中括号内的整数其实指的是索引数组中的实际值,而不是位置值,如果,我们按照位置来取值的话,反而会出错。例如a[0]
- dataframe相同索引的Series对象排列,就形成了DataFrame。
constants, variables, operations in tensorflow
# first, create a TensorFlow constant
const = tf.constant(2.0, name="const")
# create TensorFlow variables
b = tf.Variable(2.0, name='b')
c = tf.Variable(1.0, name='c')
# now create some operations
d = tf.add(b, c, name='d')
e = tf.add(c, const, name='e')
a = tf.multiply(d, e, name='a')
# setup the variable initialisation
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
# initialise the variables
sess.run(init_op)
# compute the output of the graph
a_out = sess.run(a)
print("Variable a is {}".format(a_out))
print("Variable a is {}".format(const))
- as the Python code runs through these commands, the variables haven’t actually been declared as they would have been if you just had a standard Python declaration (i.e. b = 2.0). Instead, all the constants, variables, operations and the computational graph are only created when the initialisation commands are run.
d e fis not a variable but an operation
参数传递
所有的都是引用传递,但是不可变对象重新赋值的时候,会产生一个新对象。
- 可变对象(比如字典或者列表)
- 不可变对象(比如数字、字符或者元组)
对象的几种移除方法差别
- remove 移除对应value的元素
- pop 移除对应index的元素,并且返回改对象
- del 移除对应index的元素
assert用法
#if condition returns False, AssertionError is raised:
assert x == "goodbye", "x should be 'hello'"
判断相等
==判断两个对象是否相等is判断两个对象是否为同一个对象
Iterator
常用以下函数
iter()可以返回第一个元素的迭代器next()跳到下一个元素,但是返回当前元素filter()函数返回指向所有合格的元素的迭代器
Generator
Generator 是Iterator的子类,print(issubclass(Generator,Iterator))。通过yield关键字创建,主要有一下两种方式
# way 1
num_generator = (x*2 for x in range(1,3))
# 不能使用中括号`num_list = [x*2 for x in range(1,3)]`,否则就变成了list
# way2
def firstn(n):
num = 0
while num < n:
yield num # 下一次进入从这里执行。
num += 1
Decorator
装饰器就是给函数增加前置或者后置的操作,内部是执行装饰器函数,然后把被装饰的对象传入。
import time
def decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
func()
end_time = time.time()
print(end_time - start_time)
return wrapper
@decorator
def func():
time.sleep(0.8)
func() # 函数调用# 输出:0.800644397735595
# 执行func(),其实是在执行 decorator(func)
类装饰器与普通装饰器也类似,__call__实际上类似重载了()运算符
class Decorator(object):
def __init__(self, f):
self.f = f
def __call__(self):
print("decorator start")
self.f()
print("decorator end")
@decorator
def func():
pass
p = Decorator(func) # p是类Decorator的一个实例
p() # 实现了__call__()方法后,p可以被调用
Descriptor
Definition:一种特殊的class,如果一个Class有__get__,__set__,__delete__方法,那么这个Class就是一个Descriptor.
- 当外界access(get,set,delete)这个变量时,就会自动调用相应的函数
- Descriptors only work when used as class variables. When put in instances, they have no effect.
- 所有的function都包含
__get__, 都是descriptor, 准确点是non-data descriptor. - 等同代码
f.xwould causetype(f).__dict__['x'].__get__to be called, andf.x = 3would calltype(f).__dict__['x'].__set__(3).
class Dog:
def __get__(self, obj, objtype):
return "call the get method"
class Cat:
pass
class House:
d = Dog()
c = Cat()
print(type(House.d)) # House.d返回是一个str 对象
print(type(House.c)) # House.c返回是一个cat对象
print(type(House().d))
## 使用举例,用作数据转换
class Number:
def __init__(self):self.value=0
def getx(self):
return -self.value;
neg_value=property(getx,None,"what")
n = Number();
n.value =10
print(n.neg_value)
__dict__
__dict__ 可以打印出对象所有的成员,及其对应的值。
print(House.__dict__) # 两者等价
print(vars(House))
访问属性的查找顺序(有待纠正)
- descriptor
- instance.dict
- class.dict
class attribute 是不出现在 instance attribute 里面的。
实例方法与类方法同名
实例方法会被覆盖
class Bar(object):
def fun(self):
print("instance method")
@classmethod
def fun(cls):
print("class method")
a = Bar()
a.fun()
Bar.fun()
两者都会print class method
访问attribute/method原理
Object访问attribute以及调用instance method都是线调用__getattr__函数,return一个对象。这个对象如果callable, 就成了函数
例外情况:如果这个attribute已经初始化,就不会调用
getattr函数。__getattribute__不管变量是否已经存在,都会调用。
__get__ 与 __getattr__ 与 __getattribute__ 区别
- 查找lookuptable
- 找到,执行(默认/override)
__get__函数 - 找不到,执行(默认/override)
__getattr__函数
__getattribute__将会屏蔽上述所有操作。
设置attribute
对某个属性进行赋值时,调用__setattr__函数
del 某个属性,其实也是调用函数
@name.deleter
def name(self):
self._name = 'Number Six'
__call__
python 的__call__属性就是重载call函数
class Test:
def __call__(self,a,b):
print(a+b)
t = Test()
t(1,2)
object() is shorthand for object.call()
包管理
导入当前目录的文件
test.py
def add(x,y):
return x + y
main.py
import test
test.add(1,2)
导入package
在一个文件夹下如果有__init__.py的文件, import这个package的时候会自动执行。
创建一个pac的文件夹,包含__init__.py与test.py文件
init.py
import pac.test
add = pac.test.add
test.py
def add(x,y):
return x + y
main.py
import pac as p
p.add(1,2)
__init__.py这个文件不是必须的,如果有的话,在import的时候,会自动执行某些初始化函数。import导入的是module,不能直接导入package,如果有import package,本质上是运行的__init__.py的函数。stackoverflow.com/questions/3…from package import module可以进行部分的导入,与import package.module同样可以导入外部模块,区别是前者使用的时候可以module.fun(),后者需要一直加package.module.fun(),