@Pythonetc рд╕рдВрдХрд▓рди, рдЕрдЧрд╕реНрдд 2019



рдореЗрд░реА @pythonetc рдлреАрдб рд╕реЗ рдкрд╛рдпрдерди рдЯрд┐рдкреНрд╕ рдФрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХрд╛ рдПрдХ рдирдпрд╛ рдЪрдпрдиред

тЖР рдкрд┐рдЫрд▓рд╛ рд╕рдВрдЧреНрд░рд╣


рдпрджрд┐ рд╢реНрд░реЗрдгреА рдХреЗ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рджрд┐рдП рдЧрдП рдирд╛рдо рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рдирд╣реАрдВ рд╣реИ, рддреЛ рдпрд╣ рдЙрд╕реА рдирд╛рдо рдХреЗ рд╕рд╛рде рд╡рд░реНрдЧ рд╡рд┐рд╢реЗрд╖рддрд╛ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИред

>>> class A: ... x = 2 ... >>> Ax 2 >>> A().x 2 

рдПрдХ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдПрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реЛ рд╕рдХрддреА рд╣реИ рдЬреЛ рд╡рд░реНрдЧ рдХреЗ рдкрд╛рд╕ рдирд╣реАрдВ рд╣реИ, рдпрд╛ рдПрдХ рдЕрд▓рдЧ рдореВрд▓реНрдп рдХреЗ рд╕рд╛рде рдПрдХ рд╡рд┐рд╢реЗрд╖рддрд╛ рд╣реИ:

 >>> class A: ... x = 2 ... def __init__(self): ... self.x = 3 ... self.y = 4 ... >>> A().x 3 >>> Ax 2 >>> A().y 4 >>> Ay AttributeError: type object 'A' has no attribute 'y' 

рдпрджрд┐ рдЖрдк рдЪрд╛рд╣рддреЗ рд╣реИрдВ рдХрд┐ рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдРрд╕рд╛ рд╡реНрдпрд╡рд╣рд╛рд░ рд╣реЛ рдЬреИрд╕рд╛ рдХрд┐ рдЙрд╕рдореЗрдВ рдХреЛрдИ рд╡рд┐рд╢реЗрд╖рддрд╛ рдирд╣реАрдВ рд╣реИ, рд╣рд╛рд▓рд╛рдБрдХрд┐ рдХрдХреНрд╖рд╛ рдореЗрдВ рдпрд╣ рд╣реИ, рддреЛ рдЖрдкрдХреЛ рдПрдХ рдХрд╕реНрдЯрдо рд╡рд┐рд╡рд░рдгрдХ рдмрдирд╛рдирд╛ рд╣реЛрдЧрд╛ рдЬреЛ рдЗрд╕ рдЙрджрд╛рд╣рд░рдг рд╕реЗ рдкрд╣реБрдБрдЪ рдХреЛ рдкреНрд░рддрд┐рдмрдВрдзрд┐рдд рдХрд░рддрд╛ рд╣реИ:

 class ClassOnlyDescriptor: def __init__(self, value): self._value = value self._name = None # see __set_name__ def __get__(self, instance, owner): if instance is not None: raise AttributeError( f'{instance} has no attribute {self._name}' ) return self._value def __set_name__(self, owner, name): self._name = name class_only = ClassOnlyDescriptor class A: x = class_only(2) print(Ax) # 2 A().x # raises AttributeError 

рдпрд╣ рднреА рджреЗрдЦреЗрдВ рдХрд┐ classonlymethod Django рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреИрд╕реЗ classonlymethod : https://github.com/django/django/blob/b709d701303b3877387020c1558a590713b9853/django/utecorators.py#L6


рд╡рд░реНрдЧ рдирд┐рдХрд╛рдп рдореЗрдВ рдШреЛрд╖рд┐рдд рдХрд╛рд░реНрдп рдЗрд╕ рд╡рд░реНрдЧ рдХреЗ рджрд╛рдпрд░реЗ рдХреЗ рд▓рд┐рдП рд╕реБрд▓рдн рдирд╣реАрдВ рд╣реИрдВред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣ рдЧреБрдВрдЬрд╛рдЗрд╢ рдХреЗрд╡рд▓ рдХрдХреНрд╖рд╛ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдХреЗ рджреМрд░рд╛рди рд╣реА рдореМрдЬреВрдж рд╣реИред

 >>> class A: ... x = 2 ... def f(): ... print(x) ... f() ... [...] NameError: name 'x' is not defined 

рдпрд╣ рдЖрдорддреМрд░ рдкрд░ рдПрдХ рд╕рдорд╕реНрдпрд╛ рдирд╣реАрдВ рд╣реИ: рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдХрдХреНрд╖рд╛ рдХреЗ рдЕрдВрджрд░ рдШреЛрд╖рд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╡реЗ рд╡рд┐рдзрд┐рдпрд╛рдВ рдмрди рд╕рдХреЗрдВ рдФрд░ рдмрд╛рдж рдореЗрдВ рдмреБрд▓рд╛рдП рдЬрд╛ рд╕рдХреЗрдВ:

 >>> class A: ... x = 2 ... def f(self): ... print(self.x) ... >>> >>> >>> A().f() 2 

рд╣реИрд░рд╛рдиреА рдХреА рдмрд╛рдд рд╣реИ, рд╕рдордЭ рдХреЗ рд▓рд┐рдП рднреА рдпрд╣реА рд╕рдЪ рд╣реИред рдЙрдирдХрд╛ рдЕрдкрдирд╛ рджрд╛рдпрд░рд╛ рд╣реИ рдФрд░ рд╡рд░реНрдЧреЛрдВ рдХреЗ рджрд╛рдпрд░реЗ рдореЗрдВ рдЙрдирдХреА рдкрд╣реБрдБрдЪ рднреА рдирд╣реАрдВ рд╣реИред рдЬрдирд░реЗрдЯрд░ рдХреА рд╕рдордЭ рдХреЗ рд╕рдВрджрд░реНрдн рдореЗрдВ рдпрд╣ рдмрд╣реБрдд рддрд╛рд░реНрдХрд┐рдХ рд╣реИ: рдЬрдм рдХрдХреНрд╖рд╛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдмрдирд╛рдИ рдЬрд╛рддреА рд╣реИ, рддреЛ рдЙрдирдореЗрдВ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрд┐рдд рд╣реЛрддрд╛ рд╣реИред

 >>> class A: ... x = 2 ... y = [x for _ in range(5)] ... [...] NameError: name 'x' is not defined 

рд╣рд╛рд▓рд╛рдБрдХрд┐, рд╕рдордЭ рдХреА self рддрдХ рдкрд╣реБрдБрдЪ рдирд╣реАрдВ рд╣реИред x рддрдХ рдкрд╣реБрдВрдЪ рдкреНрд░рджрд╛рди рдХрд░рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рдПрдХ рдФрд░ рдЧреБрдВрдЬрд╛рдЗрд╢ рдЬреЛрдбрд╝рдирд╛ рд╣реИ (рд╣рд╛рдБ, рдмреЗрд╡рдХреВрдл рд╕рдорд╛рдзрд╛рди):

 >>> class A: ... x = 2 ... y = (lambda x=x: [x for _ in range(5)])() ... >>> Ay [2, 2, 2, 2, 2] 


рдкрд╛рдпрдерди рдореЗрдВ, None рдмрд░рд╛рдмрд░ None , рдЗрд╕рд▓рд┐рдП рдРрд╕рд╛ рд▓рдЧ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рдЖрдк == рд╕рд╛рде None рд▓рд┐рдП None рдЬрд╛рдВрдЪ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 ES_TAILS = ('s', 'x', 'z', 'ch', 'sh') def make_plural(word, exceptions=None): if exceptions == None: # тЖР тЖР тЖР exceptions = {} if word in exceptions: return exceptions[word] elif any(word.endswith(t) for t in ES_TAILS): return word + 'es' elif word.endswith('y'): return word[0:-1] + 'ies' else: return word + 's' exceptions = dict( mouse='mice', ) print(make_plural('python')) print(make_plural('bash')) print(make_plural('ruby')) print(make_plural('mouse', exceptions=exceptions)) 

рд▓реЗрдХрд┐рди рд╡рд╣ рдПрдХ рдЧрд▓рддреА рд╣реЛрдЧреАред рд╣рд╛рдВ, None рдХрд┐рд╕реА рдХреЗ рдмрд░рд╛рдмрд░ None , рд▓реЗрдХрд┐рди рдХреЗрд╡рд▓ рдЗрддрдирд╛ рд╣реА рдирд╣реАрдВред рдХрд╕реНрдЯрдо рдСрдмреНрдЬреЗрдХреНрдЯ None рднреА None рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:

 >>> class A: ... def __eq__(self, other): ... return True ... >>> A() == None True >>> A() is None False 

None рд╕рд╛рде рддреБрд▓рдирд╛ рдХрд░рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рд╕рд╣реА рддрд░реАрдХрд╛ None is None ред



рдкрд╛рдпрдерди рдореЗрдВ рдлреНрд▓реЛрдЯрд┐рдВрдЧ рдкреЙрдЗрдВрдЯ рдирдВрдмрд░ рдореЗрдВ NaN рдорд╛рди рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, math.nan рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдРрд╕реА рд╕рдВрдЦреНрдпрд╛ рдкреНрд░рд╛рдкреНрдд рдХреА рдЬрд╛ рд╕рдХрддреА рд╣реИред nan рдЕрдкрдиреЗ рдЖрдк рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдХреЗ рдмрд░рд╛рдмрд░ рд╣реИ:

 >>> math.nan == math.nan False 

рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдПрдХ NaN рдСрдмреНрдЬреЗрдХреНрдЯ рдЕрджреНрд╡рд┐рддреАрдп рдирд╣реАрдВ рд╣реИ; рдЖрдкрдХреЗ рдкрд╛рд╕ рд╡рд┐рднрд┐рдиреНрди рд╕реНрд░реЛрддреЛрдВ рд╕реЗ рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ NaN рдСрдмреНрдЬреЗрдХреНрдЯ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:

 >>> float('nan') nan >>> float('nan') is float('nan') False 

рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐, рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдЖрдк NaN рдХрд╛ рдЙрдкрдпреЛрдЧ рдПрдХ рд╢рдмреНрджрдХреЛрд╖ рдХреЗ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 >>> d = {} >>> d[float('nan')] = 1 >>> d[float('nan')] = 2 >>> d {nan: 1, nan: 2} 


typing рдЖрдкрдХреЛ рдЬрдирд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЗрд╕рдХреЗ рдЕрддрд┐рд░рд┐рдХреНрдд, рдЖрдк рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХреМрди рд╕рд╛ рдкреНрд░рдХрд╛рд░ рдЬреЗрдирд░реЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬреЛ рдЬрдирд░реЗрдЯрд░ рдХреЛ рдкрд╛рд╕ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдФрд░ рдЬреЛ return рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ return ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, Generator[int, None, bool] g.send() Generator[int, None, bool] рдкреВрд░реНрдгрд╛рдВрдХ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ, g.send() рд▓реМрдЯрд╛рддрд╛ рд╣реИ, рдФрд░ g.send() рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рд▓реЗрдХрд┐рди рдЙрджрд╛рд╣рд░рдг рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рд╣реИред chain_while рдЕрдиреНрдп рдЬрдирд░реЗрдЯрд░ рдХреЗ рдбреЗрдЯрд╛ рдХреЛ рддрдм рддрдХ chain_while рдЬрдм рддрдХ рдХрд┐ рдЙрдирдореЗрдВ рд╕реЗ рдХреЛрдИ рднреА рдПрдХ рдорд╛рди рд▓реМрдЯрд╛рддрд╛ рдирд╣реАрдВ рд╣реИ рдЬреЛ condition рдлрд╝рдВрдХреНрд╢рди рдХреЗ рдЕрдиреБрд╕рд╛рд░ рдПрдХ рд╕реНрдЯреЙрдк рд╕рд┐рдЧреНрдирд▓ рд╣реИ:

 from typing import Generator, Callable, Iterable, TypeVar Y = TypeVar('Y') S = TypeVar('S') R = TypeVar('R') def chain_while( iterables: Iterable[Generator[Y, S, R]], condition: Callable[[R], bool], ) -> Generator[Y, S, None]: for it in iterables: result = yield from it if not condition(result): break def r(x: int) -> Generator[int, None, bool]: yield from range(x) return x % 2 == 1 print(list(chain_while( [ r(5), r(4), r(3), ], lambda x: x is True, ))) 


рдлрд╝реИрдХреНрдЯрд░реА рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдПрдиреЛрдЯреЗрд╢рди рд╕реЗрдЯ рдХрд░рдирд╛ рдЗрддрдирд╛ рдЖрд╕рд╛рди рдирд╣реАрдВ рд╣реИ рдЬрд┐рддрдирд╛ рдпрд╣ рд▓рдЧ рд╕рдХрддрд╛ рд╣реИред рдмрд╕ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ:

 class A: @classmethod def create(cls) -> 'A': return cls() 

рд▓реЗрдХрд┐рди рдпрд╣ рдЧрд▓рдд рд╣реЛрдЧрд╛ред рдЪрд╛рд▓ рдпрд╣ рд╣реИ рдХрд┐ рд░рд┐рдЯрд░реНрди A рдирд╣реАрдВ create , рдпрд╣ рд░рд┐рдЯрд░реНрди cls , рдЬреЛ A рдпрд╛ рдЗрд╕рдХреЗ рд╡рдВрд╢рдЬреЛрдВ рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рдХреЛрдб рдкрд░ рдПрдХ рдирдЬрд╝рд░ рдбрд╛рд▓реЗрдВ:

 class A: @classmethod def create(cls) -> 'A': return cls() class B(A): @classmethod def create(cls) -> 'B': return super().create() 

Mypy рдЪреЗрдХ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рддреНрд░реБрдЯрд┐ error: Incompatible return value type (got "A", expected "B") ред рдПрдХ рдмрд╛рд░ рдлрд┐рд░, рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ super().create() A рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд░реВрдк super().create() рдПрдиреЛрдЯреЗрдЯ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ, рд╣рд╛рд▓рд╛рдВрдХрд┐ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдпрд╣ B рд╡рд╛рдкрд╕ рдЖрддрд╛ рд╣реИ B

рдпрд╣ рдареАрдХ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдпрджрд┐ TypeVar рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реБрдП TypeVar :

 AType = TypeVar('AType') BType = TypeVar('BType') class A: @classmethod def create(cls: Type[AType]) -> AType: return cls() class B(A): @classmethod def create(cls: Type[BType]) -> BType: return super().create() 

рдЕрдм create cls рд╡рд░реНрдЧ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджреЗрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпреЗ рдПрдиреЛрдЯреЗрд╢рди рдмрд╣реБрдд рдЕрд╕реНрдкрд╖реНрдЯ рд╣реИрдВ, рд╣рдордиреЗ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рдЦреЛ рджреА рд╣реИ рдХрд┐ cls A рдЙрдкрдкреНрд░рдХрд╛рд░ рд╣реИ:

 AType = TypeVar('AType') class A: DATA = 42 @classmethod def create(cls: Type[AType]) -> AType: print(cls.DATA) return cls() 

рд╣рдореЗрдВ рддреНрд░реБрдЯрд┐ "Type[AType]" has no attribute "DATA" ред

рдЗрд╕реЗ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ A рдХреЛ A рдЙрдкрдкреНрд░рдХрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ A рдЗрд╕рдХреЗ рд▓рд┐рдП, bound рддрд░реНрдХ рдХреЗ рд╕рд╛рде TypeVar рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред

 AType = TypeVar('AType', bound='A') BType = TypeVar('BType', bound='B') class A: DATA = 42 @classmethod def create(cls: Type[AType]) -> AType: print(cls.DATA) return cls() class B(A): @classmethod def create(cls: Type[BType]) -> BType: return super().create() 

Source: https://habr.com/ru/post/hi466315/


All Articles