2017-09-07 17 views
0

모든 파이썬 버전 (27, 33, 34, 35, 36 및 pypy)에서 작동 할 것으로 예상되는 Python 라이브러리에 대한 테스트를하고 있습니다. 제 테스트에서 저는 datetime 라이브러리를 조롱했습니다. 그리고 그것들을 모두 pypy에서 실행할 때를 제외하고는 모두 작동합니다. (왜 내가 이전에 그렇게 대담하게했는지 보시라. 그런 플롯 트위스트!). 마지막 줄 False 반환 모든 파이썬 버전의pypy에서 datetime 라이브러리를 조롱하면 2 개의 조롱 된 오브젝트를 비교할 때 TypeError가 발생합니다.

import mock 
import datetime as dtl 
mk = mock.Mock(wraps=dtl.datetime) 
p = mock.patch('datetime.datetime', mk) 
p.start() 
from datetime import datetime 
d1 = datetime.now() 
d2 = datetime.now() 
print d1 == d2 

:

다음은 문제가 나는 데에 대한 MCVE입니다. pypy에서 마지막 행 예외 :

>>>> d1 == d2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib/pypy/lib_pypy/datetime.py", line 1764, in __eq__ 
    if isinstance(other, datetime): 
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types 

내가 문제를 이해하려고 노력 pypy의 소스 코드를 파고, 왜 지구에 다른 파이썬 버전 사이의 차이가, 나는 다음과 같은 발견 :

# Comparisons of datetime objects with other. 

def __eq__(self, other): 
    if isinstance(other, datetime): 
     return self._cmp(other) == 0 
    elif hasattr(other, "timetuple") and not isinstance(other, date): 
     return NotImplemented 
    else: 
     return False 

이런 종류의 의미가 있습니다. datetime 클래스는 이제 Mock 객체입니다. 파이썬은 isinstance의 두 번째 인수가 유형이 될 것이라고 주장합니다. Neato.

그래서 나는 datetime의 CPython과의 구현을 찾기로 결정, 깜짝 놀랄 :

# Comparisons of datetime objects with other. 

def __eq__(self, other): 
    if isinstance(other, datetime): 
     return self._cmp(other, allow_mixed=True) == 0 
    elif not isinstance(other, date): 
     return NotImplemented 
    else: 
     return False 

같은 정확한 검증이 여기 완료, 아직 아무것도 ¯\_(ツ)_/¯을 발생시키지 않습니다.

나는이 파이썬 2.7에서 일어나는 것을 추가 할 것입니다 :

  1. 왜 지구에 CPython과 작동 않습니다

    >>> d = datetime.now() 
    >>> d 
    datetime.datetime(2017, 9, 7, 9, 31, 50, 838155) 
    >>> d == d 
    True 
    >>> datetime 
    <Mock id='139788521555024'> 
    >>> isinstance(d, datetime) 
    Traceback (most recent call last): 
        File "<stdin>", line 1, in <module> 
    TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and types 
    

    내가 함께 사투를 벌인거야 2 개 질문이 있습니다?

  2. 어떻게 __eq__ 또는 다른 어떤 마술 방법 : 많은 의무

를 재 구현하지 않고이 작동하는 방식으로 날짜 객체를 조롱 수 있습니다!

답변

1

그건 파이썬의 진짜 문제이고 좋은 예제는 isinstanceof을 사용하는 것이 나쁜 습관입니다.

솔루션은 모의로 패치하지 않고 datetime.datetime에서 상속하는 클래스로 해결해야합니다. 하지만 datetime을 상속하고 실제 datetime 클래스를 기반으로 유형을 확인하려는 경우 isinstance 체크를 실제 클래스로 대체해야합니다.

import datetime as dtl 
import mock 

real_datetime_class = dtl.datetime 

class DatetimeSubclassMeta(type): 
    """Datetime mock metaclass to check instancechek to the real class.""" 

    @classmethod 
    def __instancecheck__(mcs, obj): 
     return isinstance(obj, real_datetime_class) 

class BaseMockedDatetime(real_datetime_class): 
    """Mock class to cover datetime class.""" 

MockedDatetime = DatetimeSubclassMeta('datetime', 
             (BaseMockedDatetime,), 
             {}) 

p = mock.patch('datetime.datetime', MockedDatetime) 
p.start() 


from datetime import datetime 
d = datetime.now() 

isinstance(d, datetime) 
0

"왜", 아마 CPython과에서 C로 구현되고 datetime 및 PyPy 순수 파이썬, 일부 미묘한과 관련이있다 파이썬 클래스 객체와 내장 된 C 객체 사이의 차이점.