目录
一、基础知识
1.面向对象编程和面向过程编程的区别?
2.一个类通常都定义了什么?
3.函数与类的区别
二、公有和私有
1.默认对象的属性和方法都是公有的
2.定义私有变量只需在变量名或函数名前加上”__“双下划线
三、继承
1.子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性
2.子类继承父类时,子类若重写魔法方法,则应在子类重写魔法方法的时候先调用父类的魔法方法
3.多重继承
4.组合和绑定
5.一些相关的BIF
# 一、面向过程
>>> fruit1 = {'name' : 'Apple', 'sweetness' : 'C'}
>>> fruit2 = {'name' : 'Banana', 'sweetness' : 'B'}
>>> def print_fruit(fruit1):
print('水果名称:%s\n甜度:%s' % (fruit1['name'], fruit1['sweetness']))
>>> print_fruit(fruit1)
#二、面向对象
>>> class Fruit:
... def __init__(self, name, sweetness):
... self.name = name
... self.sweetness = sweetness
... def print_fruit(self):
... print('水果名称:%s\n甜度:%s' % (self.name, self.sweetness))
>>> fru = Fruit('Apple','C')
>>> fru.print_fruit()
水果名称:Apple
甜度:C
对象的特征(即属性)和行为(即方法)
类名约定用大写字母开头,函数用小写字母开头
>>> class Person:
... name = "666"
>>> p = Person()
>>> p.name
'666'
Python 采用 Name Mangling(名字改编技术),这样若要访问私有变量则从理论上讲要从内部进行
>>> class Person:
... def __init__(self,name):
... self.__name = name
... def getname(self):
... return self.__name
>>> p = Person("666")
>>> p.getname()
'666'
# 外部调用则报错
>>> p.__name
AttributeError
>>> class Parent:
... def inherit(self):
... print("正在调用父类的方法")
>>> class Child(Parent):
... def inherit(self):
... print("正在调用子类的方法")
>>> c = Child()
>>> c.inherit()
'正在调用子类的方法'
两种实现技术:(1)调用未绑定的父类方法;(2)使用super函数(其与父类没有直接关系,获取的是 MRO 列表中下一个类)
(MRO详解参考:Python的MRO_鄙人张钊_有何贵干的博客-CSDN博客_mro python)
# 采用”小甲鱼“书中的例子
# 方法一:调用未绑定的父类方法
>>> import random as r
...
... class Fish:
... def __init__(self):
... self.x = r.randint(0,10)
... self.y = r.randint(0,10)
... def move(self):
... self.x -= 1
... print("我的位置是:", self.x, self.y)
...
... class Shark(Fish):
... def __init__(self):
... Fish.__init__(self) # 方法二采用 super 函数:super().__init__()
... self.hungry = True
... def eat(self):
... if self.hungry:
... print("吃吃吃!")
... self.hungry = False
... else:
... print("饱了!")
>>> shark = Shark()
>>> shark.eat()
'吃吃吃!'
>>> shark.eat()
'饱了!'
>>> shark.move()
# 若不添加 Fish.__init__(self) 或 super().__init__() 则报错
# 子类中重写魔法方法,但没有初始化Shark的坐标,所以调用 move() 方法会出错
# 因此需先调用基类的魔法方法
(1)语法:class 类名(父类1,父类2,...)
(2)注意:不确定必须使用多重继承时就尽量不用,易出现钻石继承(菱形继承)等问题
(3)举例:
>>> class A:
... def goods1(self):
... print("goods1在A中")
>>> class B:
... def goods2(self):
... print("goods2在B中")
>>> class C(A, B):
... pass
>>> ab = C()
>>> ab.goods1()
goods1在A中
>>> ab.goods2()
goods2在B中
组合:将需要的类放在一起进行实例化
>>> class Apple:
... def __init__(self, x):
... self.level = x
>>> class Banana:
... def __init__(self, y):
... self.level = y
>>> class Fruits(Apple, Banana):
... def __init__(self, x, y):
... self.apple = Apple(x)
... self.banana = Banana(y)
... def sweetness_level(self):
... print("苹果的甜度等级为%s\n香蕉的甜度等级为%s" % (self.apple.level, self.banana.level))
>>> fruits = Fruits('C', 'B')
>>> fruits.sweetness()
苹果的甜度等级为C
香蕉的甜度等级为B
绑定:Python 严格要求方法需要有实例才能被调用
>>> class CC:
... def setXY(self, x, y):
... self.x = x
... self.y = y
... def printXY(self):
... print(self.x, self.y)
>>> dd = CC()
>>> dd.__dict__
{}
>>> CC.__dict__
# 此处以字典显示实例对象的属性
>>> dd.setXY(2, 3)
>>> dd.__dict__
{'x': 2, 'y': 3}
# 删除类实例,而实例对象 dd 仍可调用类方法
>>> del CC
>>> dd.printXY()
2 3
(1)issubclass(class, classinfo)
>>> class A:
... pass
>>> class B(A):
... pass
# 1.若首个参数(class)是第二个参数(classinfo)的一个子类,则返回 True ,否则返回 False
>>> issubclass(B,A)
True
# 2.一个类被认为是其自身的子类
>>> issubclass(B,B)
True
# 3.classinfo 可以是类对象组成的元组,只要 class 是其中一个候选类的子类,则返回True
>>> issubclass(B,object) # object 是所有类的基类
True
>>> class C:
... pass
>>> issubclass(B,C)
False
(2)isinstance(object, classinfo)
# 1.若首个参数(object)是第二个参数的实例对象(classinfo),则返回 True,否则返回 False
>>> issubclass(B,C)
False
>>> b1 = B()
>>> issubclass(b1,B)
True
# 2.若 object 是 classinfo 的子类的一个实例,也符合条件
>>> isinstance(b1,C)
False
>>> isinstance(b1,A)
True
# 3.classinfo 可以是类对象组成的元组,只要 object 是其中任何一个候选类的子类,则返回 True
>>> isinstance(b1,(A,B,C))
True
(3)hasattr(object, name):测试一个对象是否有指定的属性,attr 即 attribute 的缩写,属性的意思,object 是对象,name 是属性名
>>> class C:
... def __init__(self, x = 0):
... self.x = x
>>> c1 = C()
>>> hasattr(c1, 'x') # 属性名要用引号括起来
True
(4)getattr(object, name[ ,default]):返回对象指定的属性值,若指定的属性不存在,则返回default(可选参数)的值,若未设 default 参数,则抛出 ArttributeError 异常
>>> class C:
... def __init__(self, x = 0):
... self.x = x
>>> c1 = C()
>>> getattr(c1, 'x')
0
>>> getattr(c1, 'y')
AttributeError
>>> getattr(c1, 'y', '您所访问的属性不存在...')
您所访问的属性不存在...
(5)setattr(object,name,value):设置对象中指定的属性值,若不存在,则新建属性并赋值
>>> setattr(c1, 'y', '666')
>>> getattr(c1, 'y')
'666'
>>> setattr(c1, 'y', 666)
>>> getattr(c1, 'y')
666
(6)delattr(object,name):用于删除对象中指定的属性,若属性不存在,抛出 AttributeError 异常
>>> delattr(c1, 'y')
>>> hasattr(c1, 'y')
False
>>> delattr(c1, 'z')
AttributeError
(7)property(fget = None, fset = None, fel = None, doc = None):通过属性设置属性
# 为用户访问只提供了 x 属性,无论内部如何改动,只需要相应地修改 property() 的参数,用户仍然只需要操作 x 的属性即可
>>> class C:
... def __init__(self, size = 10):
... self.size = size
...
... def getSize(self):
... return self.size
...
... def setSize(self):
... self.size = value
...
... def delSize(self):
... del self.size
...
... x = property(getSize, setSize, delSize)
>>> c = C()
>>> c.x
10
>>> c.x = 12 # 不能对c.x赋值的原因?
TypeError: setSize() takes 1 positional argument but 2 were given
>>> c.size = 12
>>> c.x
12
>>> del c.x
>>> c.size
AttributeError: 'C' object has no attribute 'size'
# 将 property 函数用作装饰器可以很方便的创建只读属性
>>> class PropTest(object):
... def __init__(self):
... self._number = 1234
... # 将 number_getter() 方法转化成同名只读属性的 getter 方法
... @property
... def number_getter(self):
... return self._number
>>> a = PropTest()
>>> a._number
1234