天池Python训练营笔记—Python基础进阶:从函数到高级魔法方法 函数 7.1.2 递归 Lambda表达式 匿名函数的应用 类与对象 self是什么? Python的魔法方法 公有和私有 继承 组合 类、类对象和实例对象 绑定 一些相关的内置函数 魔法方法

天池Python训练营笔记—Python基础进阶:从函数到高级魔法方法
函数
7.1.2 递归
Lambda表达式
匿名函数的应用
类与对象
self是什么?
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'>