python面对对象编程-------5:获取属性

一:最基本的属性操作

 1 class Generic:
 2     pass
 3
 4 g= Generic()
 5
 6 >>> g.attribute= "value"    #创建属性并赋值
 7 >>> g.attribute
 8 ‘value‘
 9 >>> g.unset
10 Traceback (most recent call last):
11 File "<stdin>", line 1, in <module>
12 AttributeError: ‘Generic‘ object has no attribute ‘unset‘
13 >>> del g.attribute         #注意,此地时直接删除了这个属性
14 >>> g.attribute
15 Traceback (most recent call last):
16 File "<stdin>", line 1, in <module>
17 AttributeError: ‘Generic‘ object has no attribute ‘attribute‘

基本的属性操作

二:@property

  被@property修饰的是一个方法,但此方法名可以像属性一样被获取,设置,删除  需要注意的是,属性的外部添加是十分简单的,但property的外部添加不是,所以其与属性还是有区别的  有两种方法创建property:      1:用@property修饰的函数      2:用property()方法  有两种设计模式:      1:懒惰计算模式:被调用时才执行      2:主动计算模式:实例化时就执行

  懒惰模式:计算手牌总和

 1 class Hand_Lazy(Hand):
 2     def __init__( self, dealer_card, *cards ):
 3         self.dealer_card= dealer_card
 4         self._cards= list(cards)
 5     @property
 6     def total( self ):
 7         delta_soft = max(c.soft-c.hard for c in self._cards)
 8         hard_total = sum(c.hard for c in self._cards)
 9         if hard_total+delta_soft <= 21:
10             return hard_total+delta_soft
11         return hard_total
12     @property
13     def card( self ):
14         return self._cards
15     @card.setter
16     def card( self, aCard ):
17         self._cards.append( aCard )
18     @card.deleter
19     def card( self ):
20         self._cards.pop(-1)
21
22
23 d= Deck()
24 h= Hand_Lazy( d.pop(), d.pop(), d.pop() )
25 h.total                 #被调用时才执行计算手头的牌之和
26 # 19
27 h.card = d.pop()        #注意,可以将@property看作@property.getter,而此地可以看作两步,左边为@property获取属性,=号调用@property.setter并且将右边的d.pop()当作参数传入。
28 h.total
29 # 29

懒惰模式

  主动计算模式

 1 # 将计算嵌入到@card.setter中,每新添加一张手牌就立马更新手牌总和
 2 class Hand_Eager(Hand):
 3     def __init__( self, dealer_card, *cards ):
 4         self.dealer_card= dealer_card
 5         self.total= 0
 6         self._delta_soft= 0
 7         self._hard_total= 0
 8         self._cards= list()
 9         for c in cards:
10             self.card = c
11     @property
12     def card( self ):
13         return self._cards
14     @card.setter
15     def card( self, aCard ):
16         self._cards.append(aCard)
17         self._delta_soft = max(aCard.soft-aCard.hard,self._delta_soft)
18         self._hard_total += aCard.hard
19         self._set_total()
20     @card.deleter
21     def card( self ):
22         removed= self._cards.pop(-1)
23         self._hard_total -= removed.hard
24         # Issue: was this the only ace?
25         self._delta_soft = max( c.soft-c.hard for c in self._cards)
26         self._set_total()
27
28     def _set_total( self ):
29         if self._hard_total+self._delta_soft <= 21:
30             self.total= self._hard_total+self._delta_soft
31         else:
32             self.total= self._hard_total
33
34 d= Deck()
35 h1= Hand_Lazy( d.pop(), d.pop(), d.pop() )
36 print( h1.total )
37 h2= Hand_Eager( d.pop(), d.pop(), d.pop() )
38 print( h2.total )

主动计算模式

  补充:廖雪峰的关于@property片段的代码

 1 class Student:
 2     def get_score(self):
 3         return self._score
 4
 5     def set_score(self,value):
 6         if not isinstance(value,int):
 7             raise ValueError(‘must be integer‘)
 8         if value < 0 or value > 100:
 9             raise ValueError(‘0~100‘)
10         self._score = value
11
12 s=Student()
13 s.set_score(60)
14 s.get_score()
15 # 60
16
17 # 用@property优化:
18 # 注意,可以把@property看作getter,而setter与deletter都是基于getter的
19 class Student:
20     @property
21     def score(self):
22         return self._score
23
24     @score.setter
25     def score(self,value):
26         if not isinstance(value,int):
27             raise ValueError(‘must be integer‘)
28         if value < 0 or value > 100:
29             raise ValueError(‘0~100‘)
30         self._score = value
31
32 s=Student()
33 s.score = 60
34 s.score
35 # 60

廖雪峰@property

三:属性获取的特殊方法

  __getattr__(), __setattr__(), and __delattr__(),__dir__(),__getattribute__()         __setattr__(): 创建属性并赋值         __getattr__(): 首先:如果此属性已有值,不会用到__getattr__(),直接返回值就是了。                        其次:如果此属性没有值,此时调用__getattr__()并且返回其中设定的返回值。                       最后:如果压根没有这属性,报 AttributeError 错误。         __delattr__():删除一个属性         __dir__():    返回包含属性的list         __getattribute__():更加底层的属性获取方法,他默认从__dict__(或__slots__)中获取值,如果没有找到,调用__getattr__()作为反馈。如果发现此值是一个dexcriptor,就调用descriptor,否者就直接返回值。

    __getattr__()方法只当某个属性没有值时才起作用。

    1:创建immutable object    什么是immutable object:不能够在外部直接赋值一个已有属性的值,不能创建新属性    immutable object的一个特点是__hash__()能够返回固定的值    版本一:用__slots__创建immutable object:

 1 class BlackJackCard:
 2     """Abstract Superclass"""
 3     __slots__ = ( ‘rank‘, ‘suit‘, ‘hard‘, ‘soft‘ )          #__slots__限定了只有这些属性可用
 4     def __init__( self, rank, suit, hard, soft ):
 5         super().__setattr__( ‘rank‘, rank )
 6         super().__setattr__( ‘suit‘, suit )
 7         super().__setattr__( ‘hard‘, hard )
 8         super().__setattr__( ‘soft‘, soft )
 9     def __str__( self ):
10         return "{0.rank}{0.suit}".format( self )
11     def __setattr__( self, name, value ):
12         raise AttributeError( "‘{__class__.__name__}‘ has no attribute ‘{name}‘".format( __class__= self.__class__, name= name ) )
13
14 # We defined __setattr__() to raise an exception rather than do anything useful.
15 # __init__() use the superclass version of __setattr__() so that values can be properly set in spite of the absence of a working __setattr__() method in this class.
16 # 我们知道,python并不阻止人干坏事,所以可以通过 object.__setattr__(c, ‘bad‘, 5) 来绕过immutable机制

__slots__创建immutable object

    版本2: 我们还可以通过继承 tuple 并且覆盖__getattr__()来写immutable object。

 1 class BlackJackCard2( tuple ):
 2     def __new__( cls, rank, suit, hard, soft ):          # tuple(iterable) -> tuple initialized from iterable‘s items
 3         return super().__new__( cls, (rank, suit, hard, soft) )
 4
 5     def __getattr__( self, name ):      #translate __getattr__(name) requests to self[index] requests
 6         return self[{‘rank‘:0, ‘suit‘:1, ‘hard‘:2 , ‘soft‘:3}[name]]
 7
 8     def __setattr__( self, name, value ):
 9         raise AttributeError
10
11 >>> d = BlackJackCard2( ‘A‘, ‘?‘, 1, 11 )
12 >>> d.rank
13 ‘A‘
14 >>> d.suit
15 ‘?‘
16 >>> d.bad= 2            #不能改变属性值了
17 Traceback (most recent call last):
18 File "<stdin>", line 1, in <module>
19 File "<stdin>", line 7, in __setattr__AttributeError

继承tuple实现immutable object

  # 注意上面两个版本是有区别的,在版本2中可以通过d.__dict__来增加属性  # 而版本1中用了__slots__后就会关闭__dict__    2:创建一个一旦给定速度与时间就自动更新距离的类,让其继承自dict,好处是用format函数特别方便

 1 class RateTimeDistance( dict ):
 2     def __init__( self, *args, **kw ):
 3         super().__init__( *args, **kw )
 4         self._solve()
 5     def __getattr__( self, name ):
 6         return self.get(name,None)              #对应字典的get方法
 7     def __setattr__( self, name, value ):
 8         self[name]= value                       #对应字典的赋值方法
 9         self._solve()                           #在__setattr__中调用方法既是一旦赋值就能能够完成计算
10     def __dir__( self ):
11         return list(self.keys())
12     def _solve(self):
13         if self.rate is not None and self.time is not None:
14             self[‘distance‘] = self.rate*self.time
15         elif self.rate is not None and self.distance is not None:
16             self[‘time‘] = self.distance / self.rate
17         elif self.time is not None and self.distance is not None:
18             self[‘rate‘] = self.distance / self.time
19
20 >>> rtd= RateTimeDistance( rate=6.3, time=8.25, distance=None )
21 >>> print( "Rate={rate}, Time={time}, Distance={distance}".format(**rtd ) )
22 Rate=6.3, Time=8.25, Distance=51.975
23 # It‘s also important to note that once all three values are set, this object can‘t be changed to provide new solutions easily.
24 # 上面有个bug在于,一旦我们想改变时间,这时发现速度与距离至少其一一定会变,按代码顺序是改变了距离,而如果我们不想改变距离而是改变速度就不行了
25 # 或者是两个都不想改变,唯一的办法不改变其中一个就是先把一个值设为None
26
27 # 解决办法:design a model that tracked the order that the variables were set in
28 # this model could save us from having to clear one variable before setting another to recompute a related result.

综合__settattr__,__getattr__,__dir__以及主动计算

   3:The __getattribute__() method

    总的来说,几乎没必要用__getattribute__(),其默认的方法已近够强大了,况且几乎所有我们需要的都能够通过__getattr__()实现。

 1 class BlackJackCard3:
 2     """Abstract Superclass"""
 3     def __init__( self, rank, suit, hard, soft ):
 4         super().__setattr__( ‘rank‘, rank )
 5         super().__setattr__( ‘suit‘, suit )
 6         super().__setattr__( ‘hard‘, hard )
 7         super().__setattr__( ‘soft‘, soft )
 8     def __setattr__( self, name, value ):
 9         if name in self.__dict__:
10             raise AttributeError( "Cannot set {name}".format(name=name) )
11         raise AttributeError( "‘{__class__.__name__}‘ has no attribute‘{name}‘".format( __class__= self.__class__, name= name ) )
12     def __getattribute__( self, name ):
13         if name.startswith(‘_‘):
14             raise AttributeError
15         return object.__getattribute__( self, name )
16
17 >>> c = BlackJackCard3( ‘A‘, ‘?‘, 1, 11 )
18 >>> c.rank= 12
19 Traceback (most recent call last):
20 File "<stdin>", line 1, in <module>
21 File "<stdin>", line 9, in __setattr__
22 File "<stdin>", line 13, in __getattribute__
23 AttributeError
24 >>> c.__dict__[‘rank‘]= 12
25 Traceback (most recent call last):
26 File "<stdin>", line 1, in <module>
27 File "<stdin>", line 13, in __getattribute__
28 AttributeError

__getattribute__

四:descriptors

    Descriptor.__get__( self, instance, owner ),Descriptor.__set__( self, instance, value ),Descriptor.__delete__( self, instance )        instance: the self variable of the object being accessed        owner   : the owning class object        value   : the new value that the descriptor needs to be set to.

    描述符是一个类:在达到属性前处理,可用于get,set,delete    其本身在类定义时创建,并不是在__init__中创建,它是类的一部分,不同于方法以及属性    用其来实现(不)可变对象:        无数据描述符:实现__set__or__delete__ or both,若是immutable对象,只用实现__set__并返回AttributeError        数据描述符:  至少实现__get__,通常实现__get__与__set__来创建个可变对象。

  1:无数据描述符

 1 class UnitValue_1:
 2     """Measure and Unit combined."""
 3     def __init__( self, unit ):
 4         self.value= None
 5         self.unit= unit
 6         self.default_format= "5.2f"
 7     def __set__( self, instance, value ):
 8         self.value= value
 9     def __str__( self ):
10         return "{value:{spec}} {unit}".format( spec=self.default_format, **self.__dict__)
11     def __format__( self, spec="5.2f" ):
12         #print( "formatting", spec )
13         if spec == "": spec= self.default_format
14             return "{value:{spec}} {unit}".format( spec=spec,**self.__dict__)
15
16 # The following is a class that does rate-time-distance calculations eagerly:
17 class RTD_1:
18     rate= UnitValue_1( "kt" )
19     time= UnitValue_1( "hr" )
20     distance= UnitValue_1( "nm" )
21     def __init__( self, rate=None, time=None, distance=None ):
22         if rate is None:
23             self.time = time
24             self.distance = distance
25             self.rate = distance / time
26         if time is None:
27             self.rate = rate
28             self.distance = distance
29             self.time = distance / rate
30         if distance is None:
31             self.rate = rate
32             self.time = time
33             self.distance = rate * time
34     def __str__( self ):
35         return "rate: {0.rate} time: {0.time} distance:{0.distance}".format(self)
36
37 # As soon as the object is created and the attributes loaded, the missing value is computed.
38 # Once computed, the descriptor can be examined to get the value or the unit‘s name.
39 # Additionally, the descriptor has a handy response to str() and formatting requests
40
41 >>> m1 = RTD_1( rate=5.8, distance=12 )
42 >>> str(m1)
43 ‘rate: 5.80 kt time: 2.07 hr distance: 12.00 nm‘
44 >>> print( "Time:", m1.time.value, m1.time.unit )
45 Time: 2.0689655172413794 hr

无数据描述符的例子

  2:数据描述符,转换单位后自动更新

 1 class Unit:
 2     conversion= 1.0
 3     def __get__( self, instance, owner ):
 4         return instance.kph * self.conversion       #kph:千米每小时
 5     def __set__( self, instance, value ):
 6         instance.kph= value / self.conversion
 7
 8 # The following are the two conversion descriptors:
 9 class Knots( Unit ):
10     conversion= 0.5399568
11 class MPH( Unit ):
12     conversion= 0.62137119
13 # The following is a unit descriptor for a standard unit, kilometers per hour:
14 class KPH( Unit ):
15     def __get__( self, instance, owner ):
16         return instance._kph
17     def __set__( self, instance, value ):
18         instance._kph= value
19
20
21 class Measurement:
22     kph= KPH()
23     knots= Knots()
24     mph= MPH()
25     def __init__( self, kph=None, mph=None, knots=None ):
26         if kph:
27             self.kph= kph
28         elif mph:
29             self.mph= mph
30         elif knots:
31             self.knots= knots
32         else:
33             raise TypeError
34     def __str__( self ):
35         return "rate: {0.kph} kph = {0.mph} mph = {0.knots}knots".format(self)
36
37 # 在不同进制下自动完成转换
38 >>> m2 = Measurement( knots=5.9 )
39 >>> str(m2)
40 ‘rate: 10.92680006993152 kph = 6.789598762345432 mph = 5.9 knots‘
41 >>> m2.kph
42 10.92680006993152
43 >>> m2.mph
44 6.789598762345432

数据描述符例子

五:一些补充:

  Internally, Python uses descriptors to implement features such as method functions,static method functions, and properties. Many of the cool use cases for descriptorsare already first-class features of the language

  
In Python, it‘s considerably simpler to treat all attributes as public. This means the following:     They should be well documented.     They should properly reflect the state of the object; they shouldn‘t be temporary or transient values.     In the rare case of an attribute that has a potentially confusing (or brittle)        value, a single leading underscore character (_) marks the name as "not part        of the defined interface." It‘s not really private.
  一般来说,外部能够改变属性值并不是严重的事,但是当一个属性值改变后会影响到另一个时,我们需要考虑用函数或者property进行一些设置。注意区别property的两种设计方式(eager calcilation & lazy calculation)

    descriptor是非常高级的python用法,一般用于连接 python 与 non-python 的处理,比如python与SQL,python做网络服务器,在我们的程序里,关于attributes我们尽量用property来实现,如果发现property需要写的太复杂,那么我们转向descriptor。
时间: 2024-10-13 11:19:17

python面对对象编程-------5:获取属性的相关文章

js面对对象编程(二):属性和闭包

上篇博客中讲解了一些js对象的基本概念和用法,这篇博客讲解一下js属性方面的:公有属性,私有属性,特权方法. 如果学过java,公有属性,私有属性,特权方法(即可以访问和设置私有属性的方法)一定很熟悉,那么让我们来看看在js里如何实现呢? 1.公有属性 首先看公有的第一层意思是可以被大家所访问的,对外开放的属性,是相对于私有属性而言的: function Person(name,age){ this.name=name; this.age=age; this.getName=function()

Python 面对对象编程

面向对象编程: 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强..." 面向过程编程最易被初学者接受,其往往用一长段代码来实现指定功能,开发过程中最常见的操作就是粘贴复制,即:将之前实现的代码块复制到现需功能处. 封装 封装最好理解了.封装是面向对象的特征之一,是对象和类概念的主要特性. 封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对

python面对对象编程

基本概念 class类 一个类即是对一类拥有相同属性的对象的抽象.蓝图.原型.在类中定义了这些对象的都具备的属性(variables(data)).共同的方法 Object 对象 一个对象即是一个类的实例化后实例,一个类必须经过实例化后方可在程序中调用,一个类可以实例化多个对象,每个对象亦可以有不同的属性,就像人类是指所有人,每个人是指具体的对象,人与人之前有共性,亦有不同 Encapsulation 封装在类中对数据的赋值.内部调用对外部用户是透明的,这使类变成了一个胶囊或容器,里面包含着类的

python接口自动化九--面对对象编程二,搭建测试环境,多线程与多进程

1.面对对象编程 1.1 基本概念 实例方法:在类里面定义的函数都是实例方法,函数内有self变量 类方法: 不可以实例化,直接用类名调用 类方法可以使用类变量,cls.xxx 实例可以通过self.xx使用类方法 类方法里面不能使用实例方法和实例变量 静态方法: 定义在类里的普通函数 用不了实例方法,实例变量,类方法,类变量 不需要实例化,直接用类名调用 ? 属性方法: 是实例方法 不能有入参 用它的时候,直接m.func,把它当做变量来使用,后面不需要加括号 它是获取函数的返回值 析构函数:

Python - 面对对象(其他相关,异常处理,反射,单例模式,等..)

目录 Python - 面对对象(其他相关,异常处理,反射,等..) 一.isinstance(obj, cls) 二.issubclass(sub, super) 三.异常处理 1. 异常处理 2.异常种类 3.异常其他结构 4.主动触发异常 5.自定义异常 6.断言 四.反射 五. 单例模式 Python - 面对对象(其他相关,异常处理,反射,等..) 一.isinstance(obj, cls) 检查是否obj是否是类 cls 的对象 class Foo(object): pass ob

Python - 面对对象(基础)

目录 Python - 面对对象(基础) 一. 概述 二. 创建类和对象 三. 面向对象三大特征 封装 继承 多态 Python - 面对对象(基础) 一. 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发"更快更好更强..." 面向过程编程(Object Oriented Programming,OOP,面向对象程序设计) 最易被初学者接受,其往往用一长段代码来实现指定功能,开发

16、python面对对象之类和继承

前言:本文主要介绍python面对对象中的类和继承,包括类方法.静态方法.只读属性.继承等. 一.类方法 1.类方法定义 使用装饰器@classmethod装饰,且第一个参数必须是当前类对象,该参数名一般约定为“cls",通过它来传递类的属性和方法 (不能传递实例属性和实例方法),跟实例方法的self用法相似. 2.类方法的调用 实例对象和类对象都可以调用 3.应用场景 在需要站在类的角度执行某个行为时,那么就可以定义为类方法 class Student: def __init__(self,

跟着百度学PHP[4]OOP面对对象编程-5-内部引用$this

$this就是对象内部代表这个对象的引用 可以调用被封装的方法或者属性! <?php class Person{ private $name; private $age="21"; var $sex; function play(){ echo "他正在玩儿呢"; } private function Hello(){ //使用private封装hello方法.该方法不可直接调用.但是可以在内部使用$this调用. echo "这个是被封装的内容&q

js面对对象编程

说到js,很大一部分人会说我很熟悉,在日常的web开发中经常用,那么你的js代码是符合面对对象思路的吗?那你会问我面向过程的js代码有什么不好吗?我的感受是面对对象的js编码更加简洁,减少了混乱,可维护行增强,适合编写富客户端时应用. 好了,首先看看js里如何定义对象: <html> <head> <script type="text/javascript"> var obj=new Object(); obj.name='josh'; obj.ag