在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作。例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问。一般而言,点(.)属性运算符比较直观,也是我们经常碰到的一种属性访问方式。然而,在点(.)属性运算符的背后却是别有洞天,值得我们对对象的属性访问进行探讨。

在进行对象属性访问的分析之前,我们需要先了解一下对象怎么表示其属性。为了便于说明,本文以新式类为例。有关新式类和旧式类的区别,大家可以查看Python官方文档。

对象的属性

Python中,“一切皆对象”。我们可以给对象设置各种属性。先来看一个简单的例子:

Python

class Animal(object):

run = True

class Dog(Animal):

fly = False

def __init__(self, age):

self.age = age

def sound(self):

return "wang wang~"

1

2

3

4

5

6

7

8

classAnimal(object):

run=True

classDog(Animal):

fly=False

def__init__(self,age):

self.age=age

defsound(self):

return"wang wang~"

上面的例子中,我们定义了两个类。类Animal定义了一个属性run;类Dog继承自Animal,定义了一个属性fly和两个函数。接下来,我们实例化一个对象。对象的属性可以从特殊属性__dict__中查看。

Python

# 实例化一个对象dog

>>> dog = Dog(1)

# 查看dog对象的属性

>>> dog.__dict__

{'age': 1}

# 查看类Dog的属性

>>> Dog.__dict__

dict_proxy({'__doc__': None,

'__init__': ,

'__module__': '__main__',

'fly': False,

'sound': })

# 查看类Animal的属性

>>> Animal.__dict__

dict_proxy({'__dict__': ,

'__doc__': None,

'__module__': '__main__',

'__weakref__': ,

'run': True})

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# 实例化一个对象dog

>>>dog=Dog(1)

# 查看dog对象的属性

>>>dog.__dict__

{'age':1}

# 查看类Dog的属性

>>>Dog.__dict__

dict_proxy({'__doc__':None,

'__init__':,

'__module__':'__main__',

'fly':False,

'sound':})

# 查看类Animal的属性

>>>Animal.__dict__

dict_proxy({'__dict__':,

'__doc__':None,

'__module__':'__main__',

'__weakref__':,

'run':True})

由上面的例子可以看出:属性在哪个对象上定义,便会出现在哪个对象的__dict__中。例如:

类Animal定义了一个属性run,那这个run属性便只会出现在类Animal的__dict__中,而不会出现在其子类中。

类Dog定义了一个属性fly和两个函数,那这些属性和方法便会出现在类Dog的__dict__中,同时它们也不会出现在实例的__dict__中。

实例对象dog的__dict__中只出现了一个属性age,这是在初始化实例对象的时候添加的,它没有父类的属性和方法。

由此可知:Python中对象的属性具有 “层次性”,属性在哪个对象上定义,便会出现在哪个对象的__dict__中。

在这里我们首先了解的是属性值会存储在对象的__dict__中,查找也会在对象的__dict__中进行查找的。至于Python对象进行属性访问时,会按照怎样的规则来查找属性值呢?这个问题在后文中进行讨论。

对象属性访问与特殊方法__getattribute__

正如前面所述,Python的属性访问方式很直观,使用点属性运算符。在新式类中,对对象属性的访问,都会调用特殊方法__getattribute__。__getattribute__允许我们在访问对象属性时自定义访问行为,但是使用它特别要小心无限递归的问题。

还是以上面的情景为例:

Python

class Animal(object):

run = True

class Dog(Animal):

fly = False

def __init__(self, age):

self.age = age

# 重写__getattribute__。需要注意的是重写的方法中不能

# 使用对象的点运算符访问属性,否则使用点运算符访问属性时,

# 会再次调用__getattribute__。这样就会陷入无限递归。

# 可以使用super()方法避免这个问题。

def __getattribute__(self, key):

print "calling __getattribute__\n"

return super(Dog, self).__getattribute__(key)

def sound(self):

return "wang wang~"

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

classAnimal(object):

run=True

classDog(Animal):

fly=False

def__init__(self,age):

self.age=age

# 重写__getattribute__。需要注意的是重写的方法中不能

# 使用对象的点运算符访问属性,否则使用点运算符访问属性时,

# 会再次调用__getattribute__。这样就会陷入无限递归。

# 可以使用super()方法避免这个问题。

def__getattribute__(self,key):

print"calling __getattribute__\n"

returnsuper(Dog,self).__getattribute__(key)

defsound(self):

return"wang wang~"

上面的例子中我们重写了__getattribute__方法。注意我们使用了super()方法来避免无限循环问题。下面我们实例化一个对象来说明访问对象属性时__getattribute__的特性。

Python

# 实例化对象dog

>>> dog = Dog(1)

# 访问dog对象的age属性

>>> dog.age

calling __getattribute__

1

# 访问dog对象的fly属性

>>> dog.fly

calling __getattribute__

False

# 访问dog对象的run属性

>>> dog.run

calling __getattribute__

True

# 访问dog对象的sound方法

>>> dog.sound

calling __getattribute__

>

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# 实例化对象dog

>>>dog=Dog(1)

# 访问dog对象的age属性

>>>dog.age

calling __getattribute__

1

# 访问dog对象的fly属性

>>>dog.fly

calling __getattribute__

False

# 访问dog对象的run属性

>>>dog.run

calling __getattribute__

True

# 访问dog对象的sound方法

>>>dog.sound

calling __getattribute__

>

由上面的验证可知,__getattribute__是实例对象查找属性或方法的入口。实例对象访问属性或方法时都需要调用到__getattribute__,之后才会根据一定的规则在各个__dict__中查找相应的属性值或方法对象,若没有找到则会调用__getattr__(后面会介绍到)。__getattribute__是Python中的一个内置方法,关于其底层实现可以查看相关官方文档,后面将要介绍的属性访问规则就是依赖于__getattribute__的。

对象属性控制

在继续介绍后面相关内容之前,让我们先来了解一下Python中和对象属性控制相关的相关方法。

__getattr__(self, name)__getattr__可以用来在当用户试图访问一个根本不存在(或者暂时不存在)的属性时,来定义类的行为。前面讲到过,当__getattribute__方法找不到属性时,最终会调用__getattr__方法。它可以用于捕捉错误的以及灵活地处理AttributeError。只有当试图访问不存在的属性时它才会被调用。

__setattr__(self, name, value)__setattr__方法允许你自定义某个属性的赋值行为,不管这个属性存在与否,都可以对任意属性的任何变化都定义自己的规则。关于__setattr__有两点需要说明:第一,使用它时必须小心,不能写成类似self.name = “Tom”这样的形式,因为这样的赋值语句会调用__setattr__方法,这样会让其陷入无限递归;第二,你必须区分 对象属性 和 类属性 这两个概念。后面的例子中会对此进行解释。

__delattr__(self, name)__delattr__用于处理删除属性时的行为。和__setattr__方法要注意无限递归的问题,重写该方法时不要有类似del self.name的写法。

还是以上面的例子进行说明,不过在这里我们要重写三个属性控制方法。

Python

class Animal(object):

run = True

class Dog(Animal):

fly = False

def __init__(self, age):

self.age = age

def __getattr__(self, name):

print "calling __getattr__\n"

if name == 'adult':

return True if self.age >= 2 else False

else:

raise AttributeError

def __setattr__(self, name, value):

print "calling __setattr__"

super(Dog, self).__setattr__(name, value)

def __delattr__(self, name):

print "calling __delattr__"

super(Dog, self).__delattr__(name)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

classAnimal(object):

run=True

classDog(Animal):

fly=False

def__init__(self,age):

self.age=age

def__getattr__(self,name):

print"calling __getattr__\n"

ifname=='adult':

returnTrueifself.age>=2elseFalse

else:

raiseAttributeError

def__setattr__(self,name,value):

print"calling __setattr__"

super(Dog,self).__setattr__(name,value)

def__delattr__(self,name):

print"calling __delattr__"

super(Dog,self).__delattr__(name)

以下进行验证。首先是__getattr__:

Python

# 创建实例对象dog

>>> dog = Dog(1)

calling __setattr__

# 检查一下dog和Dog的__dict__

>>> dog.__dict__

{'age': 1}

>>> Dog.__dict__

dict_proxy({'__delattr__': ,

'__doc__': None,

'__getattr__': ,

'__init__': ,

'__module__': '__main__',

'__setattr__': ,

'fly': False})

# 获取dog的age属性

>>> dog.age

1

# 获取dog的adult属性。

# 由于__getattribute__没有找到相应的属性,所以调用__getattr__。

>>> dog.adult

calling __getattr__

False

# 调用一个不存在的属性name,__getattr__捕获AttributeError错误

>>> dog.name

calling __getattr__

Traceback (most recent call last):

File "", line 1, in

File "", line 10, in __getattr__

AttributeError

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

# 创建实例对象dog

>>>dog=Dog(1)

calling __setattr__

# 检查一下dog和Dog的__dict__

>>>dog.__dict__

{'age':1}

>>>Dog.__dict__

dict_proxy({'__delattr__':,

'__doc__':None,

'__getattr__':,

'__init__':,

'__module__':'__main__',

'__setattr__':,

'fly':False})

# 获取dog的age属性

>>>dog.age

1

# 获取dog的adult属性。

# 由于__getattribute__没有找到相应的属性,所以调用__getattr__。

>>>dog.adult

calling __getattr__

False

# 调用一个不存在的属性name,__getattr__捕获AttributeError错误

>>>dog.name

calling __getattr__

Traceback(most recent call last):

File"",line1,in

File"",line10,in__getattr__

AttributeError

可以看到,属性访问时,当访问一个不存在的属性时触发__getattr__,它会对访问行为进行控制。接下来是__setattr__:

Python

# 给dog.age赋值,会调用__setattr__方法

>>> dog.age = 2

calling __setattr__

>>> dog.age

2

# 先调用dog.fly时会返回False,这时因为Dog类属性中有fly属性;

# 之后再给dog.fly赋值,触发__setattr__方法。

>>> dog.fly

False

>>> dog.fly = True

calling __setattr__

# 再次查看dog.fly的值以及dog和Dog的__dict__;

# 可以看出对dog对象进行赋值,会在dog对象的__dict__中添加了一条对象属性;

# 然而,Dog类属性没有发生变化

# 注意:dog对象和Dog类中都有fly属性,访问时会选择哪个呢?

>>> dog.fly

True

>>> dog.__dict__

{'age': 2, 'fly': True}

>>> Dog.__dict__

dict_proxy({'__delattr__': ,

'__doc__': None,

'__getattr__': ,

'__init__': ,

'__module__': '__main__',

'__setattr__': ,

'fly': False})

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

# 给dog.age赋值,会调用__setattr__方法

>>>dog.age=2

calling __setattr__

>>>dog.age

2

# 先调用dog.fly时会返回False,这时因为Dog类属性中有fly属性;

# 之后再给dog.fly赋值,触发__setattr__方法。

>>>dog.fly

False

>>>dog.fly=True

calling __setattr__

# 再次查看dog.fly的值以及dog和Dog的__dict__;

# 可以看出对dog对象进行赋值,会在dog对象的__dict__中添加了一条对象属性;

# 然而,Dog类属性没有发生变化

# 注意:dog对象和Dog类中都有fly属性,访问时会选择哪个呢?

>>>dog.fly

True

>>>dog.__dict__

{'age':2,'fly':True}

>>>Dog.__dict__

dict_proxy({'__delattr__':,

'__doc__':None,

'__getattr__':,

'__init__':,

'__module__':'__main__',

'__setattr__':,

'fly':False})

实例对象的__setattr__方法可以定义属性的赋值行为,不管属性是否存在。当属性存在时,它会改变其值;当属性不存在时,它会添加一个对象属性信息到对象的__dict__中,然而这并不改变类的属性。从上面的例子可以看出来。

最后,看一下__delattr__:

Python

# 由于上面的例子中我们为dog设置了fly属性,现在删除它触发__delattr__方法

>>> del dog.fly

calling __delattr__

# 再次查看dog对象的__dict__,发现和fly属性相关的信息被删除

>>> dog.__dict__

{'age': 2}

1

2

3

4

5

6

# 由于上面的例子中我们为dog设置了fly属性,现在删除它触发__delattr__方法

>>>deldog.fly

calling __delattr__

# 再次查看dog对象的__dict__,发现和fly属性相关的信息被删除

>>>dog.__dict__

{'age':2}

描述符

描述符是Python 2.2 版本中引进来的新概念。描述符一般用于实现对象系统的底层功能, 包括绑定和非绑定方法、类方法、静态方法特特性等。关于描述符的概念,官方并没有明确的定义,可以在网上查阅相关资料。这里我从自己的认识谈一些想法,如有不当之处还请包涵。

在前面我们了解了对象属性访问和行为控制的一些特殊方法,例如__getattribute__、__getattr__、__setattr__、__delattr__。以我的理解来看,这些方法应当具有属性的”普适性”,可以用于属性查找、设置、删除的一般方法,也就是说所有的属性都可以使用这些方法实现属性的查找、设置、删除等操作。但是,这并不能很好地实现对某个具体属性的访问控制行为。例如,上例中假如要实现dog.age属性的类型设置(只能是整数),如果单单去修改__setattr__方法满足它,那这个方法便有可能不能支持其他的属性设置。

在类中设置属性的控制行为不能很好地解决问题,Python给出的方案是:__getattribute__、__getattr__、__setattr__、__delattr__等方法用来实现属性查找、设置、删除的一般逻辑,而对属性的控制行为就由属性对象来控制。这里单独抽离出来一个属性对象,在属性对象中定义这个属性的查找、设置、删除行为。这个属性对象就是描述符。

描述符对象一般是作为其他类对象的属性而存在。在其内部定义了三个方法用来实现属性对象的查找、设置、删除行为。这三个方法分别是:

get(self, instance, owner):定义当试图取出描述符的值时的行为。

set(self, instance, value):定义当描述符的值改变时的行为。

delete(self, instance):定义当描述符的值被删除时的行为。

其中:instance为把描述符对象作为属性的对象实例;

owner为instance的类对象。

以下以官方的一个例子进行说明:

Python

class RevealAccess(object):

def __init__(self, initval=None, name='var'):

self.val = initval

self.name = name

def __get__(self, obj, objtype):

print 'Retrieving', self.name

return self.val

def __set__(self, obj, val):

print 'Updating', self.name

self.val = val

class MyClass(object):

x = RevealAccess(10, 'var "x"')

y = 5

1

2

3

4

5

6

7

8

9

10

11

12

13

classRevealAccess(object):

def__init__(self,initval=None,name='var'):

self.val=initval

self.name=name

def__get__(self,obj,objtype):

print'Retrieving',self.name

returnself.val

def__set__(self,obj,val):

print'Updating',self.name

self.val=val

classMyClass(object):

x=RevealAccess(10,'var "x"')

y=5

以上定义了两个类。其中RevealAccess类的实例是作为MyClass类属性x的值存在的。而且RevealAccess类定义了__get__、__set__方法,它是一个描述符对象。注意,描述符对象的__get__、__set__方法中使用了诸如self.val和self.val = val等语句,这些语句会调用__getattribute__、__setattr__等方法,这也说明了__getattribute__、__setattr__等方法在控制访问对象属性上的一般性(一般性是指对于所有属性它们的控制行为一致),以及__get__、__set__等方法在控制访问对象属性上的特殊性(特殊性是指它针对某个特定属性可以定义不同的行为)。

以下进行验证:

Python

# 创建Myclass类的实例m

>>> m = MyClass()

# 查看m和MyClass的__dict__

>>> m.__dict__

{}

>>> MyClass.__dict__

dict_proxy({'__dict__': ,

'__doc__': None,

'__module__': '__main__',

'__weakref__': ,

'x': <__main__.RevealAccess at 0x5130080>,

'y': 5})

# 访问m.x。会先触发__getattribute__方法

# 由于x属性的值是一个描述符,会触发它的__get__方法

>>> m.x

Retrieving var "x"

10

# 设置m.x的值。对描述符进行赋值,会触发它的__set__方法

# 在__set__方法中还会触发__setattr__方法(self.val = val)

>>> m.x = 20

Updating var "x"

# 再次访问m.x

>>> m.x

Retrieving var "x"

20

# 查看m和MyClass的__dict__,发现这与对描述符赋值之前一样。

# 这一点与一般属性的赋值不同,可参考上述的__setattr__方法。

# 之所以前后没有发生变化,是因为变化体现在描述符对象上,

# 而不是实例对象m和类MyClass上。

>>> m.__dict__

{}

>>> MyClass.__dict__

dict_proxy({'__dict__': ,

'__doc__': None,

'__module__': '__main__',

'__weakref__': ,

'x': <__main__.RevealAccess at 0x5130080>,

'y': 5})

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

# 创建Myclass类的实例m

>>>m=MyClass()

# 查看m和MyClass的__dict__

>>>m.__dict__

{}

>>>MyClass.__dict__

dict_proxy({'__dict__':,

'__doc__':None,

'__module__':'__main__',

'__weakref__':,

'x':<__main__.RevealAccess at0x5130080>,

'y':5})

# 访问m.x。会先触发__getattribute__方法

# 由于x属性的值是一个描述符,会触发它的__get__方法

>>>m.x

Retrieving var"x"

10

# 设置m.x的值。对描述符进行赋值,会触发它的__set__方法

# 在__set__方法中还会触发__setattr__方法(self.val = val)

>>>m.x=20

Updating var"x"

# 再次访问m.x

>>>m.x

Retrieving var"x"

20

# 查看m和MyClass的__dict__,发现这与对描述符赋值之前一样。

# 这一点与一般属性的赋值不同,可参考上述的__setattr__方法。

# 之所以前后没有发生变化,是因为变化体现在描述符对象上,

# 而不是实例对象m和类MyClass上。

>>>m.__dict__

{}

>>>MyClass.__dict__

dict_proxy({'__dict__':,

'__doc__':None,

'__module__':'__main__',

'__weakref__':,

'x':<__main__.RevealAccess at0x5130080>,

'y':5})

上面的例子对描述符进行了一定的解释,不过对描述符还需要更进一步的探讨和分析,这个工作先留待以后继续进行。

最后,还需要注意一点:描述符有数据描述符和非数据描述符之分。

只要至少实现__get__、__set__、__delete__方法中的一个就可以认为是描述符;

只实现__get__方法的对象是非数据描述符,意味着在初始化之后它们只能被读取;

同时实现__get__和__set__的对象是数据描述符,意味着这种属性是可读写的。

属性访问的优先规则

在以上的讨论中,我们一直回避着一个问题,那就是属性访问时的优先规则。我们了解到,属性一般都在__dict__中存储,但是在访问属性时,在对象属性、类属型、基类属性中以怎样的规则来查询属性呢?以下对Python中属性访问的规则进行分析。

由上述的分析可知,属性访问的入口点是__getattribute__方法。它的实现中定义了Python中属性访问的优先规则。Python官方文档中对__getattribute__的底层实现有相关的介绍,本文暂时只是讨论属性查找的规则,相关规则可见下图:

上图是查找b.x这样一个属性的过程。在这里要对此图进行简单的介绍:

查找属性的第一步是搜索基类列表,即type(b).__mro__,直到找到该属性的第一个定义,并将该属性的值赋值给descr;

判断descr的类型。它的类型可分为数据描述符、非数据描述符、普通属性、未找到等类型。若descr为数据描述符,则调用desc.__get__(b, type(b)),并将结果返回,结束执行。否则进行下一步;

如果descr为非数据描述符、普通属性、未找到等类型,则查找实例b的实例属性,即b.__dict__。如果找到,则将结果返回,结束执行。否则进行下一步;

如果在b.__dict__未找到相关属性,则重新回到descr值的判断上。

若descr为非数据描述符,则调用desc.__get__(b, type(b)),并将结果返回,结束执行;

若descr为普通属性,直接返回结果并结束执行;

若descr为空(未找到),则最终抛出 AttributeError 异常,结束查找。

python描述符与实例属性_Python 中的属性访问与描述符相关推荐

  1. python 类可以调用实例变量_python中的实例方法、静态方法、类方法、类变量和实例变量浅析...

    注:使用的是Python2.7. 一.实例方法 实例方法就是类的实例能够使用的方法.如下: class Foo: def __init__(self, name): self.name = name ...

  2. python的name属性_Python中__name__属性的妙用

    在Python中,每一个module文件都有一个built-in属性:__name__,这个__name__有如下特点: 1 如果这个module文件是被别的文件导入的,那么,该__name__属性的 ...

  3. Python基础_第3章_Python中的循环结构

    Python基础_第3章_Python中的循环结构 文章目录 Python基础_第3章_Python中的循环结构 Python中的循环结构 一.回顾分支练习题 1.判断是否为一个合法三角形 2.求世界 ...

  4. Python基础_第5章_Python中的数据序列

    Python基础_第5章_Python中的数据序列 文章目录 Python基础_第5章_Python中的数据序列 Python中的数据序列 一.字典--Python中的==查询==神器 1.为什么需要 ...

  5. python选取元音开头的单词_Python中的Regex,用于查找遵循以下模式的单词:元音、辅音、元音、辅音...

    如果将辅音有向图映射成单个辅音,则最长的单词是解剖病理学的10*VC字符串. 如果您正确映射y,那么您将得到完整的字符串,如乙酰丙酮作为8*VC,下胚轴作为8*CV. 如果不需要字符串是完整的,那么在 ...

  6. python实例属性与类属性_Python中的类属性和实例属性引发的一个坑-续

    上篇文章Python 中的类属性和实例属性,我们探讨了类属性和实例属性引发的一个小坑.总结了类属性和实例属性的区别如下:类属性可以被类和实例调用,实例属性只能被实例调用 类属性不会随着实例的调用而改变 ...

  7. python程序实例讲解_Python编程之属性和方法实例详解

    本文实例讲述了Python编程中属性和方法使用技巧.分享给大家供大家参考.具体分析如下: 一.属性 在python中,属性分为公有属性和私有属性,公有属性可以在类的外部调用,私有属性不能在类的外部调用 ...

  8. python私有属性怎么定义_Python中私有属性的定义方式

    Python没有类似于Java的private关键字, 但也可以为类定义私有属性. 只需将属性命名变为以__开头, 例如 __field. 示例代码: class Vector2D(object): ...

  9. 基于python渗透测试_Python中基于属性的测试简介

    基于python渗透测试 by Shashi Kumar Raja 由Shashi Kumar Raja Python中基于属性的测试简介 (Intro to property-based testi ...

最新文章

  1. 专访刘刚:360手机卫士的性能监控与优化
  2. 谷歌施密特:美人才签证政策让硅谷转移到中国
  3. git 恢复误删的分支
  4. spring service 怎么拿到数据源信息_SSM(SpringMVC + Spring + MyBatis)中各层作用及关系Ⅰ...
  5. discuz 二次开发
  6. 活动推荐丨阿里云TechInsight论坛为什么这么火?
  7. 阿里云多账号管控与网络安全集中化管理能力升级发布
  8. matlab井深测量,一种井深测量系统及方法与流程
  9. 数字调色盘【RGB和16位】
  10. 常用的linux文件权限
  11. 最大似然估计的缺陷 —— 方差和均值的 bias
  12. 无法访问移动磁盘显示磁盘未被格式化的文件寻回方案
  13. python基础5-序列思维脑图
  14. 服务中没有listen_Odoo 中的 IM(即时通讯)实现分析
  15. 软件multisim的安装教程
  16. phpstudy如何创建mysql_PHPStudy怎样创建数据库
  17. 搭建sql注入平台及DVWA漏洞环境
  18. 关闭Win10自动更新
  19. 华为系列服务器账号密码,常用设备管理口默认用户名密码汇总
  20. (附源码)计算机毕业设计SSM游泳馆管理平台

热门文章

  1. 员工一言不合就离职怎么办?用 Python 写了个员工流失预测模型
  2. 第二十二届中国科协年会开幕,百度CTO王海峰等共话产业发展机遇
  3. 拼多多公布新iPhone SE补贴后价格:2899元起;BOSS直聘回应“App崩了”;Chrome 新测试版发布|极客头条...
  4. 从青铜到王者,来聊聊 Synchronized 底层实现原理 | 原力计划
  5. 用Python爬取3万多条评论,看韩国人如何评价电影《寄生虫》?
  6. “我在小公司混,有没有资格去知名技术大会上做分享?”
  7. 逃离泄露事件,阿里云安全默认防御大揭秘 | 问底中国 IT 技术演进
  8. AI 如何应用于油气勘探?
  9. 微软开源项目 NeuronBlocks:像搭积木一样构建 NLP 深度学习模型!
  10. 如何用 Linux 技巧大大提高工作效率?