类和对象、属性和方法(变量与函数)
class Person:
uuid = "123456" # 类属性
def __init__(self, name, age, sex): # 方法
self.name = name # 对象属性
self.age = age # 对象属性
self.sex = sex # 对象属性
def walk(self, n): # 方法
print(self.name + "走路" + str(n) + "步")
def run(self):
print(str(self) + "跑路")
注:使用对象概念时,有广义和狭义之分,广义上,指Python一切皆对象,类、函数或方法、变量或属性皆为对象,狭义上,特指某场景下类实例化出来的独享。如在对象实例化p = Person("张三", 15, "男")
中,广义上,p
、Person
、"张三"
、15
、男
均为对象,狭义上,p
为对象,Person
为类。
属性分为类属性和对象属性,对象属性为对象独有,类属性为该类所有对象共享。Python中支持类属性和对象属性的动态创建和删除,正因如此,仅仅通过类定义无法分析类或对象的全部属性。
# 定义类
class Person:
uuid = "123456"
def __init__(self, name, age, sex): # 方法
self.name = name
self.age = age
self.sex = sex
def walk(self, n):
print(self.name + "走路" + str(n) + "步")
def run(self):
print(str(self) + "跑路")
# 实例化对象
a, b = Person("张三", 15, "男"), Person("洛五", 17, "女")
# 类属性方访问
print(a.uuid, b.uuid, Person.uuid) # 123456 123456 123456
Person.uuid = "654321"
print(a.uuid, b.uuid, Person.uuid) # 654321 654321 654321
# 类属性动态添加
Person.uuid2 = "uuid2"
print(a.uuid2, b.uuid2, Person.uuid2) #
# 类属性动态删除
del Person.uuid2
# print(Person.uuid2) # AttributeError: type object 'Person' has no attribute 'uuid2'.
# 对象属性访问
print(a.name, b.name) # 张三 洛五
a.name, b.name = b.name[0], a.name[0]
print(a.name, b.name) # 洛 张
# 对象属性动态创建,uuid为对象属性
a.uuid, b.uuid = "1", "2"
print(a.uuid, b.uuid, Person.uuid)
# 对象属性动态删除,打印类属性
del a.uuid, b.uuid
print(a.uuid, b.uuid, Person.uuid)
property装饰器修饰类中的方法,用于定义动态属性。
property
装饰的函数名一致,如r
,可以直接以.
访问属性,如c.r
。r
会执行r.getter
修饰的方法r
。r.setter
修饰的方法r
。r.setter
修饰的方法r
。r
名称上的一致。r.getter
修饰的方法,则获取属性r
时会执行property
修饰的函数。from math import pi
class Circle:
def __init__(self):
self.__r = 0
@property
def r(self):
print("property")
return pi
@r.getter # getter
def r(self):
print("getter")
return self.__r
@r.setter # setter
def r(self, r):
print("setter")
self.__r = r
@r.deleter
def r(self):
print("deleter")
self.__r = 0
@property
def area_property(self):
return pi * self.r ** 2
def area_func(self):
return pi * self.r ** 2
c = Circle()
print(c.r)
# getter
# 0
c.r = 3
# setter
print(c.area_property)
# getter
# 28.274333882308138
print(c.area_func())
# getter
# 28.274333882308138
del c.r
# deleter
print(c.r)
# getter
# 0
方法分为一般方法(对象方法)、类方法、静态方法。
一般方法即对象方法,默认第一个参数为该类的实例化对象。习惯上使用对象.方法(除对象参数之外的参数列表)
形式调用,调用形式直接指明对象参数,参数列表中无需手动传入,语法上支持类.方法(对象, 除对象参数之外的参数列表)
,调用形式未直接指明对象参数,需要手动传入对象,对象一般是该方法所属类的实例化对象,但允许传入任意对象。
class Person:
uuid = "123456"
def __init__(self, name, age, sex): # 方法
self.name = name
self.age = age
self.sex = sex
def walk(self, n):
print(self.name + "走路" + str(n) + "步")
def run(s): # 方法的第一个形参通常用于指向当前对象,习惯上命名为self,允许其他命名
print(str(s) + "跑路")
def run(self): # 习惯上,函数的形参一般不命名为self,允许该命名
print(str(self) + "跑路")
a, b = Person("张三", 15, "男"), Person("洛五", 17, "女")
# 方法的调用
a.walk(520) # 张三走路520步
Person.walk(a, 520) # 张三走路520步
b.run() # <__main__.Person object at 0x000001EE375447D0>跑路
Person.run(b) # <__main__.Person object at 0x000001EE375447D0>跑路
Person.run("删库") # 删库跑路,指定与Person类无关的"删库"对象
类方法是以装饰器classmethod
修饰的方法,默认第一个参数为类。类方法用于执行与对象无关的操作,若操作与对象五无关,何必实例化再调用方法。习惯上,以类.方法(除类参数之外的参数列表)
形式调用,调用形式直接指明类参数,参数列表中无需手动传入,语法上支持对象.方法(除类参数之外的参数列表)
,调用形式上并未指明类,但根据对象可以唯一确定类,同样无需手动传入类参数。
class Person:
uuid = "123456"
def __init__(self, name, age, sex): # 方法
self.name = name
self.age = age
self.sex = sex
@classmethod
def change_uuid(cls, uuid):
cls.uuid = uuid
print(f"{cls.__name__} {uuid}")
a = Person("张三", 15, "男")
a.change_uuid("123") # Person 123
Person.change_uuid("456") # Person 456
静态方法是以装饰器classmethod
修饰的方法,没有固定的对象参数或者类参数,等同于嵌套在类中但与类无关的函数,习惯上,以类.方法(参数列表)
形式调用,同样支持对象.方法(除类参数之外的参数列表)
。
class Person:
uuid = "123456"
def __init__(self, name, age, sex): # 方法
self.name = name
self.age = age
self.sex = sex
@staticmethod
def change_uuid(uuid):
Person.uuid = uuid
print(f"{Person.__name__} {uuid}")
a = Person("张三", 15, "男")
a.change_uuid("123") # Person 123
Person.change_uuid("456") # Person 456
绑定方法指绑定到对象或者类的方法,绑定方法参数列表第一个即为绑定的对象或者类,使用对象或者类调用方法可以自动将对象或者类传入方法,特别地,对象调用类方法会传入对象对应的类。类中一般方法都是绑定到对象的方法,可以使用classmethod
装饰器将方法绑定到类,可以使用staticmethod
将方法解除绑定,既不绑定对象也不绑定类。
class Person:
uuid = "123456"
def __init__(self, name, age, sex): # 方法
self.name = name
self.age = age
self.sex = sex
def walk(self, n):
print(self.name + "走路" + str(n) + "步")
@classmethod
def change_uuid1(cls, uuid):
cls.uuid = uuid
print(f"{cls.__name__} {uuid}")
@staticmethod
def change_uuid2(uuid):
Person.uuid = uuid
print(f"{Person.__name__} {uuid}")
def run(self):
print(str(self) + "跑路")
a = Person("张三", 15, "男")
print(run) #
print(a.walk) # >
print(Person.change_uuid1) # >
print(Person.change_uuid2) #
访问权限控制决定外部可以访问属性或方法与否,分为公有public和私有private.
__属性或方法名
。_类__属性或方法
形式的名字,且该转换是内部的,动态添加双下划线前缀属性或方法不会转换。class A:
__uuid = 1
def __init__(self, a, b):
self.a = a
self.__b = b
def get_b(self):
print(f"公有方法get_b -> {self.__b}")
def __get_b(self):
print(f"私有方法__get_b -> {self.__b}")
o = A("a", "b")
print(o.a) # a
# print(o.__b) # AttributeError: 'A' object has no attribute '__b'
print(o._A__b) # b
o.get_b() # 公有方法get_b -> b
# o.__get_b() # AttributeError: 'A' object has no attribute '__get_b'. Did you mean: '_A__get_b'?
o._A__get_b() # 私有方法__get_b -> b
o.__c = "c"
print(o.__c) # c
# print(o._A__c) # AttributeError: 'A' object has no attribute '_A__c'. Did you mean: '_A__b'?
o.__get_c = lambda _: "c"
print(A.__dict__)
print(o.__dict__)
o.__get_c(None)
o._A__get_c(None) # AttributeError: 'A' object has no attribute '_A__get_c'. Did you mean: '_A__get_b'?
class A:
def __init__(self):
print("A __init__")
self.func()
def func(self):
print("A func")
class B(A):
def func(self):
print("B func")
b = B() # 显然使用继承的__init__方法,调用的自己的func
# A __init__
# B func
print(b.__dict__)
print(B.__dict__)
print(A.__dict__)
多继承经典情形,菱形继承
class A:
def __init__(self):
print("A __init__")
def func(self):
print("A func")
class B(A):
def func(self):
print("B func")
class C(A):
def func(self):
print("C func")
class D(B, C):
pass
D().func()
# A __init__
# B func
某个类实例化对象时,在初始化该类中的对象属性之前应当先初始化父类定义的对象属性,否则可能出现调用继承自父类的方法时,由于父类对象属性未初始化导致方法调用异常。
初始化对象时,会调用__init__初始化方法使用,在该方法初始化对象属性之前,使用super来调用父类的初始化方法方法,同理,初始化父类对象属性之前,也会先调用父类的父类的初始化方法,依据继承关系,初始化方法会逐层调用直到调用顶层父类初始化方法执行完毕,随后次一层执行完毕,同理逐层执行完毕返回,直到再次回到这个类的初始化方法并执行完毕,此时整个初始化过程结束。
实例化链在C++
、Java
都有所体现,不同是的,Python中允许中断初始化链。
class A:
def __init__(self, a):
self.a = a
def get_a(self):
print(self.a)
class B(A):
def __init__(self, a, b):
super().__init__(a)
self.b = b
class C(A):
def __init__(self, c):
self.c = c
B(1, 2).get_a() # 1
C(1).get_a() # AttributeError: 'C' object has no attribute 'a'
Python中使用C3算法确定方法解析顺序,访问类的__mro__
属性可以获得线性序列。
class O:
def func(self):
s = "O"
print(s + "()")
return s
class A(O):
def func(self):
s = "A"
print(s + "(" + super().func() + ")" + " (注意此处,D非A父类)")
return s
class B(O):
def func(self):
s = "B"
print(s + "(" + super().func() + ")")
return s
class C(A):
def func(self):
s = "C"
print(s + "(" + super().func() + ")")
return s
class D(B):
def func(self):
s = "D"
print(s + "(" + super().func() + ")")
return s
class E(C, D):
def func(self):
s = "E"
print(s + "(" + super().func() + ")")
return s
e = E()
e.func()
# O()
# B(O)
# D(B)
# A(D) (注意此处,D非A父类)
# C(A)
# E(C)
print(E.__mro__)
# (, , , , , , )
print(E.__base__)
#
print(E.__bases__)
# (, )
print(issubclass(A, O)) # True 是否子类
print(issubclass(A, D)) # False
print(issubclass(E, A)) # True
print(isinstance(e, E)) # True 是否实例
print(isinstance(e, C)) # True
# https://zhuanlan.zhihu.com/p/151856162
# https://zh.wikipedia.org/wiki/C3%E7%BA%BF%E6%80%A7%E5%8C%96
property
python本身便是多态,没有向上转型,没有重载。
ABCMeta
元类生成。abstractmethod
装饰器修饰。from abc import abstractmethod, ABCMeta
# Abstract Base Class
class A(metaclass=ABCMeta):
@abstractmethod
def func_1(self):
pass
class A_1(A):
def func_1(self):
pass
a = A_1()
顶层父类,Python3中所有类默认继承object,Python2中可选择性继承object,不继承object的类称之为经典类,继承object的类称之为新式类,Python3中一切类均为新式类。
class object:
"""
The base class of the class hierarchy.
When called, it accepts no arguments and returns a new featureless
instance that has no instance attributes and cannot be given any.
"""
def __delattr__(self, *args, **kwargs): # real signature unknown
""" Implement delattr(self, name). """
pass
def __dir__(self, *args, **kwargs): # real signature unknown
""" Default dir() implementation. """
pass
def __eq__(self, *args, **kwargs): # real signature unknown
""" Return self==value. """
pass
def __format__(self, *args, **kwargs): # real signature unknown
""" Default object formatter. """
pass
def __getattribute__(self, *args, **kwargs): # real signature unknown
""" Return getattr(self, name). """
pass
def __getstate__(self, *args, **kwargs): # real signature unknown
""" Helper for pickle. """
pass
def __ge__(self, *args, **kwargs): # real signature unknown
""" Return self>=value. """
pass
def __gt__(self, *args, **kwargs): # real signature unknown
""" Return self>value. """
pass
def __hash__(self, *args, **kwargs): # real signature unknown
""" Return hash(self). """
pass
def __init_subclass__(self, *args, **kwargs): # real signature unknown
"""
This method is called when a class is subclassed.
The default implementation does nothing. It may be
overridden to extend subclasses.
"""
pass
def __init__(self): # known special case of object.__init__
""" Initialize self. See help(type(self)) for accurate signature. """
pass
def __le__(self, *args, **kwargs): # real signature unknown
""" Return self<=value. """
pass
def __lt__(self, *args, **kwargs): # real signature unknown
""" Return self
pass
@staticmethod # known case of __new__
def __new__(cls, *more): # known special case of object.__new__
""" Create and return a new object. See help(type) for accurate signature. """
pass
def __ne__(self, *args, **kwargs): # real signature unknown
""" Return self!=value. """
pass
def __reduce_ex__(self, *args, **kwargs): # real signature unknown
""" Helper for pickle. """
pass
def __reduce__(self, *args, **kwargs): # real signature unknown
""" Helper for pickle. """
pass
def __repr__(self, *args, **kwargs): # real signature unknown
""" Return repr(self). """
pass
def __setattr__(self, *args, **kwargs): # real signature unknown
""" Implement setattr(self, name, value). """
pass
def __sizeof__(self, *args, **kwargs): # real signature unknown
""" Size of object in memory, in bytes. """
pass
def __str__(self, *args, **kwargs): # real signature unknown
""" Return str(self). """
pass
@classmethod # known case
def __subclasshook__(cls, subclass): # known special case of object.__subclasshook__
"""
Abstract classes can override this to customize issubclass().
This is invoked early on by abc.ABCMeta.__subclasscheck__().
It should return True, False or NotImplemented. If it returns
NotImplemented, the normal algorithm is used. Otherwise, it
overrides the normal algorithm (and the outcome is cached).
"""
pass
__class__ = None # (!) forward: type, real value is ""
__dict__ = {}
__doc__ = ''
__module__ = ''
魔术方法指内置的名称中带有上下划线前后缀的方法,又称双下方法,例如__init__
。
__new__
,构造方法,用于通过类创建实例
__init__
,初始化方法,实例被创建后调用
__del__
,终结方法,使用del
将对象引用减一,引用计数为0时终结方法会被调用
__repr__
,representation,返回一个对象的正式字符串表示,通常是便于解释器理解的,在适当环境下可以基于该字符串重建对象,若不可则返回一个 <...some useful description...>
结构的表示信息。在调用内置函数repr
时调用。
__str__
,string,返回一个对象非正式的字符串表示,通常是便于人理解的。在调用内置函数str
、print
、format
时调用,若没有__str__
实现,会调用__repr__
。
s = "yuzao"
print(str(s)) # yuzao
print(repr(s)) # 'yuzao'
print(eval(repr(s))) # yuzao eval重建对象
d = [1, '2', [3]]
print(str(d)) # [1, '2', [3]]
print(repr(d)) # [1, '2', [3]]
class C:
def __init__(self, c):
self.c = c
c = C(1)
print(repr(c)) # <__main__.C object at 0x000001DB21E33C50>
__bytes__
,返回一个bytes对象。
__format__
,返回一个对象的格式化字符串,在调用内置函数format
、f-string和str.format()
方法时调用。
比较方法
使用关系运算符比较两个对象时会调用对应方法。
__lt__
,小于
__le__
,小于等于
__eq__
,等于
__ne__
,不等于
__gt__
,大于
__ge__
,大于等于
PEP 544 – Protocols: Structural subtyping (static duck typing)
协议用于描述静态鸭子类型,约定有具有双下方法的类型即为同一类型。与Java中接口的概念类似。
迭代器协议
实现__iter__
、__next__
方法的类型即为迭代器。