• 天池Python训练营笔记—Python基础进阶:从函数到高级魔法方法


    函数

    1.函数定义

    • Python将函数也视作对象,可以从另一个函数中返回出来去构建高阶函数,比如:参数是函数,返回值也是函数
    • 函数以def关键词开头,后接函数名和圆括号()
    • return 表示结束函数,选择性地返回一个值给调用方,不带表达式的return相当于返回None

    2.函数调用

    def printme(str):
        print(str)
    
    printme("我要调用用户自定义函数")
    printme("再次调用同一函数")
    temp = printme('hello')
    print(temp)
    
    我要调用用户自定义函数
    再次调用同一函数
    hello
    None
    

    3.函数文档

    def MyFirstFunction(name):
        "函数定义过程中name是形参"
        print("传递进来的{0}叫做实参,因为Ta是具体的参数值".format(name))
    
    MyFirstFunction('老马的程序人生')
    
    print(MyFirstFunction.__doc__)
    
    help(MyFirstFunction)
    
    传递进来的老马的程序人生叫做实参,因为Ta是具体的参数值
    函数定义过程中name是形参
    Help on function MyFirstFunction in module __main__:
    
    MyFirstFunction(name)
        函数定义过程中name是形参
    

    4.函数参数

    Python的函数具有非常灵活多样的参数形态,从简到繁的参数形态如下:

    • 位置参数
    • 默认参数
    • 可变参数
    • 关键字参数
    • 命名关键字参数
    • 参数组合

    4.1 位置参数

    def functionname(arg1):
    "函数,文档字符串"
    return [expression]

    • arg1 - 位置参数,这些参数在调用函数时位置要固定

    4.2 默认参数

    def functionname(arg1,arg2 = v):
    "函数 文档字符串"
    return [expression]

    • arg2 = v - 默认参数=默认值,调用函数时,默认参数没有传入则为默认值
    • 默认参数一定要放在位置参数后面
    def printinfo(name,age = 0):
        print("Name:{0},Age:{1}".format(name,age))
    printinfo("小马")
    printinfo("小马",10)
    
    Name:小马,Age:0
    Name:小马,Age:10
    
    • Python允许函数调用时参数的顺序与声明时不一致,因为Python解释器能够用参数名匹配参数值
    def printinfo(name,age = 0):
        print("Name:{0},Age:{1}".format(name,age))
    printinfo(age = 0,name = "小马")
    
    Name:小马,Age:0
    

    4.3 可变参数

    def functionname(arg1,arg2 = v,*args):
    return [expression]

    • *args -可变参数,可以是从零个到任意个,自动组装成元组
    • 加了星号(*)的变量名会存放所有未命名的变量参数
    def printinfo(arg1,*args):
        print(arg1)
        for var in args:
            print(var)
    printinfo(10)
    printinfo(70,60,50)
    
    10
    70
    60
    50
    

    4.4 关键字参数

    def functionname(arg1,arg2 = v,args,*kw):
    return [expression]

    • *kw -关键字参数,可以是从零个到任意个,自动组装成字典
    def printinfo(arg1,*args,**kwargs):
        print(arg1)
        print(args)
        print(kwargs)
    printinfo(70,60,50)
    printinfo(70,60,50,a = 1,b =2)
    
    70
    (60, 50)
    {}
    70
    (60, 50)
    {'a': 1, 'b': 2}
    
    • 可变参数和关键字参数的同异总结如下:
      • 可变参数允许传入零个到任意个参数,他们在函数调用时会自动组装成一个元组
      • 关键字参数允许传入零个到任意个参数,他们在函数内部自动组装成一个字典。

    4.5 命名关键字参数

    def functionname(arg1,arg2 = v,args,* ,nkw,** kwargs):
    return [expression]

    • *,nkw - 命名关键字参数,用户想要输入的关键字参数,定义方式是在nkw前面加个分隔符 *
    • 如果想要限制关键字参数的名字,可以使用命名关键字参数
    • 使用命名关键字参数时,要特别注意不能缺少参数名。
    def printinfo(arg1,*,nkw,**kwargs):
        print(arg1)
        print(nkw)
        print(kwargs)
    
    printinfo(70,nkw = 10,a=1,b =2)
    printinfo(70,10,a=1,b=2)
    
    70
    10
    {'a': 1, 'b': 2}
    
    
    
    ---------------------------------------------------------------------------
    
    TypeError                                 Traceback (most recent call last)
    
    <ipython-input-5-670826578daa> in <module>
          5 
          6 printinfo(70,nkw = 10,a=1,b =2)
    ----> 7 printinfo(70,10,a=1,b=2)
    
    
    TypeError: printinfo() takes 1 positional argument but 2 were given
    

    4.6 参数组合

    参数定义的顺序:

    • 位置参数、默认参数、可变参数和关键字参数
    • 位置参数、默认参数、命名关键字参数和关键字参数

    注意定义可变参数和关键字参数的语法:

    • *args是可变参数,args接收的是一个tuple
    • **kw是关键字参数,kw接收的是一个dict

    5. 函数的返回值

    def add(a,b):
        return a+b
    
    print(add(1,2))
    print(add([1,2,3],[4,5,6]))
    
    3
    [1, 2, 3, 4, 5, 6]
    
    def back():
        return [1,'小马的程序人生',3.14]
    print(back())
    
    [1, '小马的程序人生', 3.14]
    
    def back():
        return 1,'小马的程序人生',3.14
    print(back())
    
    (1, '小马的程序人生', 3.14)
    
    def printme(str):
        print(str)
    temp = printme('hello')
    print(temp)
    print(type(temp))
    
    hello
    None
    <class 'NoneType'>
    

    6.变量作用域

    • Python中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量在哪里赋值的。
    • 定义在函数内部的变量拥有局部作用域,该变量称为局部变量
    • 定义在函数外部的变量拥有全局作用域,该变量称为全局变量
    • 局部变量只能在其声明的函数内部访问,而全局变量可以在整个程序范围内访问。
    def discount(price,rate):
        final_price = price * rate
        return final_price
    
    old_price = float(input("请输入原价:"))
    rate = float(input("请输入折扣率:"))
    new_price = discount(old_price,rate)
    print("打折后价格是:%.2f"%new_price)
    
    请输入原价:98
    请输入折扣率:0.9
    打折后价格是:88.20
    
    • 当内部作用域想修改外部作用域变量时,需要用到global和nonlocal关键字
    num = 1
    
    def fun1():
        global num
        print(num)
        num = 123
        print(num)
    fun1()
    print(num)
    
    1
    123
    123
    

    7.1 内嵌函数

    def outer():
        print("outer函数在这被调用")
        
        def inner():
            print('inner函数在这里被调用')
        
        inner()
    outer()
    
    outer函数在这被调用
    inner函数在这里被调用
    

    7.1.1 闭包

    • 是函数式编程的一个重要的语法结构,是一种特殊的内嵌函数
    • 如果在一个内部函数里对外层非全局作用域的变量进行引用,那么内部函数就被认为是闭包
    • 通过闭包可以访问外层非全局作用域的变量,这个作用域称为 闭包作用域
    def funX(x):
        def funY(y):
            return x*y
        return funY
    
    i = funX(8)
    print(type(i))
    print(i(5))
    
    <class 'function'>
    40
    
    #闭包的返回值通常是函数
    def make_counter(init):
        counter = [init]
        
        def inc():counter[0] += 1
        def dec():counter[0] -= 1
        def get():return counter[0]
        def reset(): counter[0] = init
        
        return inc,dec,get,reset
    
    inc,dec,get,reset = make_counter(0)
    inc()
    inc()
    inc()
    print(get())
    dec()
    print(get())
    reset()
    print(get())
    
    3
    2
    0
    
    #修改闭包作用域中的变量则需要`nonlocal`关键字
    def outer():
        num = 10
        
        def inner():
            nonlocal num
            num = 100
            print(num)
        
        inner()
        print(num)
        
    outer()
    
    100
    100
    

    7.1.2 递归

    • 如果一个函数在内部调用自身本身,这个函数就是递归函数
    n = 5
    for k in range(1,5):
        n = n * k
    print(n)
    
    def factorial(n):
        if n ==1:
            return 1
        return n*factorial(n-1)
    
    print(factorial(5))
    
    120
    120
    
    #斐波拉契数列
    i = 0
    j = 1
    lst = list([i,j])
    for k in range(2,11):
        k = i+j
        lst.append(k)
        i = j
        j = k
    print(lst)
    
    def recur_fibo(n):
        if n<=1:
            return n
        return recur_fibo(n-1) + recur_fibo(n-2)
    
    lst = list()
    for k in range(11):
        lst.append(recur_fibo(k))
    print(lst)
    
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
    
    #设置递归的层数,python默认递归层数为100
    import sys
    
    sys.setrecursionlimit(1000)
    

    Lambda表达式

    匿名函数的定义

    在Python里有两类函数:

    • 第一类:用def关键词定义的正规函数
    • 第二类:用lambda关键词定义的匿名函数

    Python使用lambda关键词来创建匿名函数,语法结构为:

    lambda argument_list:expression

    • lambda - 定义匿名函数的关键词
    • argument_list - 函数参数,它们可以是位置参数,默认参数,关键字参数和正规函数里的参数类型一样
    • expression-表达式,输入函数参数,输出一些值

    注:

    • expreion中没有return语句,因为lambda不需要它来返回,表达式本身结果就是返回值
    • 匿名函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间的参数
    def sqr(x):
        return x ** 2
    
    
    print(sqr)
    # <function sqr at 0x000000BABD3A4400>
    
    y = [sqr(x) for x in range(10)]
    print(y)
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    lbd_sqr = lambda x: x ** 2
    print(lbd_sqr)
    # <function <lambda> at 0x000000BABB6AC1E0>
    
    y = [lbd_sqr(x) for x in range(10)]
    print(y)
    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    
    
    sumary = lambda arg1, arg2: arg1 + arg2
    print(sumary(10, 20))  # 30
    
    func = lambda *args: sum(args)
    print(func(1, 2, 3, 4, 5))  # 15
    
    <function sqr at 0x000002DDE39820D0>
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    <function <lambda> at 0x000002DDE551C0D0>
    [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
    30
    15
    

    匿名函数的应用

    函数式编程是指代码中每一块都是不可变的,都由纯函数形式组成。这里的纯函数指的是函数本身相互独立,互不影响,对于相同的输入,总会由相同的输出,没有任何副作用。

    # 非函数式编程
    def f(x):
        for i in range(0,len(x)):
            x[i] += 10
        return x
    
    x = [1,2,3]
    f(x)
    print(x)
    
    [11, 12, 13]
    
    #函数式编程
    def f(x):
        x = []
        for item in x:
            y.append(item+10)
        return y
    
    x = [1,2,3]
    f(x)
    print(x)
    
    [1, 2, 3]
    

    匿名函数常常应用与函数式编程的高阶函数,主要有两种形式:

    • 参数是函数
    • 返回值是函数

    比如,在filtermap函数中的应用:

    • filter(function,iterable)过滤序列,过滤掉不符合条件的元素,返回一个迭代器对象,如果要转换为列表,可以使用list()来转换
    odd = lambda x:x%2 ==1
    templist = filter(odd,[1,2,3,4,5,6,7,8,9])
    print(list(templist))
    
    [1, 3, 5, 7, 9]
    
    • map(function,*iterables) 根据提供的函数对指定序列做映射
    m1 = map(lambda x:x **2,[1,2,3,4,5])
    print(list(m1))
    
    m2 = map(lambda x,y:x+y,[1,3,5,7,9],[2,4,6,8,10])
    print(list(m2))
    
    [1, 4, 9, 16, 25]
    [3, 7, 11, 15, 19]
    
    • 自定义高阶函数
    def apply_to_list(fun,some_list):
        return fun(some_list)
    
    lst = [1,2,3,4,5]
    print(apply_to_list(sum,lst))
    
    print(apply_to_list(len,lst))
    
    print(apply_to_list(lambda x:sum(x)/len(x),lst))
    
    15
    5
    3.0
    

    类与对象

    对象 = 属性+方法

    对象是类的实例,类主要定义对象的结构,然后我们以类为模板创建对象。类不但包括方法定义,而且还包括所有实例共享的数据。

    • 封装:信息隐藏技术

    可以使用关键字class定义python类,关键字后面紧跟类的名称、分号和类的实现。

    class Turtle: #Python中的类名约定以大写字母开头
        #属性
        color = 'green'
        weight = 10
        legs = 4
        shell = True
        mouth = '大嘴'
        
        #方法
        def climb(self):
            print("我正在很努力的向前爬...")
        def run(self):
            print("我正在飞快地向前跑...")
        def bite(self):
            print('咬死你咬死你!!')
        def eat(self):
            print('有得吃,真满足...')
        def sleep(self):
            print('困了,睡了,晚安,zzz')
    
    tt = Turtle()
    print(tt)
    
    print(type(tt))
    
    print(tt.__class__)
    
    print(tt.__class__.__name__)
    
    tt.climb()
    tt.run()
    tt.bite()
    print(type(Turtle))
    
    <__main__.Turtle object at 0x000002DDE4F5D2E0>
    <class '__main__.Turtle'>
    <class '__main__.Turtle'>
    Turtle
    我正在很努力的向前爬...
    我正在飞快地向前跑...
    咬死你咬死你!!
    <class 'type'>
    
    • 继承:子类自动共享父类之间数据和方法地机制
    class MyList(list):
        pass
    
    lst = MyList([1,5,2,7,8])
    lst.append(9)
    lst.sort()
    print(lst)
    
    [1, 2, 5, 7, 8, 9]
    
    • 多态:不同对象对同一方法响应不同地行动
    class Animal:
        def run(self):
            raise AttributeError('子类必须实现这个方法')
    
    
    class People(Animal):
        def run(self):
            print('人正在走')
    
    
    class Pig(Animal):
        def run(self):
            print('pig is walking')
    
    
    class Dog(Animal):
        def run(self):
            print('dog is running')
    
    
    def func(animal):
        animal.run()
    
    
    func(Pig())
    # pig is walking
    
    pig is walking
    

    self是什么?

    Python 的self相当于C++的this指针

    class Test:
        def prt(self):
            print(self)
            print(self.__class__)
        
    t = Test()
    t.prt()
    
    <__main__.Test object at 0x000002DDE50AC2B0>
    <class '__main__.Test'>
    

    类的方法与普通的函数只有一个特别的区别——它们必须有一个额外的第一个参数名称self

    class Ball:
        def setName(self, name):
            self.name = name
    
        def kick(self):
            print("我叫%s,该死的,谁踢我..." % self.name)
    
    
    a = Ball()
    a.setName("球A")
    b = Ball()
    b.setName("球B")
    c = Ball()
    c.setName("球C")
    a.kick()
    # 我叫球A,该死的,谁踢我...
    b.kick()
    # 我叫球B,该死的,谁踢我...
    
    我叫球A,该死的,谁踢我...
    我叫球B,该死的,谁踢我...
    

    Python的魔法方法

    类有一个名为__init__(self,param1,...,paramn)的魔法方法,该方法在类实例化时会自动调用

    class Ball:
        def __init__(self, name):
            self.name = name
    
        def kick(self):
            print("我叫%s,该死的,谁踢我..." % self.name)
    
    
    a = Ball("球A")
    b = Ball("球B")
    c = Ball("球C")
    a.kick()
    # 我叫球A,该死的,谁踢我...
    b.kick()
    # 我叫球B,该死的,谁踢我...
    
    我叫球A,该死的,谁踢我...
    我叫球B,该死的,谁踢我...
    

    公有和私有

    在Python中定义私有变量只需要在变量名或函数名前加上__两个下划线,那么这个函数或变量就会变为私有了

    • 类的私有属性实例
    class JustCounter:
        __secretCount = 0  # 私有变量
        publicCount = 0  # 公开变量
    
        def count(self):
            self.__secretCount += 1
            self.publicCount += 1
            print(self.__secretCount)
    
    
    counter = JustCounter()
    counter.count()  # 1
    counter.count()  # 2
    print(counter.publicCount)  # 2
    
    # Python的私有为伪私有
    print(counter._JustCounter__secretCount)  # 2 
    print(counter.__secretCount)  
    # AttributeError: 'JustCounter' object has no attribute '__secretCount'
    
    1
    2
    2
    2
    
    
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-20-0e7487766f54> in <module>
         16 # Python的私有为伪私有
         17 print(counter._JustCounter__secretCount)  # 2
    ---> 18 print(counter.__secretCount)
         19 # AttributeError: 'JustCounter' object has no attribute '__secretCount'
    
    
    AttributeError: 'JustCounter' object has no attribute '__secretCount'
    
    • 类的私有方法实例
    class Site:
        def __init__(self, name, url):
            self.name = name  # public
            self.__url = url  # private
    
        def who(self):
            print('name  : ', self.name)
            print('url : ', self.__url)
    
        def __foo(self):  # 私有方法
            print('这是私有方法')
    
        def foo(self):  # 公共方法
            print('这是公共方法')
            self.__foo()
    
    
    x = Site('老马的程序人生', 'https://blog.csdn.net/LSGO_MYP')
    x.who()
    # name  :  老马的程序人生
    # url :  https://blog.csdn.net/LSGO_MYP
    
    x.foo()
    # 这是公共方法
    # 这是私有方法
    
    x.__foo()
    # AttributeError: 'Site' object has no attribute '__foo'
    
    name  :  老马的程序人生
    url :  https://blog.csdn.net/LSGO_MYP
    这是公共方法
    这是私有方法
    
    
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-21-555cf676b575> in <module>
         25 # 这是私有方法
         26 
    ---> 27 x.__foo()
         28 # AttributeError: 'Site' object has no attribute '__foo'
    
    
    AttributeError: 'Site' object has no attribute '__foo'
    

    继承

    • 如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性
    # 类定义
    class people:
        # 定义基本属性
        name = ''
        age = 0
        # 定义私有属性,私有属性在类外部无法直接进行访问
        __weight = 0
    
        # 定义构造方法
        def __init__(self, n, a, w):
            self.name = n
            self.age = a
            self.__weight = w
    
        def speak(self):
            print("%s 说: 我 %d 岁。" % (self.name, self.age))
    
    
    # 单继承示例
    class student(people):
        grade = ''
    
        def __init__(self, n, a, w, g):
            # 调用父类的构函
            people.__init__(self, n, a, w)
            self.grade = g
    
        # 覆写父类的方法
        def speak(self):
            print("%s 说: 我 %d 岁了,我在读 %d 年级" % (self.name, self.age, self.grade))
    
    
    s = student('小马的程序人生', 10, 60, 3)
    s.speak()
    # 小马的程序人生 说: 我 10 岁了,我在读 3 年级
    
    小马的程序人生 说: 我 10 岁了,我在读 3 年级
    

    注意:如果上面的程序去掉:people.__init__(self, n, a, w),则输出:说: 我 0 岁了,我在读 3 年级,因为子类的构造方法把父类的构造方法覆盖了。

    import random
    
    class Fish:
        def __init__(self):
            self.x = random.randint(0, 10)
            self.y = random.randint(0, 10)
    
        def move(self):
            self.x -= 1
            print("我的位置", self.x, self.y)
    
    
    class GoldFish(Fish):  # 金鱼
        pass
    
    
    class Carp(Fish):  # 鲤鱼
        pass
    
    
    class Salmon(Fish):  # 三文鱼
        pass
    
    
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True
    
    
    g = GoldFish()
    g.move()  # 我的位置 9 4
    s = Shark()
    s.eat() # 吃货的梦想就是天天有得吃!
    s.move()  
    # AttributeError: 'Shark' object has no attribute 'x'
    
    我的位置 2 1
    吃货的梦想就是天天有得吃!
    
    
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-3-f795a471252a> in <module>
         40 s = Shark()
         41 s.eat() # 吃货的梦想就是天天有得吃!
    ---> 42 s.move()
         43 # AttributeError: 'Shark' object has no attribute 'x'
    
    
    <ipython-input-3-f795a471252a> in move(self)
          7 
          8     def move(self):
    ----> 9         self.x -= 1
         10         print("我的位置", self.x, self.y)
         11 
    
    
    AttributeError: 'Shark' object has no attribute 'x'
    

    出现上述报错的原因是因为子类的构造方法覆盖了父类的构造方法,导致父类构造方法中的变量无法继承,有以下两种解决方法。

    • 调用未绑定的父类方法
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            Fish.__init__(self)
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True
    
    • 使用super函数super().__init__()
    class Shark(Fish):  # 鲨鱼
        def __init__(self):
            super().__init__()
            self.hungry = True
    
        def eat(self):
            if self.hungry:
                print("吃货的梦想就是天天有得吃!")
                self.hungry = False
            else:
                print("太撑了,吃不下了!")
                self.hungry = True
    

    组合

    class Turtle:
        def __init__(self, x):
            self.num = x
    
    
    class Fish:
        def __init__(self, x):
            self.num = x
    
    
    class Pool:
        def __init__(self, x, y):
            self.turtle = Turtle(x)
            self.fish = Fish(y)
    
        def print_num(self):
            print("水池里面有乌龟%s只,小鱼%s条" % (self.turtle.num, self.fish.num))
    
    
    p = Pool(2, 3)
    p.print_num()
    # 水池里面有乌龟2只,小鱼3条
    
    水池里面有乌龟2只,小鱼3条
    

    类、类对象和实例对象

    类对象:创建一个类,表示一个对象在内存开辟了一块空间,称为类对象,类对象只有一个。

    实例对象:通过实例化类创建的对象,称为实例对象,实例对象有多个。

    class A(object):
        pass
    
    # 实例化对象 a、b、c都属于实例对象。
    a = A()
    b = A()
    c = A()
    

    类属性:类里面方法外定义的变量称为类属性,类属性所属于类对象并且多个实例对象之间共享同一个类属性,类属性所有通过该类实例化的对象都能共享

    class A():
        a = 0  #类属性
        def __init__(self, xx):
            A.a = xx  #使用类属性可以通过 (类名.类属性)调用。
    

    实例属性:实例属性和具体的某个实例对象有关系,并且一个实例对象和另外一个实例对象是不共享属性的,说白了实例属性只能在自己的对象里面使用,其他的对象不能直接使用,因为self是谁调用,它的值就属于该对象。

    # 创建类对象
    class Test(object):
        class_attr = 100  # 类属性
    
        def __init__(self):
            self.sl_attr = 100  # 实例属性
    
        def func(self):
            print('类对象.类属性的值:', Test.class_attr)  # 调用类属性
            print('self.类属性的值', self.class_attr)  # 相当于把类属性 变成实例属性
            print('self.实例属性的值', self.sl_attr)  # 调用实例属性
    
    
    a = Test()
    a.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    b = Test()
    b.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    a.class_attr = 200
    a.sl_attr = 200
    a.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 200
    # self.实例属性的值 200
    
    b.func()
    
    # 类对象.类属性的值: 100
    # self.类属性的值 100
    # self.实例属性的值 100
    
    Test.class_attr = 300
    a.func()
    
    # 类对象.类属性的值: 300
    # self.类属性的值 200
    # self.实例属性的值 200
    
    b.func()
    # 类对象.类属性的值: 300
    # self.类属性的值 300
    # self.实例属性的值 100
    
    类对象.类属性的值: 100
    self.类属性的值 100
    self.实例属性的值 100
    类对象.类属性的值: 100
    self.类属性的值 100
    self.实例属性的值 100
    类对象.类属性的值: 100
    self.类属性的值 200
    self.实例属性的值 200
    类对象.类属性的值: 100
    self.类属性的值 100
    self.实例属性的值 100
    类对象.类属性的值: 300
    self.类属性的值 200
    self.实例属性的值 200
    类对象.类属性的值: 300
    self.类属性的值 300
    self.实例属性的值 100
    

    绑定

    Python 对象的数据属性通常存储在名为.__ dict__的字典中,我们可以直接访问__dict__,或利用 Python 的内置函数vars()获取.__ dict__

    class CC:
        def setXY(self, x, y):
            self.x = x
            self.y = y
    
        def printXY(self):
            print(self.x, self.y)
    
    
    dd = CC()
    print(dd.__dict__)
    # {}
    
    print(vars(dd))
    # {}
    
    print(CC.__dict__)
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000C3473DA048>, 'printXY': <function CC.printXY at 0x000000C3473C4F28>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    dd.setXY(4, 5)
    print(dd.__dict__)
    # {'x': 4, 'y': 5}
    
    print(vars(CC))
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    print(CC.__dict__)
    # {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000000632CA9B048>, 'printXY': <function CC.printXY at 0x000000632CA83048>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    
    {}
    {}
    {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000001F1E5F4DC10>, 'printXY': <function CC.printXY at 0x000001F1E5F4DB80>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    {'x': 4, 'y': 5}
    {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000001F1E5F4DC10>, 'printXY': <function CC.printXY at 0x000001F1E5F4DB80>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    {'__module__': '__main__', 'setXY': <function CC.setXY at 0x000001F1E5F4DC10>, 'printXY': <function CC.printXY at 0x000001F1E5F4DB80>, '__dict__': <attribute '__dict__' of 'CC' objects>, '__weakref__': <attribute '__weakref__' of 'CC' objects>, '__doc__': None}
    

    一些相关的内置函数

    • issubclass(class,classinfo)方法用于判断参数class是否是类型参数classsinfo的子类
    • 一个类被认为是其自身的子类
    • classinfo可以是类对象的元组,只要class是其中任意一个候选类的子类则返回True
    class A:
        pass
    
    
    class B(A):
        pass
    
    
    print(issubclass(B, A))  # True
    print(issubclass(B, B))  # True
    print(issubclass(A, B))  # False
    print(issubclass(B, object))  # True
    
    True
    True
    False
    True
    
    • isinstance(object,classinfo)方法用于判断一个对象是否是一个已知的类型,类似type()
    • type()不会认为子类是一种父类类型,不考虑继承关系
    • isinstance()会认为子类是一种父类类型,考虑继承关系
    • 如果第一个参数不是对象,则永远返回False
    • 如果第二个参数不是类或者由类对象组成的元组,则会抛出异常
    a = 2
    print(isinstance(a, int))  # True
    print(isinstance(a, str))  # False
    print(isinstance(a, (str, int, list)))  # True
    
    
    class A:
        pass
    
    
    class B(A):
        pass
    
    
    print(isinstance(A(), A))  # True
    print(type(A()) == A)  # True
    print(isinstance(B(), A))  # True
    print(type(B()) == A)  # False
    
    True
    False
    True
    True
    True
    True
    False
    
    • hasattr(object,name)用于判断对象是否包含对应的属性
    class Coordinate:
        x = 10
        y = -5
        z = 0
    
    
    point1 = Coordinate()
    print(hasattr(point1, 'x'))  # True
    print(hasattr(point1, 'y'))  # True
    print(hasattr(point1, 'z'))  # True
    print(hasattr(point1, 'no'))  # False
    
    True
    True
    True
    False
    
    • getattr(object,name,default)用于返回一个对象属性值
    class A(object):
        bar = 1
    
    
    a = A()
    print(getattr(a, 'bar'))  # 1
    print(getattr(a, 'bar2', 3))  # 3
    print(getattr(a, 'bar2'))
    # AttributeError: 'A' object has no attribute 'bar2'
    
    1
    3
    
    
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-14-a381bb20461b> in <module>
          6 print(getattr(a, 'bar'))  # 1
          7 print(getattr(a, 'bar2', 3))  # 3
    ----> 8 print(getattr(a, 'bar2'))
          9 # AttributeError: 'A' object has no attribute 'bar2'
    
    
    AttributeError: 'A' object has no attribute 'bar2'
    
    • setattr(object,name,value)对应函数getattr(),用于设置属性值,该属性不一定是存在的
    class A(object):
        bar = 1
    
    
    a = A()
    print(getattr(a, 'bar'))  # 1
    setattr(a, 'bar', 5)
    print(a.bar)  # 5
    setattr(a, "age", 28)
    print(a.age)  # 28
    
    1
    5
    28
    
    • delattr(object,name)用于删除属性
    class Coordinate:
        x = 10
        y = -5
        z = 0
    
    
    point1 = Coordinate()
    
    print('x = ', point1.x)  # x =  10
    print('y = ', point1.y)  # y =  -5
    print('z = ', point1.z)  # z =  0
    
    delattr(Coordinate, 'z')
    
    print('--删除 z 属性后--')  # --删除 z 属性后--
    print('x = ', point1.x)  # x =  10
    print('y = ', point1.y)  # y =  -5
    
    # 触发错误
    print('z = ', point1.z)
    # AttributeError: 'Coordinate' object has no attribute 'z'
    
    x =  10
    y =  -5
    z =  0
    --删除 z 属性后--
    x =  10
    y =  -5
    
    
    
    ---------------------------------------------------------------------------
    
    AttributeError                            Traceback (most recent call last)
    
    <ipython-input-16-e10298e6b2b2> in <module>
         18 
         19 # 触发错误
    ---> 20 print('z = ', point1.z)
         21 # AttributeError: 'Coordinate' object has no attribute 'z'
    
    
    AttributeError: 'Coordinate' object has no attribute 'z'
    

    魔法方法

    • 魔法方法总是被双下划线包围
    • 魔法方法是面向对象Python的一切
    • 魔法方法总能在适当的时候被自动调用
    • 魔法方法的第一个参数应未cls(类方法)或者self(实例方法)
      • cls:代表一个类的名称
      • self:代表一个实例对象的名称

    基本的魔法方法

    • __init__(self)构造器,当一个实例被创建的时候调用的初始化方法
    class Rectangle:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def getPeri(self):
            return (self.x + self.y) * 2
    
        def getArea(self):
            return self.x * self.y
    
    
    rect = Rectangle(4, 5)
    print(rect.getPeri())  # 18
    print(rect.getArea())  # 20
    
    18
    20
    
    • __new__(cls[, ...]) 在一个对象实例化的时候所调用的第一个方法,在调用__init__初始化前,先调用__new__
      • __new__至少要有一个参数cls,代表要实例化的类,此参数在实例化时由 Python 解释器自动提供,后面的参数直接传递给__init__
      • __new__对当前类进行了实例化,并将实例返回,传给__init__的self。但是,执行了__new__,并不一定会进入__init__,只有__new__返回了,当前类cls的实例,当前类的__init__才会进入。
    class A(object):
        def __init__(self, value):
            print("into A __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into A __new__")
            print(cls)
            return object.__new__(cls)
    
    
    class B(A):
        def __init__(self, value):
            print("into B __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into B __new__")
            print(cls)
            return super().__new__(cls, *args, **kwargs)
    
    
    b = B(10)
    
    
    class A(object):
        def __init__(self, value):
            print("into A __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into A __new__")
            print(cls)
            return object.__new__(cls)
    
    
    class B(A):
        def __init__(self, value):
            print("into B __init__")
            self.value = value
    
        def __new__(cls, *args, **kwargs):
            print("into B __new__")
            print(cls)
            return super().__new__(A, *args, **kwargs)  # 改动了cls变为A
    
    
    b = B(10)
    
    into B __new__
    <class '__main__.B'>
    into A __new__
    <class '__main__.B'>
    into B __init__
    into B __new__
    <class '__main__.B'>
    into A __new__
    <class '__main__.A'>
  • 相关阅读:
    BCP 命令
    模板复习【updating】
    bzoj3716/4251 [PA2014]Muzeum
    bzoj4318 OSU!
    uoj308 【UNR #2】UOJ拯救计划
    bzoj4695 最假女选手
    省队集训 Day7 选点游戏
    hdu5828 Rikka with Sequence
    bzoj2482 [Spoj1557] Can you answer these queries II
    省队集训 Day6 序列
  • 原文地址:https://www.cnblogs.com/MurasameLory-chenyulong/p/14884291.html
Copyright © 2020-2023  润新知