从同一个类调用,为什么一个被视为绑定方法而另一个普通函数?

时间:2016-09-14 08:06:39

标签: python function python-3.x methods sqlalchemy

我在Python 3中有以下代码片段:

from sqlalchemy.ext.declarative import declared_attr
from sqlalchemy import Column, Integer, String, Unicode, UnicodeText
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
import arrow


datetimeString_format = {
    "UTC": "%Y-%m-%d %H:%M:%S+00:00",
    "local_with_timezoneMarker": "%Y-%m-%d %H:%M:%S %Z",
    "local_without_timezoneMarker": "%Y-%m-%d %H:%M:%S"
}

dateString_format = "%Y-%m-%d"




class My_TimePoint_Mixin:
    # define output formats:
    datetimeString_inUTC_format = "%Y-%m-%d %H:%M:%S+00:00"
    datetimeString_naive_format = "%Y-%m-%d %H:%M:%S"

    # instrumented fields:
    _TimePoint_in_database = Column('timepoint', String, nullable=False)
    _TimePoint_in_database_suffix = Column(
    'timepoint_suffix', String, nullable=False)

    @hybrid_property
    def timepoint(self):
        twoPossibleType_handlers = [
            self._report_ACCRT_DATE,
            self._report_ACCRT_DATETIME
        ]
        for handler in twoPossibleType_handlers:
            print("handler: ", handler)
            try:
                return handler(self)
            except (AssertionError, ValueError) as e:
                logging.warning("Try next handler!")

    @timepoint.setter
    def timepoint(self, datetimepointOBJ):
        handlers_lookup = {
            datetime.datetime: self._set_ACCRT_DATETIME,
            datetime.date: self._set_ACCRT_DATE
        }
        this_time = type(datetimepointOBJ)
        this_handler = handlers_lookup[this_time]
        print("handler: ", this_handler)
        this_handler(datetimepointOBJ)

    def _report_ACCRT_DATE(self):
        """Accurate Date"""
        assert self._TimePoint_in_database_suffix == "ACCRT_DATE"
        date_string = self._TimePoint_in_database
        dateString_format = "%Y-%m-%d"
        # return a datetime.date
        return datetime.datetime.strptime(date_string, dateString_format).date()

    def _report_ACCRT_DATETIME(self):
        """Accurate DateTime"""
        assert self._TimePoint_in_database_suffix in pytz.all_timezones_set
        datetimeString_inUTC = self._TimePoint_in_database
        utc_naive = datetime.datetime.strptime(
        datetimeString_inUTC, self.datetimeString_inUTC_format)
        utc_timepoint = arrow.get(utc_naive, "utc")
        # localize
        local_timepoint = utc_timepoint.to(self._TimePoint_in_database_suffix)
        # return a datetime.datetime
        return local_timepoint.datetime

    def _set_ACCRT_DATETIME(self, datetimeOBJ_aware):
        assert isinstance(datetimeOBJ_aware, datetime.datetime), "Must be a valid datetime.datetime!"
        assert datetimeOBJ_aware.tzinfo is not None, "Must contain tzinfo!"
        utctime_aware_arrow = arrow.get(datetimeOBJ_aware).to('utc')
        utctime_aware_datetime = utctime_aware_arrow.datetime
        store_datetime_string = utctime_aware_datetime.strftime(
        self.datetimeString_inUTC_format)
        self._TimePoint_in_database = store_datetime_string

    def _set_ACCRT_DATE(self, dateOBJ):
        store_date_string = dateOBJ.isoformat()
        self._TimePoint_in_database = store_date_string

由于某种原因,getter的处理程序被视为普通函数而不是方法,因此需要明确地提供'self'作为其参数。

是否因为循环?还是因为try...except结构?为什么在同一个类中,处理程序的处理方式不同? (setter的处理程序被视为预期的绑定方法。)

1 个答案:

答案 0 :(得分:1)

您所拥有的不是常规5.0,您有SQLAlchemy @hybrid_property object。在那里引用文档:

  

“hybrid”表示该属性具有在类级别和实例级别定义的不同行为。

  

在处理import urllib2 import csv import geoip2.database db = geoip2.database.Reader("GeoLite2-City.mmdb") target_url="http://myip/all.txt" data = urllib2.urlopen(target_url) for line in data: try: response = db.city(line.strip()) print line.strip(), response.country.name, response.country.iso_code, response.location.longitude, response.location.latitude exception: pass 类本身时,property描述符在给定Interval类作为参数的情况下评估函数体,当使用SQLAlchemy表达式求解时,返回一个新的SQL表达式:

hybrid_property

因此,该属性用于双容量,包括实例和类。

如果属性在类本身上使用,则Interval绑定到({1}}的子类,并且方法不受约束。在这种情况下,没有任何内容可以将绑定到,因为没有实例。

在对>>> print Interval.length interval."end" - interval.start getter进行编码时,您必须考虑到这一点(setter仅适用于实例上的 情况)。例如,selfMy_TimePoint_Mixin开头的断言不会成立。

通过使用hybrid_property装饰器为后者声明一个单独的getter,可以区分实例大小写和表达式(在类上)的情况:

_report_ACCRT_DATE

然后SQLAlchemy将使用_report_ACCRT_DATETIME类方法进行hybrid_property.expression使用,并仅在@hybrid_property def timepoint(self): twoPossibleType_handlers = [ self._report_ACCRT_DATE, self._report_ACCRT_DATETIME ] for handler in twoPossibleType_handlers: print("handler: ", handler) try: return handler(self) except (AssertionError, ValueError) as e: logging.warning("Try next handler!") @timepoint.expression def timepoint(cls): # return a SQLAlchemy expression for this virtual column 实例访问时使用原始getter。请参阅Defining Expression Behavior Distinct from Attribute Behavior section