Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。本章节我们将详细介绍Python的面向对象编程。
如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。
接下来我们先来简单的了解下面向对象的一些基本特征。
和其它编程语言相比,Python 在尽可能不增加新的语法和语义的情况下加入了类机制。
Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。对象可以包含任意数量和类型的数据。
面向对象的重要术语:
函数和面向对象编程的区别:
面向对象VS面向过程:
__init__ # 构造函数 Self.name = name # 实例变量、普通属性 或者叫 普通字段 public_object = "public" # 类变量、公有属性 或则叫 静态字段 self.__heart= "Normal" # 私有属性 在外面无法访问 def shot(self) # 类方法
def db_conn(): print("connecting db...") def db_backup(dbname): print("导出数据库...", dbname) print("将备份文件打包,移至相应目录...") def db_backup_test(): print("将备份文件导入测试库,看导入是否成功") def main(): db_conn() db_backup(‘my_db‘) db_backup_test() if __name__ == ‘__main__‘: main() # 运行结果: # connecting db... # 导出数据库... my_db # 将备份文件打包,移至相应目录... # 将备份文件导入测试库,看导入是否成功
class Role(object): #1、在定义类时继承object就是新式类,没有就是就是旧类式 public_object = "public" #2、在类例定义一个公有属性:所有实例都能访问的属性叫“公有属性” def __init__(self,name,role,weapon,life_value=100,money=15000): #构造函数==初始化方法:模板 self.name = name #3、普通属性 self.__heart= "Normal" #4、私有属性在外面无法访问 def shot(self): #5、类的方法 print("%s is shooting..."%self.name)
class Role(object): #在定义类时继承object就是新式类,没有就是就是旧类式 public_object = "public" #在类例定义一个公有属性:所有实例都能访问的属性叫“公有属性” def __init__(self,name,role,weapon,life_value=100,money=15000): #构造函数==初始化方法:模板 self.name = name #普通属性 self.role = role self.weapon = weapon self.life_value = life_value self.money = money self.__heart= "Normal" #私有属性在外面无法访问 def shot(self): #类的方法 print("%s is shooting..."%self.name) def got_shot(self): print("ah...,I got shot...") def buy_gun(self,gun_name): print("%s just bought %s" %(self.name,gun_name)) self.weapon = gun_name #在购买后让实例值改变 #在下面实例化其实就是传入: Role(‘r1‘,‘Alex‘,‘police‘,‘AK47‘) 把r1传给了self #r1就是实例化后产生的当前Role类的实例,所以self就是实例本身 #我理解r1其实就是__init__函数的内存地址 #所以在下面函数中调用self.name就相当于调用r1.name所以可以调用 r1 = Role(‘Alex‘,‘police‘,‘AK47‘) #生成一个角色 只要一实例化就会自动调用__init__ r2 = Role(‘Jack‘,‘terrorist‘,‘B22‘) #生成一个角色 r1.shot() print(r2.weapon) #在调用r2.buy_gun(‘AK47‘)前是:B22 r2.buy_gun(‘AK47‘) print(r2.weapon) #在调用r2.buy_gun(‘AK47‘)后是:AK47 #私有属性 # print(r2.__heart) #这里的.__heart是私有属性,所以在外部无法访问 print(r2._Role__heart) #强制访问私有属性的方法 #公有属性 print(r2.public_object) #打印出类的公有属性 Role.public_object = ‘change_public‘ #从全局改变类的公有属性 r1,r2的公有属性都会变 print(r2.public_object) #这里打印可以看出公有属性变成类“change_public" r2.public_object = "public_r2" #改变r2对象的公有属性,r1不会变 print(r2.public_object) #打印出改变后的r2公有属性
公有属性,普通属性,私有属性 比较
类中函数私有化
class Secretive: def __accessible(self): print("you can‘t see me,unless you‘re calling internally") def accessible(self): print("The secret message is:") self.__accessible() s = Secretive() s.accessible() # 运行结果: # The secret message is: # you can‘t see me,unless you‘re calling internally
Encapsulation 封装(隐藏实现细节)
class Foo: def __init__(self, name, age ,gender): self.name = name self.age = age self.gender = gender def eat(self): print "%s,%s岁,%s,吃奶" %(self.name, self.age, self.gender) def he(self): print "%s,%s岁,%s,喝水" %(self.name, self.age, self.gender) def shui(self): print "%s,%s岁,%s,睡觉" %(self.name, self.age, self.gender) a = Foo(‘jack‘, 10, ‘男‘) a.eat() a.he() a.shui() b = Foo(‘rose‘, 11, ‘女‘) b.eat() b.he() b.shui()
Inheritance 继承(代码重用)
class Animal: def eat(self): print "%s 吃 " %self.name def drink(self): print "%s 喝 " %self.name def shit(self): print "%s 拉 " %self.name def pee(self): print "%s 撒 " %self.name class Cat(Animal): def __init__(self, name): self.name = name self.breed = ‘猫‘ def cry(self): print ‘喵喵叫‘ class Dog(Animal): def __init__(self, name): self.name = name self.breed = ‘狗‘ def cry(self): print ‘汪汪叫‘ # ######### 执行 ######### c1 = Cat(‘猫one‘) c1.eat() c2 = Cat(‘猫two‘) c2.drink() d1 = Dog(‘狗one‘) d1.eat()
class Person(object): def __init__(self,name,age): #执行Person.__init__(self,name,age)时就会将传入的参数执行一遍 self.name = name #所以在BlackPerson中不仅有name,age而且还有sex self.age = age self.sex = "normal" def talk(self): print("person is talking....") class WhitePerson(Person): pass class BlackPerson(Person): def __init__(self,name,age,strength): #先覆盖,再继承,再重构 #先覆盖父类的__init__方法,再继承父类__init__,再加自己的参数 Person.__init__(self,name,age) #先继承父类Person,这里self就是BlackPerson本身 #先将name,age传给子类BlackPerson,然后调用Person.__init__构造方法将参数出入父类() self.strength = strength #然后再重构自己的方法,即写自己的参数 print(self.name,self.age,self.sex) print(self.strength) def talk(self): print("black balabla") def walk(self): print("is walking....") b = BlackPerson("wei er smith",22,"Strong") b.talk() b.walk() # 运行结果: # wei er smith 22 normal # Strong # black balabla # is walking.... # person is talking....
注意: 关于多继承
Polymorphism 多态(接口重用)
class Animal: def __init__(self, name): # Constructor of the class self.name = name def talk(self): # Abstract method, defined by convention only raise NotImplementedError("Subclass must implement abstract method") class Cat(Animal): def talk(self): return ‘Meow!‘ class Dog(Animal): def talk(self): return ‘Woof! Woof!‘ animals = [Cat(‘Missy‘), Dog(‘Lassie‘)] for animal in animals: print(animal.name + ‘: ‘ + animal.talk()) # 运行结果: # Missy: Meow! # Lassie: Woof! Woof!
静态方法(用这个装饰器来表示 @staticmethod)
错误示例: class Person(object): def __init__(self, name): self.name = name @staticmethod # 把eat方法变为静态方法 def eat(self): print("%s is eating" % self.name) d = Person("xiaoming") d.eat() ############## 结果: TypeError: eat() missing 1 required positional argument: ‘self‘
因为用静态方法把eat这个方法与Person这个类截断了,eat方法就没有了类的属性了,所以获取不到self.name这个变量。
正确示例: class Person(object): def __init__(self, name): self.name = name @staticmethod # 把eat方法变为静态方法 def eat(x): print("%s is eating" % x) d = Person("xiaoming") d.eat("jack") #就把eat方法当作一个独立的函数给他传参就行了
类方法(用这个装饰器来表示 @classmethod)
错误示例: class Person(object): def __init__(self, name): self.name = name @classmethod # 把eat方法变为类方法 def eat(self): print("%s is eating" % self.name) d = Person("xiaoming") d.eat() ########### 结果: AttributeError: type object ‘Person‘ has no attribute ‘name‘
因为self.name这个变量是实例化这个类传进去的,类方法是不能访问实例变量的,只能访问类里面定义的变量
class Person(object): name="杰克" def __init__(self, name): self.name = name @classmethod # 把eat方法变为类方法 def eat(self): print("%s is eating" % self.name) d = Person("xiaoming") d.eat()
属性方法(用这个装饰器表示 @property)
错误示例: class Person(object): def __init__(self, name): self.name = name @property # 把eat方法变为属性方法 def eat(self): print("%s is eating" % self.name) d = Person("xiaoming") d.eat() ########## 结果: TypeError: ‘NoneType‘ object is not callable
因为eat此时已经变成一个属性了, 不是方法了, 想调用已经不需要加()号了,直接d.eat就可以了
class Person(object): def __init__(self, name): self.name = name @property # 把eat方法变为属性方法 def eat(self): print("%s is eating" % self.name) d = Person("xiaoming") d.eat
class Flight(object): def __init__(self,name): self.flight_name = name def checking_status(self): print("checking flight %s status " % self.flight_name) return 1 @property def flight_status(self): status = self.checking_status() if status == 0 : print("flight got canceled...") elif status == 1 : print("flight is arrived...") elif status == 2: print("flight has departured already...") else: print("cannot confirm the flight status...,please check later") f = Flight("CA980") f.flight_status
成员修饰符
class a: # 说明父类的私有成员无法在子类中继承 def __init__(self): self.ge=123 self.__gene=456 class b(a): def __init__(self,name): self.name=name self.__age=18 super(b,self).__init__() # 这一行会报错 def show(self): print(self.name) print(self.__age) print(self.ge) print(self.__gene) # 这一行也会报错 obj=b("xiaoming") print(obj.name) print(obj.ge) # print(obj.__gene) # 这个也会报错 obj.show()
上面就是类里面的私有成员了。
class Dog(object): def __init__(self,name): self.name = ‘实例变量‘ self.name = name def __call__(self, *args, **kwargs): print("running call") print(args,kwargs) d = Dog("ChenRonghua") d(name=‘tom‘) # 如果只实例化,而不d()调用,__call__函数不会执行 # 运行结果: # running call # () {‘name‘: ‘tom‘}
class Foo: def __str__(self): return ‘alex li‘ obj = Foo() print(obj) # 输出:alex li
class abc: def __init__(self,age): self.age=age def __add__(self,obj): return self.age+obj.age a1=abc(18) a2=abc(20) print(a1+a2) #执行结果:38
class Province: country = ‘China‘ def __init__(self, name, count): self.name = name self.count = count def func(self, *args, **kwargs): print(‘func‘) # 获取类的成员,即:静态字段、方法、 print(Province.__dict__) # 输出:{‘country‘: ‘China‘, ‘__module__‘: ‘__main__‘, ‘func‘: <function func at 0x10be30f50>, ‘__init__‘: <function __init__ at 0x10be30ed8>, ‘__doc__‘: None} obj1 = Province(‘HeBei‘,10000) print(obj1.__dict__) # 获取 对象obj1 的成员 # 输出:{‘count‘: 10000, ‘name‘: ‘HeBei‘} obj2 = Province(‘HeNan‘, 3888) print(obj2.__dict__) # 获取 对象obj1 的成员 # 输出:{‘count‘: 3888, ‘name‘: ‘HeNan‘}
class Foo: """ 输出类的描述类信息 """ def func(self): pass print(Foo.__doc__) #运行结果:描输出类的描述类信息
class Foo(object): def __getitem__(self, key): print(‘__getitem__‘, key) def __setitem__(self, key, value): print(‘__setitem__‘, key, value) def __delitem__(self, key): print(‘__delitem__‘, key) obj = Foo() result = obj[‘k1‘] # __getitem__ k1 obj[‘k2‘] = ‘wupeiqi‘ # __setitem__ k2 wupeiqi del obj[‘k1‘] # __delitem__ k1
class Foo: def __init__(self,name,age): self.name=name self.age=age self.li=[1,2,3,4,5,6,7] def __getitem__(self, item): # 匹配:对象[item]这种形式 if isinstance(item,slice): # 如果是slice对象,返回切片后的结果 return self.li[item] # 返回切片结果 elif isinstance(item,int): # 如果是整形,说明是索引 return item+10 def __setitem__(self, key, value): # 匹配:对象[key]=value这种形式 print(key,value) def __delitem__(self, key): # 匹配:del 对象[key]这种形式 print(key) def __getslice__(self,index1,index2): print(index1,index2) li=Foo("alex",18) print(li[3:5]) #执行结果: [4, 5]
class Foo: def __init__(self,name,age): self.name=name self.age=age def __iter__(self): return iter([1,2,3,4,5]) # 返回的是一个迭代器 li=Foo("alex",18) # 1.如果类中有__iter__方法,他的对象就是可迭代对象 # 2.对象.__iter()的返回值是一个迭代器 # 3.for循环的如果是迭代器,直接执行.next方法 # 4.for循环的如果是可迭代对象,先执行对象.__iter(),获取迭代器再执行next for i in li: print(i) #执行结果: 1 2 3 4 5
class User(object): def __init__(self,name,age): print(‘__init__‘) def __new__(cls, *args, **kwargs): print("__new__",args,kwargs) return object.__new__(cls) # 调用一下object的__new__方法否则不往下走 d = User(‘tom‘,100) # 运行结果: # __new__ (‘tom‘, 100) {} # __init__
__new__和__init__的区别
isinstance和issubclass
class Foo: def __init__(self,name,age): self.name=name self.age=age class Son(Foo): pass obj=Son("xiaoming",18) print(isinstance(obj,Foo)) 执行结果:True
issubclass用来判断一个类是否是某个类的子类,返回的是一个bool类型数据,代码如下:
class Foo: def __init__(self,name,age): self.name=name self.age=age class Son(Foo): pass obj=Son("xiaoming",18) print(issubclass(Son,Foo)) 执行结果:True
class A: #经典类写法 pass class B(object): #新式类写法 pass
SchoolMember.__init__(self,name,age,sex) #经典类写法 super(Teacher,self).__init__(name,age,sex) #新式类写法
class Bird: def __init__(self): self.hungry = True def eat(self): if self.hungry == True: print("Aaaah...") self.hungry = False else: print("no, thanks") a = Bird() a.eat() a.eat() class SongBird(Bird): def __init__(self): # Bird.__init__(self) # 经典类写法 # super(SongBird,self).__init__() # 新式类写法 self.sound = ‘Squawk‘ def sing(self): print(self.sound) b = SongBird() b.sing() b.eat()
class SchoolMember(object): ‘‘‘学校成员基类‘‘‘ member = 0 def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex self.enroll() #只要一实例化就自动注册 def enroll(self): ‘‘‘注册‘‘‘ print("just enrolled a new school member [%s]"%self.name) SchoolMember.member += 1 def tell(self): print("------info:%s-------"%self.name) for k,v in self.__dict__.items(): print("\t",k,‘:‘,v) def __del__(self): #‘‘‘析构方法‘‘‘ print("开除了[%s]...."%self.name) SchoolMember.member -= 1 class Teacher(SchoolMember): def __init__(self,name,age,sex,salary,course): SchoolMember.__init__(self,name,age,sex) #经典类写法 #super(Teacher,self).__init__(name,age,sex) #新式类写法 self.salary = salary self.cource = course # self.enroll() def teaching(self): print("Teacher [%s] is teachin g [%s]"%(self.name,self.cource)) class Student(SchoolMember): def __init__(self,name,age,sex,course,tuition): SchoolMember.__init__(self,name,age,sex) self.cource = course self.tuition = tuition self.amount = 0 # self.enroll() def pay_tuition(self,amount): print("student [%s] has just paied [%s]"%(self.name,amount)) self.amount += amount t1 = Teacher("Wusir",28,"F*M",3000,"python") s1 = Student("HaiTao",38,"M","PYS15",300000) s2 = Student("Lichuang",12,"M","PYS15",11000) print(SchoolMember.member) del s2 print(SchoolMember.member) t1.tell()
class SchoolMember(object): def __init__(self,name,age): self.name = name self.age = age def tell(self): print("I am SchoolMember,my name is %s"%self.name) SM1 = SchoolMember("tom",100) class Teacher(object): def __init__(self,sex,t1): self.SchoolMember = t1 def user_SM(self): self.SchoolMember.tell() T1 = Teacher(‘F‘,SM1) T1.user_SM()
class Dog(object): def __init__(self,name,dog_type): self.name = name self.type = dog_type def sayhi(self): print("i am a dog,my name is %s"%self.name) d = Dog(‘LiChuang‘,‘京巴‘) #等价于 Dog(d,"LiChuang","京巴") d.sayhi() #运行结果:i am a dog,my name is LiChuang
class Dog(object): def eat(self,food): print("eat method!!!") d = Dog() #hasattr判断对象d是否有eat方法,有返回True,没有返回False print(hasattr(d,‘eat‘)) #True print(hasattr(d,‘cat‘)) #False
class Dog(object): def eat(self): print("eat method!!!") d = Dog() if hasattr(d,‘eat‘): # hasattr判断实例是否有eat方法 func = getattr(d, ‘eat‘) # getattr获取实例d的eat方法内存地址 func() # 执行实例d的eat方法 #运行结果: eat method!!!
class Dog(object): def eat(self,food): print("eat method!!!") d = Dog() def bulk(self): #给Dog类添加一个方法必须先写这个方法 print(‘bulk method add to Dog obj‘) d = Dog() setattr(d,"bulk",bulk) #将bulk方法添加到实例d中,命名为talk方法 d.bulk(d) #实例d调用刚刚添加的talk方法时必须将实例d自身当变量传入,因为他不会自己传入self #1. 注:setattr(x,’y’,z)用法: x就是实例对象 y就是在实例中调用时用的名字,z就是改变属性的值/或则要添加的函数的名字(正真的函数) #2. setattr( 具体实例名称 , ’在类中调用时使用的名称’ , 要添加的真实函数的名称) #3. 作用: setattr(d,"bulk",bulk) 将bulk方法添加到实例d中并且在实例中以bulk名称调用
class Dog(object): def __init__(self,name): self.name = name def eat(self,food): print("eat method!!!") d = Dog(‘Fly‘) #1 实例d中没有sex这个属性,就会动态添加一个属性 sex = Male setattr(d,"sex",‘Male‘) #给实例d添加一个属性:sex=Male print("将实例d添加一个新属性sex=Male:\t",d.sex) #2 如果实例d中本身存在这个属性那么 新的值就会覆盖这个属性 setattr(d,‘name‘,‘name change to jack‘) print("原本名字是Fly改变后的名字是:\t",d.name) # 运行结果: # 将实例d添加一个新属性sex=Male: Male # 原本名字是Fly改变后的名字是: name change to jack
class Dog(object): def __init__(self,name): self.name = name def eat(self,food): print("%s is eating....."%self.name) d = Dog("NiuHanYang") choice = input(">>:").strip() if hasattr(d,choice): delattr(d,choice) #使用delattr(d,choice)删除实例的属性那么所以下面打印就会报错 print(d.name) # 运行结果: # >>:name #输入的值是name # 下面是报错信息 # Traceback (most recent call last): # File "C:/Users/admin/PycharmProjects/s14/Day7/test1.py", line 10, in <module>
单例模式原理及作用
创建单例模式举例
class Foo(object): instance = None def __init__(self): self.name = ‘alex‘ def __new__(cls, *args, **kwargs): if Foo.instance: return Foo.instance else: Foo.instance = object.__new__(cls,*args,**kwargs) return Foo.instance obj1 = Foo() # obj1和obj2获取的就是__new__方法返回的内容 obj2 = Foo() print(obj1,obj2) # 运行结果: <__main__.Foo object at 0x00D3B450> <__main__.Foo object at 0x00D3B450> # 运行结果说明: # 这可以看到我们新建的两个Foo()对象内存地址相同,说明使用的•同一个类,没有重复建立类
这里介绍一个设计模式,设计模式在程序员写了两三年代码的时候,到一定境界了,才会考虑到设计模式对于程序带来的好处,从而使用各种设计模式,这里只是简单的介绍一个简单的设计模式:单例模式。在面向对象中的单例模式就是一个类只有一个对象,所有的操作都通过这个对象来完成,这就是面向对象中的单例模式,下面是实现代码:
class Foo: # 单例模式 __v=None @classmethod def ge_instance(cls): if cls.__v: return cls.__v else: cls.__v=Foo() return cls.__v obj1=Foo.ge_instance() print(obj1) obj2=Foo.ge_instance() print(obj2) obj3=Foo.ge_instance() print(obj3) 执行结果: <__main__.Foo object at 0x000001D2ABA01860> <__main__.Foo object at 0x000001D2ABA01860> <__main__.Foo object at 0x000001D2ABA01860>
可以看到,三个对象的内存地址都是一样的,其实,这三个变量中存储的都是同一个对象的内存地址,这样有什么好处呢?能够节省资源,就比如在数据库连接池的时候就可以使用单例模式,只创建一个类的对象供其他程序调用,还有在web服务中接收请求也可以使用单例模式来实现,节省资源。
原文:https://www.cnblogs.com/yangmaosen/p/12461032.html