Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Python Cookbook 2Nd Edition Jun 1002005 [Electronic resources] - نسخه متنی

David Ascher, Alex Martelli, Anna Ravenscroft

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید







Recipe 20.2. Coding Properties as Nested Functions


Credit: Sean Ross, David Niergarth, Holger Krekel


Problem


You want to code properties without cluttering up your class
namespace with accessor methods that are not called directly.


Solution


Functions nested within another function are quite handy for this
task:

import math
class Rectangle(object):
def _ _init_ _(self, x, y):
self.y = x
self.y = y
def area( ):
doc = "Area of the rectangle"
def fget(self):
return self.x * self.y
def fset(self, value):
ratio = math.sqrt((1.0*value)/self.area)
self.x *= ratio
self.y *= ratio
return locals( )
area = property(**area( ))


Discussion


The standard idiom used to create a property starts with defining in
the class body several accessor methods (e.g., getter, setter,
deleter), often with boilerplate-like method names such as
setThis, getThat, or
delTheother. More often than not, such accessors are
not required except inside the property itself; sometimes (rarely)
programmers even remember to del them to clean up
the class namespace after building the property
instance.

The idiom suggested in this recipe avoids cluttering up the class
namespace at all. Just write in the class body a function with the
same name you intend to give to the property. Inside that function,
define appropriate nested functions, which must
be named exactly fget, fset,
fdel, and assign an appropriate docstring named
doc. Have the outer function return a dictionary
whose entries have exactly those names, and no others: returning the
locals( ) dictionary will work, as long as your
outer function has no other local variables at that point. If you do
have other names in addition to the fixed ones, you might want to
code your return statement, for example, as:

return sub_dict(locals( ), 'doc fget fset fdel'.split( ))

using the sub_dict function shown in Recipe 4.13. Any other way to subset a
dictionary will work just as well.

Finally, the call to property uses the
** notation to expand a mapping into named
arguments, and the assignment rebinds the name to the resulting
property instance, so that the class namespace is left pristine.

As you can see from the example in this recipe's
Solution, you don't have to define
all of the four key names: you may, and should,
omit some of them if a particular property forbids the corresponding
operation. In particular, the area function in the
solution does not define fdel because the
resulting area attribute must be not deletable.

In Python 2.4, you can define a simple custom decorator to make this
recipe's suggested idiom even spiffier:

def nested_property(c):
return property(**c( ))

With this little helper at hand, you can replace the explicit
assignment of the property to the attribute name with the decorator
syntax:

    @nested_property
def area( ):
doc = "Area of the rectangle"
def fget(self):
the area function remains the same

In Python 2.4, having a decorator line
@deco right before a
def name statement is equivalent to having, right
after the def statement's body,
an assignment name =
deco(name). A mere difference of syntax
sugar, but it's useful: anybody reading the source
code of the class knows up front that the function or method
you're def'ing
is meant to get decorated in a certain way, not to get used exactly
as coded. With the Python 2.3 syntax, somebody reading in haste might
possibly miss the assignment statement that comes
after the def.

Returning locals works only if your outer function
has no other local variables besides fget,
fset, fdel, and
doc. An alternative idiom to avoid this
restriction is to move the call to property
inside the outer function:

def area( ):
what_is_area = "Area of the rectangle"
def compute_area(self):
return self.x * self.y
def scale_both_sides(self, value):
ratio = math.sqrt((1.0*value)/self.area)
self.x *= ratio
self.y *= ratio
return property(compute_area, scale_both_sides, None, what_is_area)
area = area( )

As you see, this alternative idiom enables us to give different names
to the getter and setter accessors, which is not a big deal because,
as mentioned previously, accessors are often named in uninformative
ways such as getThis and setThat
anyway. But, if your opinion differs, you may prefer this idiom, or
its slight variant based on having the outer function return a
tuple of values for
property's argument rather than a
dict. In other words, the variant obtained by
changing the last two statements of this latest snippet to:

    return compute_area, scale_both_sides, None, what_is_area
area = property(*area( ))


See Also


Library Reference and Python in a
Nutshell
docs on built-in functions
property and locals.


/ 394