Python笔记

117 阅读9分钟

1. 数据类型与变量

  • 整数

    1. py可以处理任意大小整数,负数。例如1 -1 -8080 0

    2. 也可以使用十六进制 -xff00 -xa4b1

    3. 对于很长的数 100000000000, py支持_来分割(16进制也支持),等效于1000_0000_0000

  • 浮点数

    1. 1.23 -9.01 1.23e9==1.23*10的9次方
  • 字符串

    str1 = '单引号的字符串'
    str2 = '字符串包含引号可以转义\',类似这样'
    srt3 = "双引号的字符串,与单引号工作机制完全翔通"
    str4 = '''
    三引号 可以来
    指定
    多行的
    字符串
    '''
    str5 = """
    这样的三引号
    也是'啊啊啊' "dddd"
    可以的
    """
    str6 = '这里其实是一行,但是为了美观  \
    可以写成2行,但是显示依旧一行'
    

    转义字符 \ 1. 换行\n 2. 制表符\t 3. \本身\\ 4. ...

    py支持 r'' 默认不转义 print('你好\\') 输出 你好\ print(r'你好\\') 输出 你好\\

  • 布尔值 True 和 False

2.运算

# 乘方 2的4次方
i1 = 2 ** 4
print(i1)

# 除 5.333333333333333
i2 = 16 / 3
# 整除 5
i3 = 16 // 3
# 取余 1
i4 = 16 % 3
print(i2, i3, i4)

# 左移 2=》10 -> 1000 得8
i5 = 2 << 2
# 右移 11=》1011 -> 101 得5
i6 = 11 >> 1
print(i5, i6)

# 位与 101 & 011 = 001 = 1
i7 = 5 & 3
# 位或 101 | 011 = 111 = 7
i8 = 5 | 3
# 位异或 101 ^ 011 = 110 = 6
i9 = 5 ^ 3
# 取反 x 按位取反结果是 -(x+1)
i10 = ~ 5

3. 格式化

name = '张三'
age = 19
score = 19.7653
print("他的名字是:", name)
# 这里不能像java一样,直接 整型拼接字符串,需要str 来转化
print("他的名字是:" + name + ",年龄是:" + str(age) + "")
print("他的名字是:{0},年龄是:{1}".format(name, age))
# {}里的数字 是一个可选的,以下方式也可以
print("他的名字是:{},年龄是:{}".format(name, age))
print("他的名字是:{name},年龄是:{age}".format(name='张三', age=19))
# 使用f-string
print(f"他的名字是:{name},年龄是:{age}")
# 输出19.77
print(f"他的分数是是:{score:.2f}")
#  %d-整数。%f-浮点。%s-字符串。%x-十六进制数,通过 %% 来表示一个 %
print("他获胜比例是:%d %%" % 7)
# 如果你不知道用什么,%s,它会把任何数据类型转换为字符串
print("他获胜比例是:%s %%" % 7)

4. 集合

  • 列表-list
list1 = [1, 2, 3, 4, 5]
# 列表推导 [4,6,8,10]
list2 = [2 * i for i in list1 if i > 1]

mylist = ['apple', 'mongo', 'banana', 'zhaaa']
# py 从0开始计数。0=第一个元素。-1=倒数第一个元素
print('第一个元素 0:', mylist[0])
#print('IndexError 数组越界:', mylist[4])
print('倒数第1个元素 :', mylist[-1])
print('倒数第2个元素 :', mylist[-2])
print('mylist 0-2:', mylist[0:2])
# 追加元素 ['apple', 'mongo', 'banana', 'zhaaa', 'kkk']
mylist.append('kkk')
# 新增(插入)一个元素 ['apple','bet apple and mongo', 'mongo', 'banana', 'zhaaa', 'kkk']
mylist.insert(1, 'bet apple and mongo')
# 删除指定元素 ['bet apple and mongo', 'mongo', 'banana', 'zhaaa']
mylist.pop(0)
# 也可以赋值一个数据类型不一样的元素, [True, 'mongo', 'banana', 'zhaaa']
mylist[0] = True
# 删除最后一个元素 ['mongo', 'banana', 'zhaaa']
mylist.pop()

# 删除第0个元素
del mylist[0]
# 排序
mylist.sort()

# 切片
L = list(range(100))
t = (1, 3, 5, 7, 9)
print("输出前10个:", L[:10])
print("输出后10个:", L[-10:])
print("取11-20(前包,后不包):", L[10:20])
print("按步数5 ,间隔取:", L[::5])
print("元组也可以 ,:", t[::2])
print("字符串也可以看成一种list ,[BC]:", "ABCDEFG"[1:3])
print("字符串也可以看成一种list ,[ACEG]:", "ABCDEFG"[::2])

  • 元组-

另一种有序列表叫元组:tuple。tuple和list非常类似,但是tuple一旦初始化就不能修改

# 没有元素
zero_tuple = ()
# 一个元素的元组(需要逗号)
one_tuple = ('111',)
zoo = ('bbb', 'ccc', 'aaa')
# ('ddd', 'eee', ('bbb', 'ccc', 'aaa'))
new_zoo = ('ddd', 'eee', zoo)

# 使用元组 可以让函数 返回多个值
def mutiReturn():
    zoo = (1, 2, 3)
    return 2, "张三", zoo

x, y, z = mutiReturn()
print("测试单函数多返回:", x, y, z)

# 同样的,使用元组 可以用来快速交换值
a = 1
b = 2
# a = 2, b =1 
a, b = b, a
  • 字典-dict

py的字典,可以理解为java中的Map

mydict = {
    'zhangsan': '我是张三',
    'lisi': 5,
    'wangwu': 'zoo'
}
print('输出key=wangwu的值:', mydict['wangwu'])
del mydict['lisi']
mydict['liubei'] = '我是刘备'
print(len(mydict))
# 可以通过in 来判断是否存在key
if 'liubei' in mydict:
    for k, v in mydict.items():
        print(k, v)
# 也可以通过 get 来判断,不存在 返回None
print("不存在的值:", mydict.get("noneKey"))
print("不存在的值,也可以指定一个默认值,当不存在的时候:", mydict.get("noneKey", "noneValue"))
  • 无重复元素的集合-set
set1 = {1, 2, 3, 4}
set2 = set1.copy()
set2.add(6)
# 还是 {1, 2, 3, 4}
print(set1)
set2.remove(1)
# 并集 {2, 3, 4}
print(set2 & set1)
# 交集 {1, 2, 3, 4, 6}
print(set2 | set1)
  • 迭代
# =============迭代====================
L1 = list(range(10))
# 0 1 2 3 4 5 6 7 8 9
for i in L1:
    print(i, end=" ")

# Python内置的enumerate函数可以把一个list变成索引-元素对
for i, value in enumerate(L1[::2]):
    # 带下标的遍历
    print(f"下标i={i},value={value}")

# 字典
mydict = {
    'zhangsan': '我是张三',
    'lisi': 5,
    'wangwu': 'zoo'
}
# dict默认遍历key: zhangsan lisi wangwu
for i in mydict:
    print(i, end=" ")
# dict遍历value
for i in mydict.values():
    print(i, end=" ")
# 同时遍历
for k, v in mydict.items():
    print(k, v, end="-")

# 也可以迭代字符串
for i in "ACB":
    print(i)

# 可以通过  collections.abc模块的Iterable类型判断 是否可迭代
print(isinstance("ADC", Iterable), isinstance(mydict, Iterable), isinstance(12, Iterable))
  • 列表推导和生成器
list1 = [1, 2, 3, 4, 5]
# 列表推导 [4,6,8,10]
list2 = [2 * i for i in list1 if i > 1]
# 生成器
g = (2 * i for i in list1 if i > 1)

# 生成器与列表推导的区别,在于 [] 和(), g是一个generator
# 也就是说generator保存的是算法,每次调用就计算出下一个值,没有更多元素的时候,抛出 StopIteration
print(next(g))
print(next(g))


# 斐波那契数列
# 这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator函数,调用一个generator函数将返回一个generator
# 这里,最难理解的就是generator函数和普通函数的执行流程不一样。普通函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数
# [在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行]
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'


f = fib(10)
for i in range(10):
    print(next(f))

5.函数

# 定义一个函数, 参数设置默认值后,可以不传
def print_max(a, b=1, c=10):
    # 数据类型检查
    if not isinstance(a, (int, float)):
        print(f"非法的类型a:{a}")
    else:
        print(f"int float类型a:{a}")
    print('print a={},b={},c={}'.format(a, b, c))


print_max(3, c=11)
print_max("dd", c=11)
# 灵活传参
print_max(c=12, a=1)


def mutiReturn():
    x = 1
    y = 2
    z = 3
    return x, y, z


print("函数多个返回值", mutiReturn())


# 定义一个空函数,pass 作为占位符,在其他比如条件语句 也可以使用pass
def nop():
    pass


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


# ['END']
print(add_end())
# ['END','END']
print(add_end())
# ['END','END','END']
print(add_end())


# 为什么会这样? py函数在定义的时候,默认参数L的值就被计算了,也就是[],也就是说L 就是一个变量,他指向 [],每次调用的时候 ,如果改变了L,那下次调用的时候 默认值就变了
# 所以注意一点,默认参数 必须指向不可变对象
# 修改上面的例子
def add_end(L=None):
    if L is None:
        L = []
    L.append('END')
    return L


# 可变参数
def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n
    return sum


print("cacl,计算1+2+3+4 =", calc(1, 2, 3, 4))
list3 = [1, 3, 5, 7]
print("cacl,可以使用*,传入一个列表参数:", calc(*list3))
tuple3 = (1, 3, 5, 7)
print("cacl,可以使用*,传入一个元组:", calc(*tuple3))


# ==================================


def test1(a=5, *numbers, **dict):
    '''
    可变参数 *numbers代表元组or列表,**dict代表字典
    '''
    print(a)
    print("---")
    if 'jack' in dict:
        print("存在jack")
    for a in numbers:
        print(a)
    for key, val in dict.items():
        print(key, val)


test1(10, 1, 2, 3, jack=10, john=20)
extra = {"jack": 10, "john": 20}
# 也可以使用**,传入一个字典
test1(20, 3, 5, 6, **extra)


# =================1=================
# 如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:
# 和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。
def person(name, age, *, city, job):
    print(name, age, city, job)


person("zhangsan", 18, city="zhejiang", job="ddd")
extra2 = {"city": "杭州", "job": "enginner"}
person("zhangsan", 18, **extra2)


# 如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:
def person2(name, age, *args, city, job):
    print(f"name={name},age={age},args={args},city={city},job={job}")

person2("刘备",55,1,2,3,city="四川",job="222")


# 参数组合
# 在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
# 但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)

def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)

6. 面向对象编程(1)

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

    def say(self):
        print("my name is", self.name)


# 继承
class Student(Person):

    # 类的静态变量,属于类,不属于某个实例
    school = '家里蹲大学'

    def __init__(self, name, score, age):
        super().__init__(name)
        self.score = score
        self.age = age
        # 私有变量 不能被外部直接访问,要想访问 可以写一个 set get方法
        self.__privateField = name + "="

    # 与普通函数相比,类函数的第一个参数永远是 self
    def print(self):
        print(f"name={self.name},score={self.score}")
        self.__myPrivateFunc()

    # 双下划线开头的 __F 这样的函数或者变量是 private的,不应该被直接引用
    def __myPrivateFunc(self):
        if self.age >= 18:
            print("成年人")
        else:
            print("未成年")

    def get__privateField(self):
        return self.__privateField

    def set__privateField(self, value):
        self.__privateField = value

    def say(self):
        print("我 学生,打钱", self.name)

    def __str__(self):
        # 类似java的toString方法
        return f"我是 str方法。。name={self.name},score={self.score}"

    def __len__(self):
        # 相当于调用 len(o) == o.__len__()
        return 10

s1 = Student("张三", 99, 20)
s2 = Student("李斯", 88, 11)
p = Person("person.")
s1.print()
# 可以自由地给一个实例变量绑定属性(但仅仅是给s1这个实例绑定了变量)
s1.address = "浙江"
print(s1.address)
# 相当于调用 s1.__str__()
print(str(s1))

# my name is 张三, Student 类,继承了Person类
s1.say()
# 以下会报错:AttributeError: 'Student' object has no attribute 'address'
# print(s2.address)

# 判断一个实例 是否是某个类型。以下均输出True
print(isinstance(s1, Person))
print(isinstance(s1, Student))
# type函数返回class类型
# <class '__main__.Student'>, <class '__main__.Person'> ,<class 'str'>, <class 'int'>, <class 'builtin_function_or_method'>
print(type(s1) ,type(p), type("abc"), type(12), type(abs))
# ['_Student__myPrivateFunc', '_Student__privateField', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__',
# '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__',
# '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__',
# '__weakref__', 'address', 'age', 'get__privateField', 'name', 'print', 'say', 'score', 'set__privateField']
# 通过dir 可以拿到一个对象的所有属性和方法,返回一个list
print( dir(s1))


s1.set__privateField("ddddd")
print(s1.get__privateField())

# 操作静态变量,由于实例属性优先级比类属性高,因此,它会屏蔽掉类的name属性,此时的s1.school是实例变量,非静态变量
s1.school = '清华'
Student.school = '清华2'
print(f"s1.school={s1.school},s2.school={s2.school}")

# 配合getattr()、setattr()以及hasattr(),我们可以直接操作一个对象的状态
print("存在属性name:", hasattr(s1, "name"))
print("不存在属性name222:", hasattr(s1, "name222"))
print("无法获取私有属性__privateField:", hasattr(s1, "__privateField"))

# 多态的简单示例
def say(p):
    p.say()


# 我 学生,打钱 张三
say(s1)
# my name is person.
say(p)

6. 面向对象编程(2)

  • 操作类的属性与方法
from types import MethodType


class Student:
    pass


s1 = Student()
s2 = Student()
# 给实例绑定一个属性
s1.name = "张三"
print(s1.name)


def setName(self, name):
    self.name = name


# 给类绑定一个方法(注意 这里只作用于 s1 这单个对象,对其他对象无作用)
s1.setName = MethodType(setName, s1)
s1.setName("李斯")
print(s1.name)


def setAge(self, age):
    self.age = age


# 若需要给所有实例绑定方法,需要给class绑定
Student.setAge = setAge
s1.setAge(11)
s2.setAge(15)
print(s2.age, s1.age)


# 可以使用 __slots__ ,来限制class实例能添加的对象
# [[[当然 要注意的是,__slots__ 只对当前类有效,子类,可以任意添加]]]
class Worker:
    __slots__ = ('address', 'phone')


w1 = Worker()
w1.address = '浙江'
w1.phone = 110
# 以下会报错 AttributeError: 'Worker' object has no attribute 'name'
# w1.name = 'mike'
  • 定制类
class Fib:
    def __init__(self):
        self.a = 0
        self.b = 1

    def __str__(self):
        return f"我__str__,打钱"

    # 如果希望一个类能被迭代,需要实现 __iter__
    # 然后,Python的for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,
    # 直到遇到StopIteration错误时退出循环
    def __iter__(self):
        return self  # 实例本身就是迭代对象,故返回自己

    def __next__(self):
        self.a, self.b = self.b, self.a + self.b
        if (self.a > 1000):
            raise StopIteration()
        return self.a

    # 虽然__iter__能实现迭代(for循环),但是像 list随机访问,list[1],还是不行
    # __getitem__ 相当于对对象 实现了 列表的功能,但是列表支持 切片 与 step,
    # 以下方法 仅仅实现了随机访问,要正确实现 __getitem__ ,还需要很多工作
    def __getitem__(self, item):
        a, b = 1, 1
        for i in range(item):
            a, b = b, a + b
        return a


s = Fib()
print(s)
print(str(s))

print("fib数列第4项", s[3])


# 遍历fib数列
# for i in s:
#     print(i)

# ====================================

class Student:

    def __init__(self, name, age):
        self.age = age
        self.name = name

    # __getattr__,可以动态的调用不存在的属性,来返回特定的值
    # 当调用不存在的属性时,比如score,Python解释器会试图调用__getattr__(self, 'score')来尝试获得属性,这样,我们就有机会返回score的值
    def __getattr__(self, item):
        if item == 'score':
            return 99
        elif item == 'address':
            # 也可以返回一个函数
            return self.defaultAddress
        elif item == 'gender':
            return lambda: 'boy'

    def defaultAddress(self):
        return "上海"

    # 使用__call__,可以使 实例 调用自己
    def __call__(self, *args, **kwargs):
        print("自己调用自己", *args)

    # 当对象比较 使用< 的时候,会调用此方法
    # 应该可以简单理解为 运算符重载
    def __lt__(self, other):
        return self.age < other.age

    # 当对象比较 使用> 的时候,会调用此方法
    # 其他的 类似
    # object.__le__(self, other)
    # object.__eq__(self, other)
    # object.__ne__(self, other)
    # object.__ge__(self, other)
    def __gt__(self, other):
        return self.age > other.age


s1 = Student('张三', 18)
s2 = Student('秦始皇', 55)
print("比较两个对象", s1 < s2)

# 注意, address 和 gender 都是函数
print(f"name={s1.name}, phone={s1.phone}, score={s1.score},address={s1.address()},gender={s1.gender()}")

# 自己调用自己,但是这样有一定的混淆,不知道s1 是对象 还是函数
s1()
# Py通过callable(), 可以判断一个对象是否是可调用对象
print("s1 可调用", callable(s1))
print("列表不可调用", callable([1, 2, 3]))
  • 枚举与元类
from enum import Enum

# 定义一个枚举
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
for name, member in Month.__members__.items():
    # value 属性是自动给枚举成年的int常量,默认从1开始
    print(name, member.value)


# 也可以自定义其类型,比如 元组
class WeekDay(Enum):
    Sun = (0, "周日")
    Mon = (1, "周1")
    Tue = (2, "周2")
    Wed = (3, "周3")
    Thu = (4, "周4")
    Fri = (5, "周5")
    Sat = (6, "周6")


print(WeekDay.Wed.value[1])


class Cat:
    def __init__(self):
        pass


# 使用type()
print("Cat是一个类,ta的类型是 type,输出[<class 'type'>]", type(Cat))
print("cat实例 ,他的类型就是 Cat,输出[<class '__main__.Cat'>]", type(Cat()))


# type() 可以输出一个对象的类型,也可以创建一个新的类型,
# 比如 创建一个Dog类
def func(self):
    print("my func。。。")


def func2(self):
    print("my func2。。。")


# type接受三个参数
# 1. class的名称
# 2. 元组,父类对象,默认继承object
# 3. dict,方法绑定
Dog = type("Dog", (object,), dict(myMethod=func, myMethod2=func2))
d = Dog()
d.myMethod()
d.myMethod2()


# 使用metaclass ,除了type()外,py还支持使用metaclass 来创建类
# 换句话说,可以理解为 类是metaclass创建出来的”实例“
# 按照一般习惯,metaclass类以metaclass结尾, metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
    # __new__ 参数解释
    # 1. cls = 当前准备创建的类的对象
    # 2. name = 类的名字
    # 3. bases = 类继承的父类集合
    # 4. 类的方法集合
    def __new__(cls, name, bases, attrs):
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)


# 传入关键字 metaclass后,它指示py解释器,在创建MyList时候,通过 ListMetaclass.__new__ 来创建,在此,我们给它新增了一个 add方法
class MyList(list, metaclass=ListMetaclass):
    pass


l1 = MyList()
l1.add(1)
l1.add(2)
print("输出[1,2], 而普通list没有add方法", l1)