Python中,一切皆对象。每个对象由:标识(identity)、类型(type)、值(value)组成。
id(obj)返回对象obj的标识;type(obj)返回对象obj的类型;print(obj)直接打印出对象obj的值。
同一运算符:is用来比较id,==用来比较值(本质是调用__eq__())。is运算符比==效率高,在变量和None进行比较时,应使用is。
在Python类中存在一些特殊方法(一般称之为魔术方法),这些方法都是 __方法__ 格式,这种方法(内置方法)在内部均有特殊含义。
专门用来定义一个类具有哪些属性的方法。
对象被从内存中销毁前,会被自动调用。
很少用,但比较重要。使用类名()创建对象时,Python解释器首先调用__new__方法为对象分配空间。
__new__是由object基类提供的内置静态方法,主要作用有2个:
class Foo(object): def init(self, name): print("第二步:初始化对象,在空对象中创建数据") self.name = name
def __new__(cls, *args, **kwargs): print("第一步:先创建空对象并返回") return object.__new__(cls)
obj = Foo("李小龙")
class Foo(object): def call(self, *args, **kwargs): print("执行call方法")
obj = Foo() obj() # 对象+()执行call方法
当使用print输出对象的时候,如果定义了__str__方法,那么就会打印从这个方法中return的数据。该方法需要返回一个字符串。 class Foo(object): def init(self, name): self.name = name
def __str__(self): return "我是{}".format(self.name)
obj = Foo('李小龙') print(obj) # 结果为:我是李小龙
__repr__这个特殊方法会在对当前对象使用repr()函数时调用,它的作用是指定对象在'交互模式'中直接输出的效果。
class Foo(object): def init(self, name, age): self.name = name self.age = age
obj = Foo('李小龙', 18) print(obj.dict)
用类名调用__dict__,会输出该类中所有类属性组成的字典;而使用类的实例对象调用__dict__,会输出所有实例属性组成的字典。
class Foo(object): def getitem(self, item): print(item)
def __setitem__(self, key, value): print(key, value) def __delitem__(self, key): print('删除')
obj = Foo() obj["x1"] # 自动触发类中__getitem__ obj['x2'] = 123 # 自动触发类中__setitem__ del obj['x3'] # 自动触发类中__delitem__
class Foo(object): def enter(self): print("进来了") return 666
def __exit__(self, exc_type, exc_val, exc_tb): print("出去了")
obj = Foo()
with obj as f: print(123) print(f)
输出结果如下:进来了 123 666 出去了
对象+值,内部会去执行对象.__add__方法,并将+后面的值当做参数传递过去。 class Foo(object): def init(self, age): self.age = age
def __add__(self, other): return self.age + other.age
obj1 = Foo(18) obj2 = Foo(20) obj = obj1 + obj2 print(obj) # 结果为:38
迭代器类型的定义:
class IT(object): # 创建迭代器类型 def init(self): self.counter = 0
def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter
obj1 = IT() v1 = next(obj1) # obj1.next() print(v1) # 结果为:1
v2 = next(obj1) print(v2) # 结果为:2
obj2 = IT() for item in obj2: print(item)
for循环内部在循环时,先执行__iter__方法,获取一个迭代器对象,然后不断执行的__next__取值(有异常StopIteration则终止循环)。
obj = func()
v1 = next(obj) print(v1) # 结果为:1
v2 = next(obj) print(v2) # 结果为:2
for item in obj: print(item)
如果按照迭代器的规定来看,其实生成器类也是一种特殊的迭代器类(生成器也是一种特殊的迭代器)。
如果一个类中有__iter__方法且返回一个迭代器对象,则称这个类创建的对象为可迭代对象。 class IT(object): # 创建迭代器类型 def init(self): self.counter = 0
def __iter__(self): return self def __next__(self): self.counter += 1 if self.counter == 3: raise StopIteration() return self.counter
class Foo(object): def iter(self): return IT()
obj = Foo() # obj 是可迭代对象 for item in obj: print(item)
如果类中存在继承关系,可以通过mro()获取当前类的继承关系。 class A(object): pass
class B(object): pass
class C(A, B): pass
print(C.mro()) print(C.mro)
输出结果如下:[<class 'main.C'>, <class 'main.A'>, <class 'main.B'>, <class 'object'>] (<class 'main.C'>, <class 'main.A'>, <class 'main.B'>, <class 'object'>)
如果用正经的C3算法规则去分析一个类继承关系有点繁琐,尤其是遇到一个复杂的类要分析很久。总结:从左到右,深度优先,大小钻石,留住顶端,基于这句话可以更快的找到继承关系。
类属性是针对类对象定义的属性,类方法是针对类对象定义的方法。语法如下: class Tool(): count = 0 # 类属性 @classmethod # 类方法,用修饰器@classmethod来标识 def show_count(cls): print(f'工具对象的数量为 {cls.count}')
def __init__(self, name): self.name = name Tool.count += 1
tool = Tool('斧头') tool2 = Tool('锯子')
Tool.show_count()
如果类中封装的一个方法:
这个时候,就可以把这个方法封装成一个静态方法。静态方法既不需要传递类对象也不需要传递实例对象,有利于减少不必要的内存占用和性能消耗。
静态方法用修饰器@staticmethod来标识:
class Tool(): @staticmethod def show(): print('工具对象') def init(self, name): self.name = name # 创建工具对象 tool = Tool('斧头') # 调用类方法 Tool.show()
让类创建的对象,在系统中只有唯一的一个实例,即单例。实现步骤为:
class Tool(): instance = None def new(cls, *args, **kwargs): if cls.instance is None: cls.instance = super().new(cls) return cls.instance
tool = Tool() tool2 = Tool() print(tool) print(tool2)
每次使用类名()创建对象时,Python解释器会自动调用两个方法:new、init。要让初始化动作只被执行一次,实现步骤为:
class Tool(): instance = None init_flag = False
def __new__(cls, *args, **kwargs): if cls.instance is None: cls.instance = super().__new__(cls) return cls.instance def __init__(self): if Tool.init_flag: return print('初始化') Tool.init_flag = True
tool = Tool() tool2 = Tool() print(tool) print(tool2)
Python内置的@property装饰器负责把一个方法变成属性调用。 class Square: def init(self, w, h): self.__height = h self.__width = w
def set_side(self, new_side): self.__height = new_side self.__width = new_side @property def height(self): return self.__height @height.setter def height(self, new_value): if new_value >= 0: self.__height = new_value else: raise Exception("Value must be larger than 0")
s = Square(2, 2) print(s.height) # 2 s.height = 5 print(s.height) # 5
把一个getter方法变成属性,只需要加上@property就可以了。此时,@property本身又创建了另一个装饰器@height.setter,负责把一个setter方法变成属性赋值。
只定义getter方法,不定义setter方法就是一个只读属性。
class A: def init(self): self.__age = 0
def get_age(self): return self.__age def set_age(self, age): if age < 0 or age > 120: raise ValueError("Invalid age") self.__age = age # 类属性方式的property属性 age = property(get_age, set_age)
a = A() print(a.age) # 0 a.age = 25 print(a.age) # 25
多态是指同一个方法调用由于对象不同可能会产生不同的行为。关于多态要注意以下2点:
默认情况下,Python不提供抽象类,但abc模块为定义抽象基类提供了基础。抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类的抽象方法。
当需要抽象基类时,让类继承ABC(abc模块的ABC类),使用@abstractmethod声明抽象方法,那么这个类就是抽象类。
from abc import ABC, abstractmethod class Animal(ABC): def init(self, name): self.name = name @abstractmethod def speak(self): pass # 抽象类不能实例化,只能被继承,不能创建对象 # a = Animal("dog") class Dog(Animal): def speak(self): print(f"{self.name} 汪汪叫") dog = Dog("狗") dog.speak()
本文作者:a
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!