|
class Alipay(): def pay(self,money): print('已经使用支付宝支付了%s' % money) class Applepay(): def fuqian(self,money): print('已经使用Applepay支付了%s' % money) def pay(pay_obj,money): # 统一支付入口 归一化设计 pay_obj.pay(money) pay()
多态:一类事物有多种形态,例如Animal有人狗猪等多种形态
多态性:是指在不考虑实例类型的情况下使用实例
python 天生支持多态,动态强类型的语言,崇尚鸭子类型
鸭子类型:不崇尚根据继承所得来的相似,只是根据自己实现我自己的代码就可以,如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
index tuple这种相似是根据自己写代码的时候约束的,而不是通过父类约束的
优点:松耦合,每个相似的类之间都没有影响
缺点:太随意了,只能靠自觉
# list tuple class List: def __len__(self):pass class Tuple: def __len__(self):pass def len(l_t): return l_t.__len__() l = List() print(len(l))
python中有鸭子类型,接口类和抽象类在python中的应用点并不是非常必要的
广义上面向对象的封装:代码的保护,面向对象的思想本身就是一种封装,之让自己的对象能调用自己类中的方法。
侠义的封装:面向对象的三大特性之一,属性和方法都藏起来,不让人看到。
class Person: __key = 123 # 私有静态属性 def __init__(self,name,passwd): self.name = name self.__passwd = passwd #私有属性 def get_pwd(self): print(self.__dict__) return self.__passwd # 只要在类的内部使用私有属性,就会自动的带上_类名 def login(self): self.__get_pwd() alex = Person('alex','alex3714') # print(alex.__passwd) # 不想让别人看到密码 print(alex.__dict__) print(alex._Person__passwd) # _类名__属性名,可以调到密码,不能这样用,在代码级别就变得比较私有了 print(alex.get_pwd()) alex.__high = 1 print(alex.get_pwd()) print(alex.__high) # 在类的外部定义私有属性,不顶用,可以直接调用 ''' {'name': 'alex', '_Person__passwd': 'alex3714'} alex3714 {'name': 'alex', '_Person__passwd': 'alex3714'} alex3714 {'name': 'alex', '_Person__passwd': 'alex3714', '__high': 1} alex3714 1 '''
所有的私有 都是在变量的左边加上双下划线
所有的私有 都不能在外部使用,即使知道了投机倒把的方法,也不能在类的外部使用
对象的私有属性
类中的私有方法
类中的静态属性
class A(object): a = 0 name = None b = 1 def __init__(self,name): self.a = 2 self.b = 3 self.name = name def test(self): print ('a normal func.') class B(A): def test_B(self): print ('func named test_B') obj = A('Tom') obj1 = B('Jerry') print (A.__dict__) print (obj.__dict__) print (obj.__dict__['name']) print (B.__dict__) print (obj1.__dict__) #执行结果如下 {'__module__': '__main__', 'a': 0, 'name': None, 'b': 1, '__init__': <function A.__init__ at 0x00000200C2D61840>, 'test': <function A.test at 0x00000200C2D618C8>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None} {'a': 2, 'b': 3, 'name': 'Tom'} Tom #可以通过键来获取对象__dict__属性中的值 {'__module__': '__main__', 'test_B': <function B.test_B at 0x00000200C2D61950>, '__doc__': None} {'a': 2, 'b': 3, 'name': 'Jerry'}
在python中只要有__名字,就把这个名字私有化了,就不能从类的外部直接调用了。
静态属性、方法、对象属性都可以私有化,这种私有化只是从代码级别做了变形,并没有真的约束
变形机制:__类名,__名字,在类外用不能调用,在类的内部直接__名字调用
class Room: def __init__(self,name,length,width): self.name = name self.__length = length self.__width = width def get_name(self): return self.__name def set_name(self,newName): if type(newName) is str and newName.isdigit() == False: self.__name = newName else: print('不合法的姓名') def area(self): return self.__length * self.__width jin = Room('金老板',2,1) print(jin.area()) jin.set_name('2') print(jin.name) ''' 2 不合法的姓名 金老板 '''
# 假设父类的私有属性 能被子类调用吗?不能 class Foo: __key = '123' # 变形成了_Foo__key class Son(Foo): print(Foo.__key) # 发生了变形,变成了_Son__key ''' print(Foo.__key) AttributeError: type object 'Foo' has no attribute '_Son__key' '''
会用到私有这个概念的场景:
隐藏起来一个属性,不想让类的外部调用
我想保护这个属性,不想让属性随意被改变
我先给保护这个属性,不想子类继承
from math import pi class Circle: def __init__(self,r): self.r = r def perimeter(self): return 2*pi*self.r def area(self): return pi*self.r**2 c1 = Circle(5) print(c1.area()) print(c1.perimeter())
使用property改进:
from math import pi class Circle: def __init__(self,r): self.r = r @property def perimeter(self): return 2*pi*self.r @property def area(self): return pi*self.r**2 c1 = Circle(5) print(c1.area) # 借助@property将方法伪装成一个属性,调用方法的时候需要加括号,调用属性的不用 print(c1.perimeter)
借助property将方法伪装成一个属性,调用方法的时候需要加括号,调用属性的时候不用property
class Person: def __init__(self,name): self.__name=name def name(self): return self.__name + 'sb' tiger = Person('泰哥') print(tiger.name()) tiger.name = '全班' print(tiger.name) # 无法更改 ''' 泰哥sb 全班 '''
改进
class Person: def __init__(self,name): self.__name=name @property def name(self): return self.__name + 'sb' @name.setter def name(self,new_name): self.__name = new_name tiger = Person('泰哥') print(tiger.name) tiger.name = '全班' print(tiger.name) ''' 泰哥sb 全班sb '''
class Goods: discount = 0.5 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price*Goods.discount apple = Goods('苹果',5) print(apple.price) # 2.5
# 属性 查看 修改 删除 class Person: def __init__(self,name): self.__name=name @property def name(self): return self.__name @name.deleter #deleter只是和del互相关联 def name(self): del self.__name @name.setter def name(self,new_name): self.__name = new_name brother2 = Person('二哥') print(brother2.name) del brother2.name print(brother2.name)
class Goods: __discount = 0.5 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price*Goods.__discount @classmethod #把一个方法编程一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象,即不实例化对象仍然可以操作值 def change_discount(cls,new_discount): #修改折扣 cls.__discount = new_discount apple = Goods('苹果',5) print(apple.price) apple.change_discount(0.8) print(apple.price) ''' 2.5 4.0 '''
classmethod,把一个方法编程到一个类中的方法,这个方法就可以直接被类调用,不需要依托任何对象,即,不需要实例化对象仍然可以使用。当一个方法的操作只涉及静态属性的时候就应该使用classmethod来修饰这个方法。
class Login: def __init__(self,name,password): self.name = name self.pwd = password def login(self):pass @staticmethod def get_usr_pwd(): # 静态方法 usr = input('用户名:') pwd = input('密码:') Login(usr,pwd) Login.get_usr_pwd()
在完全面向对象的程序中,如果一个函数既和对象没有关系,也和类没有关系,那么就用staticmethod函数将这个函数编程成一个静态方法。
python staticmethod 返回函数的静态方法。
该方法不强制要求传递参数,如下声明一个静态方法:
class C(object): @staticmethod def f(arg1, arg2, ...): ...
以上实例声明了静态方法 f,从而可以实现实例化使用 C().f(),当然也可以不实例化调用该方法 C.f()。
staticmethod(function)
参数说明:
无
#!/usr/bin/python# -*- coding: UTF-8 -*- class C(object): @staticmethod def f(): print('runoob'); C.f(); # 静态方法无需实例化cobj = C()cobj.f() # 也可以实例化后调用
以上实例输出结果为:
runoob runoob
类方法和静态方法都是类调用的
对象可以调用类方法和静态方法吗?可以,一般情况下,推荐用类名调用
类方法有一个默认参数,cls代表这个类
静态方法没有默认的参数,就像函数一样,不必传self参数。
反射是个很重要的概念,它可以把字符串映射到实例的变量或者实例的方法,然后可以取执行调用、修改等操作。它有四个重要的方法:
getattr 获取指定字符串名称的对象属性
setattr 为对象设置一个对象
hasattr判断对象是否有对应的对象(字符串)
delattr 删除指定属性
attr是属性英文的前几个字母,属性指的是类中类变量、实例变量和方法。但是注意不能是私有的,如果你的变量是以'__'开头的,那将无法获取。
反射常常用在动态加载模块的场景中
class Teacher: dic = { '查看学生信息':'', '查看讲师信息':'' } def show_student(self): print('show_student') def show_teacher(self): print('show_teacher') @classmethod def func(cls): print('hahaha') # hasattr getattr delattr ret = getattr(Teacher,'dic') # Teacher.dic #类.属性 print(ret) ret2 = getattr(Teacher,'func') #类.方法 Teacher.func print(ret2()) # menu = Teacher.dic # for k in menu: # print(k) if hasattr(Teacher,'dic4'): # hasattr和getattr经常配套使用 ret = getattr(Teacher,'dic4') ''' {'查看学生信息': '', '查看讲师信息': ''} hahaha None '''
class Teacher: dic = { '查看学生信息':'show_student', '查看讲师信息':'show_teacher' } def show_student(self): print('show_student') def show_teacher(self): print('show_teacher') @classmethod def func(cls): print('hahaha') alex = Teacher() # alex.show_student() func = getattr(alex,'show_student') func() ''' show_student '''
class Teacher: dic = { '查看学生信息':'show_student', '查看讲师信息':'show_teacher' } def show_student(self): print('show_student') def show_teacher(self): print('show_teacher') @classmethod def func(cls): print('hahaha') alex = Teacher() for k in Teacher.dic: print(k) key = input('请输入需求:') print(Teacher.dic[key]) if hasattr(alex,Teacher.dic[key]): func = getattr(alex,Teacher.dic[key]) func() ''' 查看学生信息 查看讲师信息 请输入需求:查看学生信息 show_student show_student '''
Archiver|手机版|科学网 ( 京ICP备07017567号-12 )
GMT+8, 2024-9-27 06:24
Powered by ScienceNet.cn
Copyright © 2007- 中国科学报社