Python高级知识点学习(三)
mro算法
类属性和实例属性的查找顺序
- 何为类属性:定义在类内部的的一些变量或者方法,都统称为类属性
- 何为实例属性:定义在对象内部的的一些变量或者方法,都统称为实例属性
对象也就是实例的意思。
class A:
aa = 1
def __init__(self, x, y):
self.x = x
self.y = y
a = A(2, 3)
类也是对象,看上边代码,实际上有两个空间,A 和 a 两个不同的空间。
单继承时,属性查找方式,向上查找,首先查找对象里,再查找类中
在多继承时,会很复杂
python2.2之前,python里的类叫经典类,经典类继承方式如果不显式继承object,实际上是不会自动继承object,Python3中,经典类已经不存在了,都叫做新式类。
经典类中,深度优先查找 。
Python2.3之后,广度优先也没有了,至今都采用C3算法
Python3多重继承C3算法:
#新式类
class D:
pass
class E:
pass
class C(E):
pass
class B(D):
pass
class A(B, C):
pass
print(A.__mro__)
打印结果:(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>)
可以看到继承顺序是 A - B - D - C - E - object
类方法静态方法和实例方法
实例方法:实例方法很常见,通常我们在类里定义的都是实例方法,
- 只是针对于实例进行操作,实例方法中第一个参数:self,self代表的就是实例本身
静待方法:
- 带@staticmethod装饰器的方法叫静态方法,静态方法不需要接受cls或self,和普通的函数用法一样
类方法:
- 带@classmethod装饰器的方法叫做类方法,类方法第一个参数是cls,代表的是类本身,(这里的cls可以修改为任意形式的代表)
def a(self):
pass
@staticmethod
def b():
pass
@classmethod
def c(cls):
pass
Python中的私有属性
双下划綫开头表示私有属性,私有属性的访问,只能在类中的公共方法中访问,类外部防问不到,无法通过实例访问。
私有属性不仅仅是变量 还可以是函数。
class User:
def __init__(self, birthday):
self.__birthday = birthday
user = User(2000)
print(user.birthday)
运行结果:
AttributeError: 'User' object has no attribute 'birthday'
以上代码块结果就是访问不到私有属性。
但是,私有不是绝对的,只是加了一个小技巧,Python中将私有属性的访问变形成这种:
class User:
def __init__(self, birthday):
self.__birthday = birthday
user = User(2000)
print(user._User__birthday)
运行结果:
2000
可以看到,通过变量_User__birthday这个就可以访问到私有属性。
Java中的反射机制也是无法做到绝对安全的,从语言层面讲,没有绝对的私有属性,Python简单一些 Java麻烦一些。
Python自省
Python对象自省
何为自省?
自省是通过一定的机制查询到对象的内部结构
使用__dict__魔法函数,dict是用C语言写的 性能高,做了很多优化,推荐使用。
也可以使用dir() ,dir()会列出类中所有属性,推荐使用。
class Student():
def __init__(self, scool_name):
self.scool_name = scool_name
if __name__ == "__main__":
user = Student("zhao")
#通过__dict__查询属性
print(user.__dict__)
打印结果:
{'scool_name': 'zhao'}
class Student():
def __init__(self, name):
self.name = name
if __name__ == "__main__":
user = Student("zhao")
user.__dict__["school_addr"] = "北京市"
print(user.school_addr)
print(user.name)
a = [1, 2]
print(dir(a))
print(dir(user))
打印结果:
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'name', 'school_addr', 'scool_name']
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
Python中super()函数
super()就是调用父类。
class A:
def __init__(self):
print('is A')
class B(A):
def __init__(self):
print('is B')
# 在某些情况下,我们希望在运行完以上代码调用父类的init方法,一般在Python3中使用下面这种方法调用
super().__init__()
if __name__ == "__main__":
b = B()
打印结果:
is B
is A
super()就是调用父类,其实这样讲并不准确,super()函数调用其实是按照mro查找的顺序调用的。
class A:
def __init__(self):
print("A")
class B(A):
def __init__(self):
print("B")
super().__init__()
class C(A):
def __init__(self):
print("C")
super().__init__()
class D(B, C):
def __init__(self):
print("D")
super().__init__()
if __name__ == "__main__":
print(D.__mro__)
d = D()
打印结果:
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D
B
C
A
既然我们重写子类的构造函数, 为什么还要去调用super再次调用父类构造函数?
有些时候,为了使用父类中的一些已经写好的方法,所以会有使用super的情况。
上下文管理器
首先介绍下这种用法:
try:
print("code started")
raise KeyError
return 1
except KeyError as e:
print ("key error")
return 2
else:
print("other error")
return 3
finally:
print ("finally")
return 4
result = exe_try()
print (result)
运行结果:
code started
key error
finally
4
在finally语句块中的代码,不管上边代码是否发生异常都会执行finally中的代码,优先finally中的return,其次return上边的。
上下文管理器,也就是with语句,实质上就是为了解放try finally这种写法而诞生的。
上下文管理器是如何完成的呢?
python是基于协议进行编程的,上下文管理器就是一种协议:上下文管理器协议。
上下文管理器协议可以使用是因为实现了两个魔法函数:__enter__和__exit__
class Sample:
def __enter__(self):
print("enter")
# 获取资源
return self
def __exit__(self, exc_type, exc_val, exc_tb):
# 释放资源
print("exit")
def do_something(self):
print("doing something")
with Sample() as sample:
sample.do_something()
运行结果:
enter
doing something
exit
还有一种方法,可以简便的实现上下文管理器的功能:@contextlib.contextmanager 可以将一个函数变为上下文管理器
import contextlib
@contextlib.contextmanager
def file_open(file_name):
print ("file open")
yield {}
print ("file end")
with file_open("a.txt") as f_opened:
print("file processing")
运行结果:
file open
file processing
file end
@contextlib.contextmanager内部会做一些逻辑,其实是利用了生成器的特性。
关注公众号
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
Python高级知识点学习(二)
深入类和对象 鸭子类型问:什么是鸭子类型?答:当看到一只鸟走起路来像鸭子,游泳像鸭子,叫起来也像鸭子,那么这只鸟就可以被看做鸭子。(所有的类或对象,都实现了共同的方法,方法名要一样,这样的话这些类就归为一种类型,在调用时同时调用同样的方法) 在java中,要实现多态,所有子类必须继承父类并重写父类的方法;在python中,python中对象和java不同,变量是动态的可以指向任何一个类型。 class Cat(): def say(): pass class Dog(): def say(): pass class Duck(): def say(): pass 三个类共同实现同一个方法且方法名相同,就实现了多态。Python多态比Java简单正是因为python是动态语言。 抽象基类abc模块 何为抽象基类?继续用java做比较,Python这里抽象基类可以当做java中的接口,java中是无法实现多继承的,java只能继承一个类,但是可以继承多个接口,接口是不能用来实例化的;所以Python里边抽象基类也是不能实例化的。 python是动态语言,动态语言是没有变量类型的,Pytho...
-
下一篇
递归小记
来自实际遇到的一个问题,需要查找出根节点的下的所有子节点,首先想到的就是递归了,用JS写过,C#之前写了一次没写对,这次专门用心看了一下的,发现和ref关键字有关,写贴上源码: public static void InsertCmsTypeName(int typeid, ref List<string> cacheNameList) { string name = string.Empty; List<TB_CMSType> cts = CMS.GetCmsTypeForParentID(typeid); if (cts != null && cts.Count > 0) { foreach (TB_CMSType item in cts) { name = "GetSpecialProducts" + item.ID + Config.SiteID; cacheNameList.Add(name); InsertCmsTypeName(item.ID, ref cacheNameList); } } } typeid是节点id,第一...
相关文章
文章评论
共有0条评论来说两句吧...

微信收款码
支付宝收款码