栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

Python 对象的内部工作原理

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Python 对象的内部工作原理

Python 对象的内部工作原理
    • 1. Python 对象管理
      • 1.1 类中的对象管理
      • 1.2 类中的属性访问
      • 1.3 类中的继承
    • 2. 类和封装
      • 2.1 共有与私有
      • 2.2 @装饰器语法
      • 2.3 Properties

1. Python 对象管理

Python 的对象系统是基于字典的实现。

字典是 Python 中最常使用的数据结构,也是最重要的数据类型。

在一个模块(Python 文件中),字典储存所有的全局变量和函数。

输入以下指令可以查看储存当前文件变量或者类属性的字典。

文件名.__dict__
类名.__dict__
#或者
globals()
1.1 类中的对象管理

Python 中的对象系统是在字典上的一个额外层。

假设有一个股票类,其属性值为 name, shares, price

实例一个对象,并查看储存类属性的字典:

>>> s = Stock('GOOG', 100, 490.1)
>>> s.__dict__
{'name' : 'GOOG', 'shares' : 100, 'price': 490.1 }

由于实例对象被分配在类的self 中,还可以以下方式查看。

self.__dict__
>>>{
    'name': 'GOOG',
    'shares': 100,
    'price': 490.1
}

类字典

__class__#查看类字典

每一个实例对象的属性,储存在自己的私有字典中。

实例字典保存每个实例唯一的实例属性,而类字典保存所有实例共同共享的类属性。

class Foo(object):
     a = 13                  # Class variable
     def __init__(self,b):
         self.b = b          # Instance variable
>>> f = Foo(10)
>>> g = Foo(20)
>>> f.a          # Inspect the class variable (same for both instances)
13
>>> g.a
13
>>> f.b          # Inspect the instance variable (differs)
10
>>> g.b
20
>>> Foo.a = 42   # Change the value of the class variable
>>> f.a
42
>>> g.a
42
>>>
1.2 类中的属性访问

Python 中一般使用 . 运算符访问属性与方法。

x = obj.name          # Getting
obj.name = value      # Setting
del obj.name          # Deleting

实例的属性储存在两个地方:

  • 本地实例字典
  • 类字典

通常访问属性的顺序是先检查本地字典再检查类字典。

修改对象的操作会更新底层字典。

>>> s = Stock('GOOG', 100, 490.1)
>>> s.__dict__
{ 'name':'GOOG', 'shares': 100, 'price': 490.1 }
>>> s.shares = 50       # Setting
>>> s.date = '6/7/2007' # Setting
>>> s.__dict__
{ 'name': 'GOOG', 'shares': 50, 'price': 490.1, 'date': '6/7/2007' }
>>> del s.shares        # Deleting
>>> s.__dict__
{ 'name': 'GOOG', 'price': 490.1, 'date': '6/7/2007' }
>>>
1.3 类中的继承

类可以继承其他类。

class A(B, C):
    ...

基类存储在子类的元组中。

>>> A.__bases__
(, )
>>>

从逻辑上讲,继承类查找属性的过程如下。

首先,检查本地__dict__. 如果没有找到,请查看类的__dict__。

如果在类中找不到,请通过 . 查看基类__bases__。

读取单一继承

class A: pass
class B(A): pass
class C(A): pass
class D(B): pass
class E(D): pass

Python 的方法解析顺序储存在 MRO中:

>>> E.__mro__
(, ,
 , ,
 )
>>>

读取多重继承

class A: pass
class B: pass
class C(A, B): pass
class D(B): pass
class E(C, D): pass

Python 多重继承读取规则:

-先读取子类
-再读取父类,(如果父类有多个)始终按列出的顺序进行读取。

>>> E.__mro__
(
  ,
  ,
  ,
  ,
  ,
  )
>>>
2. 类和封装

在编写类时,通常会尝试封装内部细节。

本节介绍了一些 Python 编程习惯,包括私有变量和属性。

2.1 共有与私有

类的主要作用之一是封装对象的属性和实现内方法部细节。

然而,一个类也定义了一个与外部世界来操作对象的公共接口。

实现细节和公共接口之间的区别很重要。

在 Python 中,几乎所有关于类和对象的东西都是开放的。

  • 可以轻松检查对象内部。
  • 可以随意改变事物。
  • 没有严格的访问控制概念(即私有类成员)。

任何带有前导的属性名称 _ 都被认为是私有的。

class Person(object):
    def __init__(self, name):
        self._name = 0

这只是一种编程风格,我们仍然可以访问和更改它。

>>> p = Person('Guido')
>>> p._name
'Guido'
>>> p._name = 'Dave'
>>>

任何带有前导的名称 _ 都被认为是私有的,无论它是变量、函数还是模块名称。

2.2 @装饰器语法

@ 被称为装饰器语法,对紧随其后的方法进行修饰。

使用__slots__可以限制属性名称。

class Person(object):
	__slots__ = ('name')
    def __init__(self, name):
        self._name = 0

slot 最常被用作对数据结构类的优化,使用 slot 优化了 Python 使用内存的性能, 但在平常类的使用中应该避免。

2.3 Properties

对类的属性赋值增加一些限制,例如以下代码 shares 应该是数值类型变量,不能用字符串类型赋值。

class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price

使用 properties 对属性增加限制,起到了保护私有属性的作用,使用者从外部不能轻易更改私有属性,但进一步想要更改私有属性,可使用 @shares.setter 可以对私有属性更改和增加限制。

class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price

    @property
    def shares(self):
        return self._shares

    @shares.setter
    def shares(self, value):
        if not isinstance(value, int):
            raise TypeError('Expected int')
        self._shares = value

访问 shares 会触发@property,shares 不会轻易被修改,从而保护了shares。

shares 被调用时与之前访问类属性一致。

修改 shares 会触发以上 @shares.setter 方法。

>>> s = Stock('IBM', 50, 91.1)
>>> s.shares         # Triggers @property
50
>>> s.shares = 75    # Triggers @shares.setter
>>>

使用 @shares.setter 这种方法,不需要对源代码进行任何更改。

当类内有赋值时也会调用 setter,包括__init__() 内。

class Stock:
    def __init__(self, name, shares, price):
        ...
        # This assignment calls the setter below
        self.shares = shares
        ...

    ...
    @shares.setter
    def shares(self, value):
        if not isinstance(value, int):
            raise TypeError('Expected int')
        self._shares = value

尽管 property 中使用私有名称像 _shares,但类的其他部分可以继续使用 shares 名称。

如下,在 cost 方法中 使用 self.share 的方式对 shares 进行操作。

class Stock:
    def __init__(self, name, shares, price):
        self.name = name
        self.shares = shares
        self.price = price

    @property
    def cost(self):
        return self.shares * self.price
    ...

以上使用 @property 对 cost 方法进行限制,当 cost 被调用时,不需要加 ()。

>>> s = Stock('GOOG', 100, 490.1)
>>> s.shares # Instance variable
100
>>> s.cost   # Computed Value
49010.0
>>>

不要过度使用私有属性、属性、slot 等。

它们用于特定目的,但是,对于大多数日常编码来说,它们并不是必需的。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/953738.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号