绑定方法
对象的绑定方法
在类中没有被任何装饰器修饰的方法就是 绑定到对象的方法,这类方法专门为对象定制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | class Person:     country = "China"
      def __init__(self, name, age):         self.name = name         self.age = age
      def speak(self):         print(self.name + ', ' + str(self.age))
 
  p = Person('Kitty', 18)
 
  print(p.__dict__)   print(Person.__dict__['speak'])  
   | 
 
speak即为绑定到对象的方法,这个方法不在对象的名称空间中,而是在类的名称空间中。
通过对象调用绑定到对象的方法,会有一个自动传值的过程,即自动将当前对象传递给方法的第一个参数(self,一般都叫self,也可以写成别的名称);若是使用类调用,则第一个参数需要手动传值。
1 2 3 4 5 6 7
   | p = Person('Kitty', 18)
  p.speak()  
 
    Person.speak(p)  
  | 
 
类的绑定方法
类中使用 @classmethod 修饰的方法就是绑定到类的方法。这类方法专门为类定制。通过类名调用绑定到类的方法时,会将类本身当做参数传给类方法的第一个参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   | class Operate_database():     host = '192.168.0.5'     port = '3306'     user = 'abc'     password = '123456'
      @classmethod     def connect(cls):           print(cls)         print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password)
 
  Operate_database.connect() ''' <class '__main__.Operate_database'> 192.168.0.5:3306 abc/123456 '''
   | 
 
通过对象也可以调用,只是默认传递的第一个参数还是这个对象对应的类。
1 2 3 4 5
   | Operate_database().connect()   ''' <class '__main__.Operate_database'> 192.168.0.5:3306 abc/123456 '''
   | 
 
非绑定方法
在类内部使用 @staticmethod 修饰的方法即为非绑定方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | import hashlib
 
  class Operate_database():     def __init__(self, host, port, user, password):         self.host = host         self.port = port         self.user = user         self.password = password
      @staticmethod     def get_passwrod(salt, password):         m = hashlib.md5(salt.encode('utf-8'))           m.update(password.encode('utf-8'))         return m.hexdigest()
 
  hash_password = Operate_database.get_passwrod('lala', '123456')   print(hash_password)  
 
  p = Operate_database('192.168.0.5', '3306', 'abc', '123456') hash_password = p.get_passwrod(p.user, p.password)   print(hash_password)  
   | 
 
简而言之,非绑定方法就是将普通方法放到了类的内部。
练习
假设我们现在有一个需求,需要让Mysql实例化出的对象可以从文件settings.py中读取数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
   |  IP = '1.1.1.10' PORT = 3306 NET = 27
 
  import uuid
  class Mysql:     def __init__(self, ip, port, net):         self.uid = self.create_uid()         self.ip = ip         self.port = port         self.net = net
      def tell_info(self):         """查看ip地址和端口号"""         print('%s:%s' % (self.ip, self.port))
      @classmethod     def from_conf(cls):         return cls(IP, NET, PORT)
      @staticmethod     def func(x, y):         print('不与任何人绑定')
      @staticmethod     def create_uid():         """随机生成一个字符串"""         return uuid.uuid1()
 
 
  obj = Mysql('10.10.0.9', 3307, 27) obj.tell_info()  
 
  | 
 
绑定方法小结
如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法
如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法
1 2 3 4 5 6 7
   |  obj1 = Mysql.from_conf() obj1.tell_info()  
  print(obj.tell_info)  
  print(obj.from_conf)  
 
  | 
 
非绑定方法小结
如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数
1 2 3 4 5 6 7 8 9 10
   | obj.func(1, 2)
  Mysql.func(3, 4)
 
  print(obj.func)  
  print(Mysql.func)  
  print(obj.uid)  
   | 
 
面向对象进阶小结
类的继承
继承父类,则会有父类的所有属性和方法
1 2 3 4 5 6 7 8
   | class ParentClass1(): 	pass 	 class ParentClass2(): 	pass
  class SubClass(ParentClass1,ParentClass2): 	pass
   | 
 
类的派生
继承父类的同时自己有init,然后也需要父类的init
1 2 3 4 5 6 7 8 9 10
   | class ParentClass1(): 	def __init__(self,name): 		pass 	
  class SubClass(ParentClass): 	def __init__(self,age): 		 		 		self.age = age
   | 
 
类的组合
类对象可以引用/当做参数传入/当做返回值/当做容器元素,类似于函数对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | class ParentClass1(): 	count = 0 	def __init__(self,name): 		pass
  class SubClass(ParentClass): 	def __init__(self,age): 		self.age = age	
  pc = ParentClass1() sc = SubClass()
  sc.parent_class = pc   sc.parent_class.count  
   | 
 
菱形继承问题
新式类:继承object的类,python3中全是新式类
经典类:没有继承object的类,只有python2中有
在菱形继承的时候,新式类是广度优先(老祖宗最后找);经典类深度优先(一路找到底,再找旁边的)
多态与多态性
一种事物的多种形态,动物–>人/猪/狗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
   |  import abc
  class Animal(metaclass=abc.ABCmeta): 	@abc.abstractmethod 	def eat(): 		print('eat')
  class People(Animal): 	def eat(): 		pass
  class Pig(Animal): 	def eat(): 		pass     def run():         pass
  class Dog(Animal):   	def run(): 		pass 		
  peo = People() peo.eat() peo1 = People() peo1.eat() pig = Pig() pig.eat()
  def func(obj): 	obj.eat()
  class Cat(Animal): 	def eat(): 		pass cat = Cat()
  func(cat)
 
  | 
 
鸭子类型:只要长得像鸭子,叫的像鸭子,游泳像鸭子,就是鸭子
类的封装
隐藏属性,只有类内部可以访问,类外部不可以访问
1 2 3 4 5 6 7 8 9
   | class Foo(): 	__count = 0  	 	def get_count(self): 		return self.__count 		 f = Foo() f.__count   f._Foo__count 
   | 
 
类的property特性
把方法变成属性引用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
   | class People(): 	def __init__(self,height,weight): 		self.height = height 		self.weight = weight 	 	@property 	def bmi(self): 		return weight/(height**2) 		 	@bmi.setter 	def bmi(self,value) 		print('setter')              @bmi.deleter     def bmi(self):         print('delter')
  peo = People peo.bmi
   | 
 
类与对象的绑定方法和非绑定方法
没有任何装饰器装饰的方法就是对象的绑定方法, 类能调用, 但是必须得传参给self
被 @classmethod 装饰器装饰的方法是类的绑定方法,参数写成cls, cls是类本身, 对象也能调用, 参数cls还是类本身
被 @staticmethod 装饰器装饰的方法就是非绑定方法, 就是一个普通的函数
isinstance与type
在游戏项目中,我们会在每个接口验证客户端传过来的参数类型,如果验证不通过,返回给客户端“参数错误”错误码。
这样做不但便于调试,而且增加健壮性。因为客户端是可以作弊的,不要轻易相信客户端传过来的参数。
验证类型用type函数,非常好用,比如
1 2 3
   | print(type('foo') == str)  
  print(type(2.3) in (int, float))  
  | 
 
既然有了type()来判断类型,为什么还有isinstance()呢?
一个明显的区别是在判断子类。
type()不会认为子类是一种父类类型;isinstance()会认为子类是一种父类类型。
千言不如一码。
1 2 3 4 5 6 7 8 9 10 11 12
   | class Foo(object):     pass   class Bar(Foo):     pass   print(type(Foo()) == Foo)  
  print(type(Bar()) == Foo)  
 
  print(isinstance(Bar(),Foo))  
   | 
 
需要注意的是,旧式类跟新式类的type()结果是不一样的。旧式类都是<type ‘instance’>。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   |  class A:     pass   class B:     pass   class C(object):     pass
  print('old style class',type(A()))  
  print('old style class',type(B()))  
  print('new style class',type(C()))  
  print(type(A()) == type(B()))  
 
  | 
 
注意:不存在说isinstance比type更好。只有哪个更适合需求。
issubclass
1 2 3 4 5 6 7 8 9
   | class Parent:     pass
  class Sub(Parent):     pass
 
  print(issubclass(Sub, Parent))   print(issubclass(Parent, object))  
   |