继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

python基础,很详尽!!!(4)

hadeslee
关注TA
已关注
手记 14
粉丝 4305
获赞 7388
-- # OOP和继承: "is - a"的关系
class A(B):
    pass
a = A()
isinstance(a, B)                    # 返回True, A是B的子类 a也是B的一种
# OOP和组合: "has- a"的关系
pass
# OOP和委托: "包装"对象 在Python中委托通常是以"__getattr__"钩子方法实现的, 这个方法会拦截对不存在属性的读取
# 包装类(或者称为代理类)可以使用__getattr__把任意读取转发给被包装的对象
class wrapper:
    def __init__(self, object):
        self.wrapped = object
    def __getattr(self, attrname):
        print('Trace: ', attrname)
        return getattr(self.wrapped, attrname)
# 注:这里使用getattr(X, N)内置函数以变量名字符串N从包装对象X中取出属性 类似于X.__dict__[N]
x = wrapper([1, 2, 3])
x.append(4)                         # 返回 "Trace: append" [1, 2, 3, 4]
x = wrapper({'a':1, 'b':2})
list(x.keys())                      # 返回 "Trace: keys" ['a', 'b']
-- 类的伪私有属性:使用__attr
class C1:
    def __init__(self, name):
        self.__name = name          # 此时类的__name属性为伪私有属性 原理 它会自动变成self._C1__name = name
    def __str__(self):
        return 'self.name = %s' % self.__name
I = C1('tom')
print(I)                            # 返回 self.name = tom
I.__name = 'jeey'                   # 这里无法访问 __name为伪私有属性
I._C1__name = 'jeey'                # 这里可以修改成功 self.name = jeey
-- 类方法是对象:无绑定类方法对象 / 绑定实例方法对象
class Spam:
    def doit(self, message):
        print(message)
    def selfless(message)
        print(message)
obj = Spam()
x = obj.doit                        # 类的绑定方法对象 实例 + 函数
x('hello world')
x = Spam.doit                       # 类的无绑定方法对象 类名 + 函数
x(obj, 'hello world')
x = Spam.selfless                   # 类的无绑定方法是函数 在3.0之前无效
x('hello world')
-- 获取对象信息: 属性和方法
a = MyObject()
dir(a)                              # 使用dir函数
hasattr(a, 'x')                     # 测试是否有x属性或方法 即a.x是否已经存在
setattr(a, 'y', 19)                 # 设置属性或方法 等同于a.y = 19
getattr(a, 'z', 0)                  # 获取属性或方法 如果属性不存在 则返回默认值0
#这里有个小技巧,setattr可以设置一个不能访问到的属性,即只能用getattr获取
setattr(a, "can't touch", 100)      # 这里的属性名带有空格,不能直接访问
getattr(a, "can't touch", 0)        # 但是可以用getattr获取
-- 为类动态绑定属性或方法: MethodType方法
# 一般创建了一个class的实例后, 可以给该实例绑定任何属性和方法, 这就是动态语言的灵活性
class Student(object):
    pass
s = Student()
s.name = 'Michael'                  # 动态给实例绑定一个属性
def set_age(self, age):             # 定义一个函数作为实例方法
    self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s)  # 给实例绑定一个方法 类的其他实例不受此影响
s.set_age(25)                       # 调用实例方法
Student.set_age = MethodType(set_age, Student)    # 为类绑定一个方法 类的所有实例都拥有该方法

"""类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题----类的高级话题"""

-- 多重继承: "混合类", 搜索方式"从下到上 从左到右 广度优先"
class A(B, C):
    pass
-- 类的继承和子类的初始化
# 1.子类定义了__init__方法时,若未显示调用基类__init__方法,python不会帮你调用。
# 2.子类未定义__init__方法时,python会自动帮你调用首个基类的__init__方法,注意是首个。
# 3.子类显示调用基类的初始化函数:
class FooParent(object):
    def __init__(self, a):
        self.parent = 'I\'m the Parent.'
        print('Parent:a=' + str(a))
    def bar(self, message):
        print(message + ' from Parent')
class FooChild(FooParent):
    def __init__(self, a):
        FooParent.__init__(self, a)
        print('Child:a=' + str(a))
    def bar(self, message):
        FooParent.bar(self, message)
        print(message + ' from Child')
fooChild = FooChild(10)
fooChild.bar('HelloWorld')
-- #实例方法 / 静态方法 / 类方法
class Methods:
    def imeth(self, x): print(self, x)      # 实例方法:传入的是实例和数据,操作的是实例的属性
    def smeth(x): print(x)                  # 静态方法:只传入数据 不传入实例,操作的是类的属性而不是实例的属性
    def cmeth(cls, x): print(cls, x)        # 类方法:传入的是类对象和数据
    smeth = staticmethod(smeth)             # 调用内置函数,也可以使用@staticmethod
    cmeth = classmethod(cmeth)              # 调用内置函数,也可以使用@classmethod
obj = Methods()
obj.imeth(1)                                # 实例方法调用 <__main__.Methods object...> 1
Methods.imeth(obj, 2)                       # <__main__.Methods object...> 2
Methods.smeth(3)                            # 静态方法调用 3
obj.smeth(4)                                # 这里可以使用实例进行调用
Methods.cmeth(5)                            # 类方法调用 <class '__main__.Methods'> 5
obj.cmeth(6)                                # <class '__main__.Methods'> 6
-- 函数装饰器:是它后边的函数的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成
    @staticmethod
    def smeth(x): print(x)
# 等同于:
    def smeth(x): print(x)
    smeth = staticmethod(smeth)
# 同理
    @classmethod
    def cmeth(cls, x): print(x)
# 等同于
    def cmeth(cls, x): print(x)
    cmeth = classmethod(cmeth)
-- 类修饰器:是它后边的类的运行时的声明 由@符号以及后边紧跟的"元函数"(metafunction)组成
    def decorator(aClass):.....
    @decorator
    class C:....
# 等同于:
    class C:....
    C = decorator(C)
-- 限制class属性: slots属性
class Student:
    __slots__ = ('name', 'age')             # 限制Student及其实例只能拥有name和age属性
# __slots__属性只对当前类起作用, 对其子类不起作用
# __slots__属性能够节省内存
# __slots__属性可以为列表list,或者元组tuple
-- 类属性高级话题: @property
# 假设定义了一个类:C,该类必须继承自object类,有一私有变量_x
class C(object):
    def __init__(self):
        self.__x = None
# 第一种使用属性的方法
    def getx(self):
        return self.__x
    def setx(self, value):
        self.__x = value
    def delx(self):
        del self.__x
    x = property(getx, setx, delx, '')
# property函数原型为property(fget=None,fset=None,fdel=None,doc=None)
# 使用
c = C()
c.x = 100                         # 自动调用setx方法
y = c.x                           # 自动调用getx方法
del c.x                           # 自动调用delx方法
# 第二种方法使用属性的方法
    @property
    def x(self):
        return self.__x
    @x.setter
    def x(self, value):
       self.__x = value
    @x.deleter
    def x(self):
       del self.__x
# 使用
c = C()
c.x = 100                         # 自动调用setter方法
y = c.x                           # 自动调用x方法
del c.x                           # 自动调用deleter方法
-- 定制类: 重写类的方法
# (1)__str__方法、__repr__方法: 定制类的输出字符串
# (2)__iter__方法、next方法: 定制类的可迭代性
class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1     # 初始化两个计数器a,b
    def __iter__(self):
        return self               # 实例本身就是迭代对象,故返回自己
    def next(self):
        self.a, self.b = self.b, self.a + self.b
        if self.a > 100000:       # 退出循环的条件
            raise StopIteration()
        return self.a             # 返回下一个值
for n in Fib():
    print(n)                      # 使用
# (3)__getitem__方法、__setitem__方法: 定制类的下标操作[] 或者切片操作slice
class Indexer(object):
    def __init__(self):
        self.data = {}
    def __getitem__(self, n):             # 定义getitem方法
        print('getitem:', n)                
        return self.data[n]
    def __setitem__(self, key, value):    # 定义setitem方法
        print('setitem:key = {0}, value = {1}'.format(key, value))
        self.data[key] = value
test = Indexer()
test[0] = 1;   test[3] = '3'              # 调用setitem方法
print(test[0])                            # 调用getitem方法
# (4)__getattr__方法: 定制类的属性操作
class Student(object):
    def __getattr__(self, attr):          # 定义当获取类的属性时的返回值
        if attr=='age':
            return 25                     # 当获取age属性时返回25
    raise AttributeError('object has no attribute: %s' % attr)
    # 注意: 只有当属性不存在时 才会调用该方法 且该方法默认返回None 需要在函数最后引发异常
s = Student()
s.age                                     # s中age属性不存在 故调用__getattr__方法 返回25
# (5)__call__方法: 定制类的'可调用'性
class Student(object):
    def __call__(self):                   # 也可以带参数
        print('Calling......')
s = Student()
s()                                       # s变成了可调用的 也可以带参数
callable(s)                               # 测试s的可调用性 返回True
#    (6)__len__方法:求类的长度
def __len__(self):
    return len(self.data)
-- 动态创建类type()
# 一般创建类 需要在代码中提前定义
    class Hello(object):
        def hello(self, name='world'):
            print('Hello, %s.' % name)
    h = Hello()
    h.hello()                             # Hello, world
    type(Hello)                           # Hello是一个type类型 返回<class 'type'>
    type(h)                               # h是一个Hello类型 返回<class 'Hello'>
# 动态类型语言中 类可以动态创建 type函数可用于创建新类型
    def fn(self, name='world'):           # 先定义函数
        print('Hello, %s.' % name)
    Hello = type('Hello', (object,), dict(hello=fn)) 
    # 创建Hello类 type原型: type(name, bases, dict)
    h = Hello()                           # 此时的h和上边的h一致

"""异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关----异常相关"""

-- #捕获异常:
    try:
    except:                               # 捕获所有的异常 等同于except Exception:
    except name:                          # 捕获指定的异常
    except name, value:                   # 捕获指定的异常和额外的数据(实例)
    except (name1, name2):
    except (name1, name2), value:
    except name4 as X:
    else:                                 # 如果没有发生异常
    finally:                              # 总会执行的部分
# 引发异常: raise子句(raise IndexError)
    raise <instance>                      # raise instance of a class, raise IndexError()
    raise <class>                         # make and raise instance of a class, raise IndexError
    raise                                 # reraise the most recent exception
-- Python3.x中的异常链: raise exception from otherException
except Exception as X:
    raise IndexError('Bad') from X
-- assert子句: assert <test>, <data>
assert x < 0, 'x must be negative'
-- with/as环境管理器:作为常见的try/finally用法模式的替代方案
with expression [as variable], expression [as variable]:
# 例子:
    with open('test.txt') as myfile:
        for line in myfile: print(line)
# 等同于:
    myfile = open('test.txt')
    try:
        for line in myfile: print(line)
    finally:
        myfile.close()
-- 用户自定义异常: class Bad(Exception):.....
"""
Exception超类 / except基类即可捕获到其所有子类
Exception超类有默认的打印消息和状态 当然也可以定制打印显示:
"""
class MyBad(Exception):
    def __str__(self):
        return '定制的打印消息'
try:
    MyBad()
except MyBad as x:
    print(x)
-- 用户定制异常数据
class FormatError(Exception):
    def __init__(self, line ,file):
        self.line = line
        self.file = file
try:
    raise FormatError(42, 'test.py')
except FormatError as X:
    print('Error at ', X.file, X.line)
# 用户定制异常行为(方法):以记录日志为例
class FormatError(Exception):
    logfile = 'formaterror.txt'
    def __init__(self, line ,file):
        self.line = line
        self.file = file
    def logger(self):
        open(self.logfile, 'a').write('Error at ', self.file, self.line)
try:
    raise FormatError(42, 'test.py')
except FormatError as X:
    X.logger()
-- 关于sys.exc_info:允许一个异常处理器获取对最近引发的异常的访问
try:
    ......
except:
    # 此时sys.exc_info()返回一个元组(type, value, traceback)
    # type:正在处理的异常的异常类型
    # value:引发的异常的实例
    # traceback:堆栈信息
-- 异常层次
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
    +-- StopIteration
    +-- ArithmeticError
    +-- AssertionError
    +-- AttributeError
    +-- BufferError
    +-- EOFError
    +-- ImportError
    +-- LookupError
    +-- MemoryError
    +-- NameError
    +-- OSError
    +-- ReferenceError
    +-- RuntimeError
    +-- SyntaxError
    +-- SystemError
    +-- TypeError
    +-- ValueError
    +-- Warning

"""Unicode和字节字符串---Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串----Unicode和字节字符串"""

-- Python的字符串类型
"""Python2.x"""
# 1.str表示8位文本和二进制数据
# 2.unicode表示宽字符Unicode文本
"""Python3.x"""
# 1.str表示Unicode文本(8位或者更宽)
# 2.bytes表示不可变的二进制数据
# 3.bytearray是一种可变的bytes类型
-- 字符编码方法
"""ASCII"""                   # 一个字节,只包含英文字符,0到127,共128个字符,利用函数可以进行字符和数字的相互转换
ord('a')                      # 字符a的ASCII码为97,所以这里返回97
chr(97)                       # 和上边的过程相反,返回字符'a'
"""Latin-1"""                 # 一个字节,包含特殊字符,0到255,共256个字符,相当于对ASCII码的扩展
chr(196)                      # 返回一个特殊字符:Ä
"""Unicode"""                 # 宽字符,一个字符包含多个字节,一般用于亚洲的字符集,比如中文有好几万字
"""UTF-8"""                   # 可变字节数,小于128的字符表示为单个字节,128到0X7FF之间的代码转换为两个字节,0X7FF以上的代码转换为3或4个字节
# 注意:可以看出来,ASCII码是Latin-1和UTF-8的一个子集
# 注意:utf-8是unicode的一种实现方式,unicode、gbk、gb2312是编码字符集
-- 查看Python中的字符串编码名称,查看系统的编码
import encodings
help(encoding)
import sys
sys.platform                  # 'win64'
sys.getdefaultencoding()      # 'utf-8'
sys.getdefaultencoding()      # 返回当前系统平台的编码类型
sys.getsizeof(object)         # 返回object占有的bytes的大小
-- 源文件字符集编码声明: 添加注释来指定想要的编码形式 从而改变默认值 注释必须出现在脚本的第一行或者第二行
"""说明:其实这里只会检查#和coding:utf-8,其余的字符都是为了美观加上的"""
# _*_ coding: utf-8 _*_
# coding = utf-8
-- #编码: 字符串 --> 原始字节 #解码: 原始字节 --> 字符串
-- Python3.x中的字符串应用
s = '...'                     # 构建一个str对象,不可变对象
b = b'...'                    # 构建一个bytes对象,不可变对象
s[0], b[0]                    # 返回('.', 113)
s[1:], b[1:]                  # 返回('..', b'..')
B = B"""
    xxxx
    yyyy
    """
# B = b'\nxxxx\nyyyy\n'
# 编码,将str字符串转化为其raw bytes形式:
    str.encode(encoding = 'utf-8', errors = 'strict')
    bytes(str, encoding)
# 编码例子:
    S = 'egg'
    S.encode()                    # b'egg'
    bytes(S, encoding = 'ascii')  # b'egg'
# 解码,将raw bytes字符串转化为str形式:
    bytes.decode(encoding = 'utf-8', errors = 'strict')
    str(bytes_or_buffer[, encoding[, errors]])
# 解码例子:
    B = b'spam'
    B.decode()                # 'spam'
    str(B)                    # "b'spam'",不带编码的str调用,结果为打印该bytes对象
    str(B, encoding = 'ascii')# 'spam',带编码的str调用,结果为转化该bytes对象
-- Python2.x的编码问题
u = u'汉'
print repr(u)                 # u'\xba\xba'
s = u.encode('UTF-8')
print repr(s)                 # '\xc2\xba\xc2\xba'
u2 = s.decode('UTF-8')
print repr(u2)                # u'\xba\xba'
# 对unicode进行解码是错误的
s2 = u.decode('UTF-8')        # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
# 同样,对str进行编码也是错误的
u2 = s.encode('UTF-8')        # UnicodeDecodeError: 'ascii' codec can't decode byte 0xc2 in position 0: ordinal not in range(128)
-- bytes对象
B = b'abc'
B = bytes('abc', 'ascii')
B = bytes([97, 98, 99])
B = 'abc'.encode()
# bytes对象的方法调用基本和str类型一致 但:B[0]返回的是ASCII码值97, 而不是b'a'
-- #文本文件: 根据Unicode编码来解释文件内容,要么是平台的默认编码,要么是指定的编码类型
# 二进制文件:表示字节值的整数的一个序列 open('bin.txt', 'rb')
-- Unicode文件
s = 'A\xc4B\xe8C'             # s = 'A?BèC'  len(s) = 5
#手动编码
    l = s.encode('latin-1')   # l = b'A\xc4B\xe8C'  len(l) = 5
    u = s.encode('utf-8')     # u = b'A\xc3\x84B\xc3\xa8C'  len(u) = 7
#文件输出编码
    open('latindata', 'w', encoding = 'latin-1').write(s)
    l = open('latindata', 'rb').read()                        # l = b'A\xc4B\xe8C'  len(l) = 5
    open('uft8data', 'w', encoding = 'utf-8').write(s)
    u = open('uft8data', 'rb').read()                         # u = b'A\xc3\x84B\xc3\xa8C'  len(u) = 7
#文件输入编码
    s = open('latindata', 'r', encoding = 'latin-1').read()   # s = 'A?BèC'  len(s) = 5
    s = open('latindata', 'rb').read().decode('latin-1')      # s = 'A?BèC'  len(s) = 5
    s = open('utf8data', 'r', encoding = 'utf-8').read()      # s = 'A?BèC'  len(s) = 5
    s = open('utf8data', 'rb').read().decode('utf-8')         # s = 'A?BèC'  len(s) = 5

"""其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他----其他"""

-- 60个字符解决FizzBuzz:
"""写一个程序, 打印数字1到100, 3的倍数打印“Fizz”来替换这个数, 5的倍数打印“Buzz”, 既是3又是5的倍数的打印“FizzBuzz”"""
for x in range(101):
    print("fizz"[x%3*4::]+"buzz"[x%5*4::] or x)        # 解释:最主要用到列表(字符串)的子表
-- Python实现任意深度的赋值 例如a[0] = 'value1'; a[1][2] = 'value2'; a[3][4][5] = 'value3'
class MyDict(dict):
    def __setitem__(self, key, value):                 # 该函数不做任何改动 这里只是为了输出
        print('setitem:', key, value, self)
        super().__setitem__(key, value)
    def __getitem__(self, item):                       # 主要技巧在该函数
        print('getitem:', item, self)                  # 输出信息
        # 基本思路: a[1][2]赋值时 需要先取出a[1] 然后给a[1]的[2]赋值
        if item not in self:                           # 如果a[1]不存在 则需要新建一个dict 并使得a[1] = dict
            temp = MyDict()                            # 新建的dict: temp
            super().__setitem__(item, temp)            # 赋值a[1] = temp
            return temp                                # 返回temp 使得temp[2] = value有效
        return super().__getitem__(item)               # 如果a[1]存在 则直接返回a[1]
# 例子:
    test = MyDict()
    test[0] = 'test'
    print(test[0])
    test[1][2] = 'test1'
    print(test[1][2])
    test[1][3] = 'test2'
    print(test[1][3])
-- Python中的多维数组
lists = [0] * 3                                        # 扩展list,结果为[0, 0, 0]
lists = [[]] * 3                                       # 多维数组,结果为[[], [], []],但有问题,往下看
lists[0].append(3)                                     # 期望看到的结果[[3], [], []],实际结果[[3], [3], [3]],原因:list*n操作,是浅拷贝,如何避免?往下看
lists = [[] for i in range(3)]                         # 多维数组,结果为[[], [], []]
lists[0].append(3)                                     # 结果为[[3], [], []]
lists[1].append(6)                                     # 结果为[[3], [6], []]
lists[2].append(9)                                     # 结果为[[3], [6], [9]]
lists = [[[] for j in range(4)] for i in range(3)]
lists
打开App,阅读手记
8人推荐
发表评论
随时随地看视频慕课网APP