赞
踩
推荐类名用驼峰命名
,函数和方法用下划线命名
函数与方法的区别:函数中的数据是显式传递的;方法与对象绑定,方法中的数据是隐式传递的。
python 的 typing 中的 Union 和 Optional 区别是什么?
assert Union[str, None] == Optional[str]
Union 是 必须是其中之一
Optional 是 可以是其中之一,但也可以不是
self
代表的是类的实例,代表当前对象的地址,而 self.class
则指向类。Python 会自动绑定类方法的第一个参数指向调用该方法的对象。
class CLanguage: name = "C语言中文网" # 类变量 def __init__(self, v): CLanguage.url = "http://c.biancheng.net" # 类变量,只有实例化对象时,才会创造 self.value = v # 实例变量 def prt(self): print("prt函数:", self, self.__class__) self.temp = "Python" # 实例变量,只有调用该方法时,才会创造 def info(self): print("info函数:", self) '''dir() & __dict__ print(dir(CLanguage)) print(CLanguage.__dict__) print(dir(a)) print(a.__dict__) ''' # 内存:类{CLanguage, name="C语言中文网"}, 此时不存在类变量url a = CLanguage(1) # 类实例化为对象a # 内存:类{CLanguage name="C语言中文网", url="http://c.biancheng.net"} # 实例a{CLanguage类对象指针, value=1} print("1", CLanguage.name, id(CLanguage.name)) print("2", a.name, id(a.name)) # 通过实例a访问类变量name a.name = "Python教程" # 类变量name并没有修改,而添加一个实例变量name # 内存:类{CLanguage name="C语言中文网", url="http://c.biancheng.net"} # 实例a{CLanguage类对象指针, name="Python教程", value=1} print("3", a.name, id(a.name)) # 通过实例a访问实例变量name,屏蔽了同名类变量name a.name = "放弃Python" # 修改实例变量,通过新的实例变量地址name'掩盖原实例变量name # 实例a{CLanguage类对象指针, name'="放弃Python", value=1}, 原实例变量name并没有回收 print("4", a.name, id(a.name)) print("5", CLanguage.url, id(CLanguage.url)) CLanguage.url = "www.runoob.com" # 通过类名修改类变量,通过新的类变量地址url'掩盖原类变量url # 类{CLanguage, name="C语言中文网", url="runoob.com"} print("6", CLanguage.url, id(CLanguage.url)) print("7", a.url, id(a.url)) # 同时修改a.url b = CLanguage(2) # 类实例化为对象b # 类{CLanguage, name="C语言中文网", url="http://c.biancheng.net"} # 实例b{CLanguage类对象指针,value=2} print("8", CLanguage.url, id(CLanguage.url)) # 注意为原url的地址,由初始化决定的 print("9", b.value, id(b.value)) # 不存在类变量 CLanguage.value CLanguage.view = 2000 # 动态添加类变量 # 类{CLanguage, name="C语言中文网", url="http://c.biancheng.net", view=2000} # 实例b{CLanguage类对象指针,value=2} print("10", id(CLanguage.view), id(b.view)) b.view = 0 # 添加实例变量view,掩盖同名的类变量 del CLanguage.view # 删除类变量 print("11", b.view, id(b.view)) # 修改,删除类变量view,不会影响同名实例变量view a.prt() # 通过调用方法添加新的实例变量temp print("12", a.temp, id(a.temp)) # 动态添加实例方法 c = CLanguage(3) c.foo = info # # 使用info对clanguage的foo方法赋值(动态绑定方法) c.foo(c) # Python不会自动将调用者绑定到第一个参数, # 因此程序需要手动将调用者绑定为第一个参数 # 使用lambda表达式为clanguage对象的bar方法赋值(动态绑定方法) c.bar = lambda self: print('lambda表达式:', self, self.__class__) c.bar(c)
类方法 & 静态方法 & 实例方法
- 采用
@classmethod
修饰的方法为类方法;- 采用
@staticmethod
修饰的方法为静态方法;- 不用任何修改的方法为实例方法。
class CLanguage(object): bar = 1 # 类变量 # 实例方法,至少包含一个self参数,用于 Python 自动绑定调用此方法的实例对象 def __init__(self, name="C语言中文网", url="ttp://c.biancheng.net"): self.name = name # 实例变量 self.url = url # 实例变量 def printd(self, *arg, **kwarg): # 实例方法 print('instancecmethod:', self, self.name, self.url) # 类方法,至少需要一个cls参数,用于 Python 自动绑定给类本身 @classmethod def cmethod(cls): print('classcmethod:', cls, cls.bar) @classmethod def str_to_name_url(cls, str, *arg, **kwarg): name, url = str.split('+') return cls(name, url) # 静态方法,无类似的self, cls参数,Python 不会对它包含的参数做任何类或对象的绑定,即类的静态方法中无法调用任何类属性和类方法 # 只能通过 类名.属性 或 类名.方法 调用 @staticmethod def smethod(*arg): print('staticmethod:', CLanguage.bar, arg) if __name__ == '__main__': a = CLanguage() a.printd() # 实例方法,通常会用类对象直接调用 CLanguage.printd(a) # 类名调用实例方法,需要手动给 self 参数传值 a.__class__.printd(a) CLanguage.cmethod() # 使用类名直接调用类方法(推荐) a.cmethod() # 使用实例对象调用类方法(不推荐) str = "Python 教程+http://c.biancheng.net/python" b = CLanguage.str_to_name_url(str) b.printd() CLanguage.smethod("C语言中文网", "http://c.biancheng.net") # 使用类名直接调用静态方法 a.smethod(CLanguage.bar) # 使用类对象调用静态方法
私有类变量 & 私有实例变量 & 私有方法
class Site: def __init__(self, name=None, url=None): print('__init__() in Site') self.name = name # public 实例变量 self.__url = url # private 实例变量 def __del__(self): print('__del__() in Site') def __repr__(self): print('__repr__() in Site') return 'Site[name='+self.name+', url='+self.__url+']' def __call__(self, name, url): print('__call__() in Site') print(name, url) def __foo(self): # private 类方法 print('这是私有方法.') def foo(self): # public 类方法 print('这是公共方法.') self.__foo() class sit(Site): def __init__(self): print('__init__() in sit') def __del__(self): super().__del__() # 继承时,必须显式调用父类__del__释放继承于父类的资源 print('__del__() in sit') x = Site('菜鸟教程', 'www.runoob.com') # 实例化类 print(x) # 由于 __repr__() 方法 x.foo() # 正常输出 # x.__foo() # 报错,外部不能调用 private 方法 # print(x.__url) # 报错,实例不能访问 private 变量 # Python采用自动引用计数(ARC)的方式实现垃圾回收机制。 # 每当删除一个 Python 实例对象的引用,计数器减1。 # 当一个 Python 实例对象的计数器值为0,自动调用__del__()方法。 # y = x del x print('删除x') del y # 之后才调用 __del__ print('删除y') a = sit() del a b = Site() # 通过实现__call__(), Site 实例对象b变为可调用对象。 print(b.__call__('C语言中文网','http://c.biancheng.net')) print(b('C语言中文网','http://c.biancheng.net'))
class A:
pass
class B:
pass
class C(A, B):
pass
print('类A的所有父类:', A.__bases__)
print('类B的所有父类:', B.__bases__)
print('类C的所有父类:', C.__bases__)
print('类A的所有子类:', A.__subclasses__())
print('类B的所有子类:', B.__subclasses__())
property() 类 && @property 描述符
1. 对象方法可以像属性一样访问
class DataSet(object):
@property
def method_with_property(self): # 含有@property
return 15
def method_without_property(self): # 不含@property
return 15
l = DataSet()
print(l.method_with_property) # 加了@property后,可以用调用属性的形式来调用方法,后面不需要加()。 结果:15
print(l.method_without_property()) #没有加@property , 必须使用正常的调用方法的形式,即在后面加() 结果:15
2. 与私有属性配合使用
@property
为语法糖
可以将一个方法变成属性调用,起到检查和访问属性的作用
# 1. 常规方式 class Person(object): def __init__(self, name, age=18): self.name = name self.__age = 18 # private 实例变量,不能用(对象.__age)访问,必须调用(对象.方法)访问 def get_age(self): return self.__age def set_age(self, age): if age< 18: print('年龄必须大于18岁') return self.__age = age def del_age(self): self.__age = 18 xm = Person('xiaoming') print(xm.get_age()) xm.set_age(20) print(xm.get_age()) xm.del_age() print(xm.get_age()) # 2. @property 更简单的方式,私有属性的访问 class Persion(object): def __init__(self, name, age=18): self.name = name self.__age = age @property def age(self): """Person a private attribute""" return self.__age @age.setter def age(self, age): if age<18: print("年龄必须大于18岁") return self.__age = age return @age.deleter def age(self): self.__age = 18 xm = Persion("xiaoming") print(xm.age) xm.age = 20 print(xm.age) del xm.age print(xm.age) # 3. 添加 property类 class Person(object): def __init__(self, name, age=18): self.name = name self.__age = 18 def get_age(self): return self.__age def set_age(self, age): if age< 18: print('年龄必须大于18岁') return self.__age = age def del_age(self): self.__age = 18 age = property(get_age, set_age, del_age, "form Person age attribute") # 添加 prooerty 类 xm = Person('xiaoming') print(xm.age) xm.age = 20 print(xm.age) del xm.age print(xm.age)
super() 函数是用来调用父类的一个方法。在多继承中使用时,需要考虑 MRO(即Method Resolution Order)的问题。super() 函数获取的是 MRO 列表中的下一个类。
class A(object): def __init__(self): self.n = 10 def minus(self, m): print('minus in class A start', ' self is {0} @A.minus.format(self)'.format(self)) self.n -= m print('minus in class A end', " self.n=", self.n) class B(A): def __init__(self): self.n = 7 def minus(self, m): print('minus in class B start', ' self is {0} @B.minus.format(self)'.format(self)) super(B, self).minus(m) self.n -= 2 print('minus in class B end', " self.n=", self.n) class C(A): def __init__(self): self.n = 12 def minus(self, m): print('minus in class C start', ' self is {0} @C.minus.format(self)'.format(self)) super(C, self).minus(m) self.n -= 5 print('minus in class C end', " self.n=", self.n) class D(B, C): def __init__(self): self.n = 15 # 实例变量 def minus(self, m): print('minus in class D start', ' self is {0} @D.minus.format(self)'.format(self)) super(D, self).minus(m) self.n -= 2 print('minus in class D end', " self.n=", self.n) print('The MRO of class D is :', D.__mro__) # D.mro() d = D() d.minus(2) print(d.n)
class Bird: def isWing(self): print("鸟有翅膀") def fly(self): print("鸟会飞") class Ostrich(Bird): def fly(self): # 重写Bird类的fly()方法 print("鸵鸟不会飞") ostrich = Ostrich() # 创建Ostrich对象 ostrich.fly() # 调用 Ostrich 类中重写的 fly() 类方法 Bird.fly(ostrich) # 调用 Bird 类中的 fly() 方法, 使用类名调用时,需要手动为self参数赋值
重载运算符,指的是在类中定义并实现一个与运算符对应的处理方法,这样当类对象在进行运算符操作时,系统就会调用类中相应的方法来处理。
Python 常用重载运算符
class Vector: def __init__(self, a, b): self.a = a self.b = b def __str__(self): # 用于将值转化为字符串形式 return 'Vector(%d, %d)' % (self.a, self.b) def __add__(self, other): return Vector(self.a+other.a, self.b+other.b) def __lt__(self, other): return True if (self.a**2+self.b**2) < (other.a**2+other.b**2) else False v1 = Vector(2, 10) v2 = Vector(5, -2) print(v1<v2) print(v1+v2)
class DictDemo: def __init__(self, key, value): self.dict = {} self.dict[key] = value def __getitem__(self, key): return self.dict[key] def __setitem__(self, key, value): self.dict[key] = value def __len__(self): return len(self.dict) dictDemo = DictDemo('key0', 'value0') print(dictDemo['key0']) # value0 dictDemo['key1'] = 'value1' print(dictDemo['key1']) # value1 print(len(dictDemo)) #2
class WhoSay: def say(self, who): who.say() class CLanguage: def say(self): print("调用的是 CLanguage 类的 say 方法") class CPython(CLanguage): def say(self): print("调用的是 CPython 类的 say 方法") class CLinux(CLanguage): def say(self): print("调用的是 CLinux 类的 say 方法") a = CLanguage() a.say() a = CPython() a.say() a = CLinux() a.say() b = WhoSay() b.say(CLanguage()) b.say(CPython()) b.say(CLinux())
实例化对象个数固定的类,可以用枚举类来定义。
from enum import Enum
class Color(Enum):
# red, green, blue为枚举成员
red = 1
green = 2
blue = 3
'''
Color = Enum("Color", ('red', 'green', 'blue'))
'''
# 调用枚举成员的 3 种方式
print(Color.red, Color['red'], Color(1))
for color in Color:
print(color)
# 调用枚举成员中的 value 和 name
print(Color.red.value, Color.red.name)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。