python个人笔记(一)基础语法

最近自学一下python,

边看边做一下笔记,主要以代码为主。

理论和描述请移步:

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000

 

语法

List&tuple

"""
1、cmp(list1, list2):比较两个列表的元素
2、len(list):列表元素个数
3、max(list):返回列表元素最大值
4、min(list):返回列表元素最小值
5、list(seq):将元组转换为列表
列表操作包含以下方法:
1、list.append(obj):在列表末尾添加新的对象
2、list.count(obj):统计某个元素在列表中出现的次数
3、list.extend(seq):在列表末尾一次性追加另一个序列中的多个值(用新列表扩展原来的列表)
4、list.index(obj):从列表中找出某个值第一个匹配项的索引位置
5、list.insert(index, obj):将对象插入列表
6、list.pop(obj=list[-1]):移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
7、list.remove(obj):移除列表中某个值的第一个匹配项
8、list.reverse():反向列表中元素
9、list.sort([func]):对原列表进行排序
"""
arr = ['a', 'b', 'c']
arr.append('d')  # 添加元素
print('取最后一个元素:' + arr[-1])
print('删除并取出某元素:' + arr.pop(0))
print('删除末尾元素:' + arr.pop())

arr = ['a', 'b', 'c']
# 反向排序
arr.reverse()

# 反向排序
arr.sort(reverse=True)
for obj in arr:
    print(obj)

#临时排序
arr2=sorted(arr)

#列表解析
arr = [val+1 for val in range(1,11)]
print(arr)


## 切片
arr = ['a', 'b', 'c']
print(arr[0:1])
print(arr[1:])
print(arr[:2])

# 字符串同样可以切片
str = 'abc'
print(str[0:1])


# 复制列表,如果arr=arr2,那么arr和arr2的id是相同的
arr = ['a', 'b', 'c']
arr2 = arr[:]

print(id(arr))
print(id(arr2))

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改,它也没有append(),insert()这样的方法。其他获取元素的方法和list是一样的,你可以正常地使用classmates[0]classmates[-1],但不能赋值成另外的元素。

不可变的tuple有什么意义?因为tuple不可变,所以代码更安全。如果可能,能用tuple代替list就尽量用tuple。

 

t =('a','b','a')

dist&set

dist = {}
dist['a'] = 1
dist['b'] = 2

# print(dist['c'])#不存在key会报错
print(dist.get('c'))  # 不存在key返回None
print(dist.get('c', '3'))  # 不存在key返回指定value

# 判断key是否存在
print('a' in dist)
dist.pop('a')  # 删除

和java的map差不多,另请务必注意,dict内部存放的顺序和key放入的顺序是没有关系的。

和list比较,dict有以下几个特点:

  1. 查找和插入的速度极快,不会随着key的增加而变慢;
  2. 需要占用大量的内存,内存浪费多。

而list相反:

  1. 查找和插入的时间随着元素的增加而增加;
  2. 占用空间小,浪费内存很少。

所以,dict是用空间来换取时间的一种方法。

set

set和dict类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在set中,没有重复的key。

s = {1, 2, 3, 3}
s.add(3)  # 重复插入无效
s.remove(2)
print(s)

循环

#用得最多的两个循环,支持List dist set tuple

arr = ['a', 'b', 'c']
for a in arr:
    print(a)

for i, a in enumerate(arr):
    print(i,a)

#遍历dist,key val方式
dist = {}
dist['a'] = 1
dist['b'] = 2

for key,val in dist.items():
    print(key,val)

 

定义函数

固定参数

def power(x):
    return x * x

默认参数

#必选参数在前,默认参数在后,否则Python的解释器会报错
def power(a, b=1):
    return a * b

print(power(2,2))
print(power(2))

另外值得注意的是,默认参数会有一个坑:

def add_end(L=[]):
    L.append('END')
    return L


# 结果正常:['END']
print(add_end())

# 结果异常:['END', 'END']
print(add_end())

很多初学者很疑惑,默认参数是[],但是函数似乎每次都“记住了”上次添加了END后的list。

原因解释如下:

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

定义默认参数要牢记一点:默认参数必须指向不变对象!

不可变(immutable):int、字符串(string)、float、(数值型number)、元组(tuple) 、None也算

可变(mutable):字典型(dictionary)、列表型(list)

正确写法:

def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L

 

可变参数

"""
在函数内部,参数numbers接收到的是一个tuple,
因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:
"""
def test(*numbers):
    for num in numbers:
        print(num)


test(1, 2, 3)

#已有List或tuple调用方法
nums = [1, 2, 3]
test(*nums)

 

关键字参数

"""
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。
而关键字参数允许你传入0个或任意个含参数名的参数,
这些关键字参数在函数内部自动组装为一个dict
"""
def person(name, age, **kw):
    print('name:', name, 'age:', age, 'other:', kw)


person('小明', 1, city='广州')


"""
已有dist调用:

**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,
kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
"""
extra = {'city': '广州', 'job': 'java'}
person('小明', 1, **extra)

命名关键字参数

"""
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。
如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
"""


# 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
def person(name, age, *, city, job):
    print(name, age, city, job)


person('Jack', 24, city='Beijing', job='Engineer')
#报错
person('Jack', 24, city='Beijing', other='Engineer')


# 命名关键字参数 也支持默认参数
def person(name, age, *, city='广州', job):
    print(name, age, city, job)

组合参数

在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。

但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

虽然可以组合多达5种参数,但不要同时使用太多的组合,否则函数接口的可理解性很差。

def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

 

 

异常与测试

try catch

try:
    print('try...')
    r = 10 / int('2')
    print('result:', r)
except ValueError as e:
    print('ValueError:', e)
except ZeroDivisionError as e:
    print('ZeroDivisionError:', e)
else:
    print('no error!')
finally:
    print('finally...')
print('END')

#PS:
1.Python的错误其实也是class,所有的错误类型都继承自BaseException
2.raise和java中的throw是一样的 raise ValueError('invalid value: %s' % s)

单元测试

import unittest


"""
特别注意:
1.文件名不能为 test.py
2.文件名带有test字样 IDE(pyCharm)才会识别到这是一个测试类,右击下面的测试方法运行才会单独运行该方法
"""
class TestDict(unittest.TestCase):
    def setUp(self):
        print('单元测试前执行')

    def tearDown(self):
        print('单元测试后执行')

    # 以test开头的方法就是测试方法,不以test开头的方法不被认为是测试方法,测试的时候不会被执行。
    def test1(self):
        # IDE 右键运行,单元测试该方法
        print('test1')

    def test_2(self):
        print('test2')


if __name__ == '__main__':
    # 运行所有单元测试
    unittest.main()

 

高级函数

map

map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。

"""
利用map()函数,把用户输入的不规范的英文名字,
变为首字母大写,其他小写的规范名字。
输入:['adam', 'LISA', 'barT'],输出:['Adam', 'Lisa', 'Bart']:
"""
def normalize(name):
    return name.lower().title()


L1 = ['adam', 'LISA', 'barT']
L2 = list(map(normalize, L1))
print(L2)

filter

Python内建的filter()函数用于过滤序列。

map()类似,filter()也接收一个函数和一个序列。和map()不同的是,filter()把传入的函数依次作用于每个元素,然后根据返回值是True还是False决定保留还是丢弃该元素。

例如,在一个list中,删掉偶数,只保留奇数,可以这么写:

def is_odd(n):
    return n % 2 == 1

list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
# 结果: [1, 5, 9, 15]

lambda

#将刚刚map的例子改成使用lambda


L1 = ['adam', 'LISA', 'barT']
L2 = list(map(lambda name: name.lower().title(), L1))
print(L2)

 

swith

python没有swith函数,但可以通过以下方式实现

swich = {
    1: lambda x: x + 1,
    2: lambda x: x + 2,
    3: lambda x: x + 3,
}
print(swich[1](1))
print(swich[2](1))
print(swich[3](1))

#不传参可以这样写
swich = {
    1: lambda: 'case1',
    2: lambda: 'case2',
    3: lambda: 'case3',
}
print(swich[1]())
print(swich[2]())
print(swich[3]())

 

sorted

import datetime

#简单的排序
sorted([36, 5, -12, 9, -21])
#反序
sorted([36, 5, -12, 9, -21],reverse=True)



#时间排序的例子

result_data = []
result_data.append({
    'id': 2,
    'create_time': '2012-10-8 11:09:22',
})
result_data.append({
    'id': 3,
    'create_time': '2011-10-10 11:09:22',
})
result_data.append({
    'id': 1,
    'create_time': '2013-10-1 11:09:22',
})


def date_sort(data_str):
    a_datetime = datetime.datetime.strptime(data_str, '%Y-%m-%d %H:%M:%S')
    return a_datetime.timestamp()

print(sorted(result_data, key=lambda item: date_sort(item['create_time'])))

 

decorator(修饰器)

和java的AOP有点类似吧

比如在不修改已有函数的情况下,给这个函数执行前后打日志:

import functools


def log(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        print('前置:', func.__name__)
        result = func(*args, **kw)
        print('后置')
        return result

    return wrapper


@log
def now():
    print('--now函数 逻辑---')
    return '2017-01-01'


print('现在时间:' + now())

# @functools.wraps(func)的作用:
# 因为返回的那个wrapper()函数名字就是'wrapper',
# 所以,需要把原始函数的__name__等属性复制到wrapper()函数中,否则,有些依赖函数签名的代码执行就会出错。
# 加了这句代码:print(now.__name__) 结果 now()
# 没加这句代码:print(now.__name__) 结果 wrapper()

@log放到now()函数的定义处,相当于执行了语句:

now = log(now)

 

如果decorator本身需要传入参数,那就需要编写一个返回decorator的高阶函数,写出来会更复杂。比如,要自定义log的文本

def logger(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print('%s %s():' % (text, func.__name__))
            return func(*args, **kw)

        return wrapper

    return decorator


# 相当于执行了 now = logger('DEBUG')(today)
@logger('DEBUG')
def today():
    print('2015-3-25')

我们来剖析上面的语句,首先执行log(execute),返回的是decorator函数,再调用返回的函数,参数是now函数,返回值最终是wrapper函数。

 

 

面向对象

类的创建与继承

class Animal(object):
    # 类属性,类的所有实例,包括子类都可以访问到
    other = '类属性'

    # 类似java的构造函数
    def __init__(self, name, age):
        # pulic 属相
        self.name = name
        # private 属相
        self.__age = age

    def run(self):
        print('Animal is running...')


#继承
class Dog(Animal):
    def call(self):
        print('汪汪汪')

    def run(self):
        print('狗走路')


# test
dog = Dog('旺财', 1)
dog.run()
dog.call()


print(isinstance(dog, Animal))  # true
print(isinstance(dog, Dog))  # true

使用__slots__

如果我们像拓展一个类或实例的属性和方法,可以这么做:

from types import MethodType


class Animal(object):
    pass


a = Animal()

# 已存在的实例绑定一个新属性
a.name = '狗'


# 已存在的实例绑定一个新方法
def run(self):
    print('走路')


a.run = MethodType(run, a)
a.run()

# 给class绑定新方法,其所有实例都可以使用
Animal.run2 = run
a.run2()

 

但是,如果我们想要限制实例的属性怎么办?比如,只允许对实例Animal添加name、age属性。

这时候我们定义类可以使用__slots__ 来达到目的

class Animal(object):
    #只允许拓展name、age属性,否则会报错
    __slots__ = (name, age)

__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

 

使用property

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/3/19 16:52
# @Author  : HeyS1
""" """

"""
@property广泛应用在类的定义中,可以让调用者写出简短的代码,
同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
"""


# 常规写法
class Student1(object):
    def get_score(self):
        return self._score

    def set_score(self, value):
        # 做一些参数验证....
        self._score = value


s1 = Student1()
s1.set_score(100)
print(s1.get_score())


# 简洁写法
class Student2(object):
    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        # 做一些参数验证....
        self._score = value

    @property  # 只定义getter方法,不定义setter方法就是一个只读属性:
    def age(self):
        pass


s2 = Student2()
s2.score = 99  # 这里就直接赋值,实际转化为s.set_score(99)
print(s2.score)


 

枚举

定义常量时,使用枚举类型去定义比普通的声明变量更优

from enum import unique, Enum


@unique  # 此装饰器可以帮助我们检查保证没有重复值
class Const(Enum):
    A = 'a'
    B = 'b'

# 调用:
print(Const.A)
print(Const.A.value)
print(Const('a'))

 

转载于:https://my.oschina.net/yejunxi/blog/1635490

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值