基础
class Person: #类名
country = 'China' #创造了只要是这个类就一定有的属性类
#类属性 静态属性
def __init__(self,name,age,sex): #对象属性
self.name = name
self.age = age
self.sex = sex
def walk(self,n):
print("%s is a %s,%s years old,walk %s steps"%(self.name,self.sex,self.age,n))
if __name__ == '__main__':
tom = Person(name='Tom',age=10,sex='boy') #实例化
tom.walk(300)
print("%s is in %s"%(tom.name,Person.country))
一个对象的诞生:调用类创建一个名为self的对象,(也可以为其他名字,不过习惯上命名为self),调用__init__()方法初始化,并将self返回。
class Person:
country = 'China'
def __init__(self,name,age,sex):
self.name = name
self.age = age
self.sex = sex
print((id(self)))
def walk(self,n):
print("%s is a %s,%s years old,walk %s steps"%(self.name,self.sex,self.age,n))
if __name__ == '__main__':
tom = Person(name='Tom',age=10,sex='boy')
print((id(tom)))
由此可以看出self和tom是同一个对象。
Tips:
- 对方法的调用,Person.walk(tom)等价于tom.walk()。
- 对象属性和类属性(静态属性)。从调用方式来说,对象属性只可以通过对象来调用,类属性既可以通过对象调用,也可以通过类调用。从内存方面来说,类属性也就是静态属性(static修饰符)在类加载的时候就已经被分配了内存(存在于静态区)只有一份。而对象属性是非static修饰符,是属于单个实例化的类。每new一个实例就会在内存堆中创建一份,就等于多个拷贝,占内存多,但比较灵活,自己修改自己的属性值,互不影响。
class Person: #类名
country = 'China' #创造了只要是这个类就一定有的属性类
#类属性 静态属性
def __init__(self,name,age,sex): #对象属性
self.name = name
self.age = age
self.sex = sex
def walk(self,n):
print("%s is a %s,%s years old,walk %s steps"%(self.name,self.sex,self.age,n))
if __name__ == '__main__':
tom = Person(name='Tom',age=10,sex='boy') #实例化
tom.walk(300)
tom.country = 'Japan'
print("%s is in %s"%(tom.name,tom.country))
print("Person.country = %s"%Person.country)
- 对于不可变数据类型来说,使用对象.静态属性这种方式想去修改静态属性是不行的,本质上它其实是给tom这个对象添加了一个country的属性,并绑定值为“Japan”。如果想要修改静态属性绑定的值就必须要使用类去调用。Person.country=“Japan”这样去修改。
class Person: #类名
country = ['China'] #创造了只要是这个类就一定有的属性类
#类属性 静态属性
def __init__(self,name,age,sex): #对象属性
self.name = name
self.age = age
self.sex = sex
def walk(self,n):
print("%s is a %s,%s years old,walk %s steps"%(self.name,self.sex,self.age,n))
if __name__ == '__main__':
tom = Person(name='Tom',age=10,sex='boy') #实例化
tom.walk(300)
tom.country[0] = 'Japan'
print("%s is in %s"%(tom.name,tom.country))
print("Person.country = %s"%Person.country)
- 对于可变的数据类型来说,可以通过以上方式去修改静态属性。
类命名空间和对象命名空间
- 在类加载时会创建一个类的命名空间,用来存储类中定义的所有名字。静态属性就直接定义到类的命名空间里,而对象属性则绑定到所有的对象。
- 在obj.name会先从obj自己的命名空间里找name,找不到则去类中找,类也找不到就找父类...最后都找不到就抛出异常。
组合
class Person: #类名
country = 'China' #创造了只要是这个类就一定有的属性类
#类属性 静态属性
def __init__(self,name,age,sex,fruit): #对象属性
self.name = name
self.age = age
self.sex = sex
self.fruit = fruit
def walk(self,n):
print("%s is a %s,%s years old,walk %s steps"%(self.name,self.sex,self.age,n))
def eat(self):
print("%s eat a %s %s %s"%(self.name,self.fruit.shape,self.fruit.color,self.fruit.name))
class Fruit:
def __init__(self,name,color,shape):
self.name = name
self.color = color
self.shape = shape
def description(self):
print("A %s %s %s"%(self.shape,self.color,self.name))
- 组合是指在一个类中以另外一个类的对象作为数据属性。
继承
class Animals:
def __init__(self,name,sex):
self.name = name
self.sex = sex
def eat(self):
print("Animals eat")
class Dog(Animals):
def __init__(self,name,sex,owner):
super().__init__(name,sex)
self.owner = owner
def eat(self):
print("Dog eat")
def eat_test(self):
return super().eat()
def bark(self):
print("Dog bark")
if __name__ == '__main__':
jim = Dog(name='Jim',sex='boy',owner='Mary')
jim.eat_test()
单继承中几个Tips:
- 子类如果自己有,一定先使用自己的方法和属性,如果子类没有,可以使用父类的方法和属性。
- 使用super()函数可以直接调用父类的方法或属性。
在Python中支持多继承
class A:
def test(self):
print("A")
class B(A):
def test(self):
print("B")
class C(A):
def test(self):
print("C")
class D(B,C):
def test(self):
print("D")
if __name__ == '__main__':
d = D()
print(d.test())
多继承中继承顺序问题,以上是典型的钻石继承
在经典类和新式类中继承顺序有所不同。在经典类中使用深度优先,在新式类中使用广度优先。对于Python3.x来说所有的类都是新式类。就钻石继承而言,新式类继承顺序为B->C->A,经典类的继承顺序为B->A->C。
多继承中的几个Tips:
- 新式类中可以使用mro()方法,查看广度优先的继承顺序。(类名.mro())
- Python3.x中,super()方法是根据广度优先的继承顺序查找上一个类父类。
- 继承中的两个相关函数
接口类和抽象类
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
@abstractmethod
def pay(self,money):
pass
class Wechatpay(Payment):
def pay(self,money):
print('微信支付了%s元'%money)
p = Wechatpay() #不调就报错了
Tips:
- Python中没有接口类,有抽象类,abc模块中的metaclass = ABCMeta,@abstractmethod。
- 本质是在做代码规范,希望在子类中实现和父类方法名字完全一样的方法。
- 在Java的角度上看是有区别的:
Java本来就支持单继承,所以就有了抽象类
Java没有多继承,所以为了借口隔离原则,设计了接口这个概念,支持多继承。 - Python既支持单继承也支持多继承,所以对于接口类和抽象类的区别不那么明显,甚至在Python中就没有内置接口类
多态
- Python天生支持多态。
- 鸭子类型:不依赖父类的情况下实现两个相似的类中的同名方法。
封装
- 在Python中只要将名字前面加上双下划线,就把这个名字私有化了。
- 私有化之后,就不能从类的外部直接调用了。
- 静态属性,静态方法,对象属性都可以私有化。
- 这种私有化只是从代码级别做了变形,并没有真正的约束。
- 变形机制__类名__名字,在类外用这个调用,在类内部直接__名字调用。
三个装饰器函数
property
@property装饰器的作用:负责把一个方法变成属性调用的
class Person:
country = 'China'
def __init__(self,name,age,sex):
self.name = name
self.__age = age
self.__sex = sex
@property
def age(self):
return self.__age
@age.setter
def age(self,new_age):
self.__age = new_age
@age.deleter
def age(self):
del self.__age
if __name__ == '__main__':
tom = Person('Tom',18,'boy')
print(tom.age)
tom.age = 20
print(tom.age)
del tom.age
print(tom.age)
classmethod
当方法操作只涉及静态属性的时候使用
class Person:
country = 'China'
def __init__(self,name,age,sex):
self.name = name
self.__age = age
self.__sex = sex
@classmethod
def change_country(cls,new_country):
cls.country = new_country
if __name__ == '__main__':
tom = Person('Tom',18,'boy')
print(tom.country)
Person.change_country('Jan')
print(tom.country)
staticmethod
面向对象规范如果一个方法既和对象没有关系,也和类没有关系,那么就使用@staticmethod将其变成一个静态方法。
class Person:
country = 'China'
def __init__(self,name,age,sex):
self.name = name
self.__age = age
self.__sex = sex
@staticmethod
def get_info():
name = input("name:")
age = input("age:")
sex = input("sex:")
if __name__ == '__main__':
Person.get_info()