рдореЗрд░реЗ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо-рдЪреИрдирд▓ @pythonetc рд╕реЗ рдЯрд┐рдкреНрд╕ рдФрд░ рдЯреНрд░рд┐рдХ, рдЕрдЧрд╕реНрдд 2019



рдпрд╣ рдореЗрд░реЗ рдЯреЗрд▓реАрдЧреНрд░рд╛рдо-рдЪреИрдирд▓ @pythonetc рд╕реЗ рдкрд╛рдпрдерди рдФрд░ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд╕реБрдЭрд╛рд╡реЛрдВ рдФрд░ рдЯреНрд░рд┐рдХреНрд╕ рдХрд╛ рдПрдХ рдирдпрд╛ рдЪрдпрди рд╣реИред

Ations рдкрд┐рдЫрд▓рд╛ рдкреНрд░рдХрд╛рд╢рди


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

>>> 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 

рдпрд╣ рднреА рджреЗрдЦреЗрдВ рдХрд┐ Django classonlymethod рдбреЗрдХреЛрд░реЗрдЯрд░ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ: https://github.com/django/django/blob/b709d701303b3877387020c1558a590713b9853/django/decorators.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 рдХреЛрдИ рдкрд╣реБрдВрдЪ рдирд╣реАрдВ рд╣реИред рдЗрд╕рдХрд╛ рдХрд╛рдо рдХрд░рдиреЗ рдХрд╛ рдПрдХрдорд╛рддреНрд░ рддрд░реАрдХрд╛ рдПрдХ рдФрд░ рдЧреБрдВрдЬрд╛рдЗрд╢ рдЬреЛрдбрд╝рдирд╛ рд╣реИ (рд╣рд╛рдВ, рдпрд╣ рдмрджрд╕реВрд░рдд рд╣реИ):

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



рдкрд╛рдпрдерди рдореЗрдВ, None рдХрд┐рд╕реА рдХреЗ рдмрд░рд╛рдмрд░ 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 рдмрд░рд╛рдмрд░ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдХреЗрд╡рд▓ рдПрдХ рдЪреАрдЬ рдирд╣реАрдВ рд╣реИред рдХрд╕реНрдЯрдо рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд┐рд╕реА рдХреЗ рднреА рдмрд░рд╛рдмрд░ рд╣реЛ рд╕рдХрддреЗ рд╣реИрдВ:

 >>> 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 рдЖрдкрдХреЛ рдЬрдирд░реЗрдЯрд░ рдХреЗ рд▓рд┐рдП рдкреНрд░рдХрд╛рд░ рдХреЛ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдЖрдк рдЕрддрд┐рд░рд┐рдХреНрдд рд░реВрдк рд╕реЗ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдЙрдкрдЬ рд╣реИ, рдХрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреЛ рдПрдХ рдЬрдирд░реЗрдЯрд░ рдореЗрдВ рднреЗрдЬрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ рдФрд░ рдХреНрдпрд╛ рд▓реМрдЯрд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред Generator[int, None, bool] g.send() Generator[int, None, bool] рдПрдХ рдЬрдирд░реЗрдЯрд░ рд╣реИ рдЬреЛ рдкреВрд░реНрдгрд╛рдВрдХ рджреЗрддрд╛ рд╣реИ, рдмреВрд▓рд┐рдпрди рдорд╛рди рджреЗрддрд╛ рд╣реИ рдФрд░ g.send() рд╕рдорд░реНрдерди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред

рдпрд╣рд╛рдБ рдереЛрдбрд╝рд╛ рдФрд░ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдЙрджрд╛рд╣рд░рдг рд╣реИред 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 рд╣реИ, рдпрд╣ рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИ рдХрд┐ A рдпрд╛ рдЗрд╕рдХреЗ рд╡рдВрд╢рдЬреЛрдВ рдореЗрдВ рд╕реЗ рдХреЛрдИ рд╣реИред рдЗрд╕ рдХреЛрдб рдХреЛ рджреЗрдЦреЗрдВ:

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

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

рдЖрдк TypeVar рдХреЗ рд╕рд╛рде cls рдПрдиреЛрдЯреЗрдЯ рдХрд░рдХреЗ рдЗрд╕реЗ рдареАрдХ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ:

 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() 

рдЕрдм cls рд╡рд░реНрдЧ рдХрд╛ рдЙрджрд╛рд╣рд░рдг рд░рд┐рдЯрд░реНрди create ред рд╣рд╛рд▓рд╛рдБрдХрд┐, рдпрд╣ рдПрдиреЛрдЯреЗрд╢рди рдмрд╣реБрдд рдвреАрд▓рд╛ рд╣реИ, рд╣рдордиреЗ рдпрд╣ рдЬрд╛рдирдХрд╛рд░реА рдЦреЛ рджреА рд╣реИ рдХрд┐ 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" ред

рдпрд╣ рддрдп рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдЖрдкрдХреЛ AType рдХреЗ bound рддрд░реНрдХ рдХреЗ рд╕рд╛рде A рдЙрдкрдкреНрд░рдХрд╛рд░ рдХреЗ рд░реВрдк рдореЗрдВ AType рдХреЛ рд╕реНрдкрд╖реНрдЯ рд░реВрдк рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд 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/hi466317/


All Articles